kd-curve-v2
v0.1.0
Published
kd curve vue2 edition
Readme
kd-curve-v2 使用手册
1. 项目介绍
kd-curve-v2 是一个功能强大的井深-时间曲线图表容器,主要用于石油钻探领域的数据可视化。它提供了丰富的配置选项和交互功能,支持实时数据展示、多主题切换、岩性显示等功能。
主要特点
- 支持井深和时间两种曲线类型
- 实时数据和历史数据切换
- 多主题支持(白色、深色、灰色)
- 自定义工具栏配置
- 参数面板显示
- 井深-钻头-时间曲线面板
- 岩性显示和自定义tooltip
- 滚动加载数据
- 导出功能
2. 安装与配置
2.1 环境要求
- Vue 2.x
2.2 安装
- npm install kd-curve-v2
3. 主要功能说明
3.1 主题切换
应用支持三种主题模式:白色、深色和灰色。主题切换会影响整个应用的视觉效果,包括图表颜色、背景色等。
3.2 曲线类型切换
支持两种曲线类型:
- 时间曲线(time):以时间为横轴
- 井深曲线(depth):以井深为横轴
3.3 数据类型切换
支持两种数据类型:
- 实时数据(real):通过定时器模拟实时数据更新
- 历史数据(history):静态历史数据展示
3.4 工具栏功能
工具栏提供以下功能:
- 曲线类型切换
- 数据类型切换
- 显示类型切换(表头/悬浮)
- 比例尺调整
- 时间范围选择
- 井深范围选择
- 预警定位
- 刷新
- 导出
3.5 参数面板
参数面板显示各种实时监测参数,如出口流量、温度、压力等。
3.6 井深-钻头-时间曲线面板
展示钻头位置与井深的关系,支持不同模式切换。
3.7 岩性显示
根据井深显示不同的岩性信息,包括砂岩、泥岩、粉砂岩等。
3.8 数据滚动加载
支持触顶和触底时自动加载更多数据。
3.9 导出功能
支持数据导出功能。
4. 组件结构
4.1 主组件
App.vue 是应用的主组件,包含以下核心部分:
- 模板部分:使用
frameLayout组件作为主要布局容器,包含表头槽位和内容槽位 - 脚本部分:包含数据定义、生命周期钩子和方法
- 样式部分:定义应用的全局样式
4.2 核心组件
- frameLayout:框架布局组件,负责整体布局和事件处理
- resizeEcharts:自适应ECharts组件,用于岩性显示等图表
5. 配置选项
5.1 主题配置
themeName: "dark" // 可选值: "white", "dark", "gray"5.2 井深配置
depthConfig: {
type: "local",
caseId: "depth",
versionCode: 5,
dataSource: {
templates: [
{
templateName: "井深",
lanes: [
{
laneName: "井深",
laneKey: "depth",
createUser: "SYSTEM_USER",
sort: 1,
},
{
laneName: "地层",
laneKey: "formation",
contentKey: "formation",
createUser: "SYSTEM_USER",
sort: 1,
},
{
sort: 2,
lines: [
{
paramId: "8008",
lineSort: 1,
min: 0,
max: 35,
lineSize: "1.5",
lineType: "solid",
isUsed: "1",
isGradient: false,
symbol: "none",
symbolSize: 0,
themeConfig: {
white: { lineColor: "#278FE6" },
dark: { lineColor: "#7EA7FF" },
gray: { lineColor: "#1C74BE" },
},
},
// 更多曲线配置...
],
},
// 更多车道配置...
],
},
],
params: [
{ paramId: "depth", paramName: "井深", paramUnit: "m" },
{ paramId: "8008", paramName: "大钩高度", paramUnit: "m" },
// 更多参数配置...
]
}
}5.3 时间配置
timeConfig: {
type: "local",
caseId: "timestamp",
versionCode: 3,
dataSource: {
templates: [
{
templateName: "时间",
lanes: [
{
laneName: "时间",
laneKey: "timestamp",
createUser: "SYSTEM_USER",
sort: 1,
},
{
sort: 2,
lines: [
{
paramId: "8008",
lineSort: 1,
min: 0,
max: 35,
lineSize: "1.5",
lineType: "solid",
isUsed: "1",
isGradient: false,
symbol: "none",
symbolSize: 0,
themeConfig: {
white: { lineColor: "#278FE6" },
dark: { lineColor: "#7EA7FF" },
gray: { lineColor: "#1C74BE" },
},
},
// 更多曲线配置...
],
},
// 更多车道配置...
],
},
],
params: [
{ paramId: "depth", paramName: "井深", paramUnit: "m" },
{ paramId: "8008", paramName: "大钩高度", paramUnit: "m" },
// 更多参数配置...
]
}
}5.4 工具栏配置
toolBarConfig: {
show: true,
width: 120,
dataTypeList: {
history: "history",
real: "real"
},
axisTypeList: {
time: "timestamp",
depth: "depth"
},
timeRangeList: [
{ label: "5min", value: 5 },
{ label: "10min", value: 10 },
{ label: "30min", value: 30 },
{ label: "1h", value: 60 },
{ label: "12h", value: 720 },
{ label: "24h", value: 1440 },
],
depthRangeList: [
{ label: "1000m", value: 1000 },
{ label: "2000m", value: 2000 },
{ label: "3000m", value: 3000 },
{ label: "4000m", value: 4000 },
{ label: "5000m", value: 5000 },
{ label: "10000m", value: 10000 },
],
scaleList: [
{ label: "1:100", value: 1 },
{ label: "1:200", value: 2 },
{ label: "1:500", value: 5 },
{ label: "1:1000", value: 10 },
{ label: "10:2000", value: 20 },
],
timeRangeBtnShow: true,
depthRangeBtnShow: true,
alertBtnShow: true,
refreshBtnShow: true,
exportBtnShow: true,
form: {
axisType: "time", // 曲线类型
dataType: "real", // 数据类型
displayType: "float", // 显示类型
scale: 5, // 比例尺
timeRange: 10, // 时间范围
depthRange: 1000 // 井深范围
}
}5.5 参数面板配置
parameterPanelConfig: {
show: true,
columns: 1, // 设置单行显示个数
width: 140,
data: [
{ label: "出口流量(L/s)", value: 231.7 },
{ label: "入口温度(℃)", value: 12.3 },
{ label: "出口温度(℃)", value: 20.2 },
{ label: "入口电导率(S/m)", value: 12.7 },
{ label: "出口电导率(S/m)", value: 53.1 },
{ label: "旋转时间(s)", value: 1231.9 },
{ label: "入口压力(kPa)", value: 101.3 },
{ label: "出口压力(kPa)", value: 98.6 },
{ label: "流速(m/s)", value: 3.25 },
{ label: "管道直径(mm)", value: 250 },
{ label: "液位高度(m)", value: 12.8 },
{ label: "泵转速(r/min)", value: 1450 },
{ label: "电机功率(kW)", value: 75 },
{ label: "系统效率(%)", value: 87.5 },
{ label: "累计运行时间(h)", value: 5320 },
{ label: "瞬时能耗(kWh)", value: 18.6 },
]
}5.6 井深-钻头-时间曲线面板配置
WellBitDepthTimePlotConfig: {
show: true,
width: 280,
data: [
{
mode: "wellBitDepthTime",
modeName: "钻头位置-井深",
axisType: "time",
datas: [
{
xName: "时间",
yName: "井深",
data: convertedData, // 具体数据
},
{
xName: "时间",
yName: "钻头位置",
data: convertedData, // 具体数据
},
],
},
{
mode: "depthTime",
axisType: "time",
modeName: "时间-井深",
datas: [
{
xName: "时间",
yName: "井深",
data: convertedData, // 具体数据
},
],
},
{
mode: "depthTime",
modeName: "时间-井深",
axisType: "depth",
datas: [
{
xName: "时间",
yName: "井深",
data: [], // 具体数据
},
],
},
]
}5.7 曲线数据配置
// 整体替换数据
curveDatas: {
type: "replace",
data: testDatas, // 数据数组
dataType: "history" // 可选,数据类型
}
// 追加数据
curveDatas: {
type: "append",
data: generator(), // 数据数组或单个数据对象
dataType: "real" // 可选,数据类型
}6. API说明
6.1 事件处理
6.1.1 自定义菜单点击
事件:@onCustomMenuClicked="onCustomMenuClicked"
描述:当用户点击自定义菜单时触发
参数:无
示例:
onCustomMenuClicked() {
// 处理自定义菜单点击事件
}6.1.2 模板变更
事件:@template-change="templateChange"
描述:当模板发生变更时触发
参数:
data:包含变更后的模板信息,结构如下:{ lanes: [ { laneId: Number, // 车道ID laneName: String, // 车道名称 laneKey: String, // 车道键 contentKey: String, // 内容键(可选) // 其他属性... }, // 更多车道... ] }
示例:
templateChange(data) {
const { lanes } = data;
lanes.forEach((item) => {
if (Object.prototype.hasOwnProperty.call(item, "laneKey")) {
if (!this.headerSlotName.some((lane) => lane.laneKey == item.laneKey)) {
this.headerSlotName.push({
laneId: `lane${item.laneId}`,
laneKey: item.laneKey,
laneName: item.laneName,
});
} else {
let index = this.headerSlotName.findIndex((lane) => lane.laneKey == item.laneKey);
this.headerSlotName[index].laneId = `lane${item.laneId}`;
}
}
if (Object.prototype.hasOwnProperty.call(item, "contentKey")) {
if (!this.contentSlotName.some((lane) => lane.contentKey == item.contentKey)) {
this.contentSlotName.push({
laneId: `content${item.laneId}`,
contentKey: item.contentKey,
laneName: item.laneName,
});
} else {
let index = this.contentSlotName.findIndex((lane) => lane.contentKey == item.contentKey);
this.contentSlotName[index].laneId = `content${item.laneId}`;
}
}
});
this.lanes = lanes;
}6.1.3 曲线变更
事件:@line-change="lineChange"
描述:当曲线配置发生变更时触发
参数:
line:变更后的曲线配置信息
示例:
lineChange(line) {
console.log(line);
// 处理曲线变更事件
}6.1.4 图表滚动
事件:@chart-scroll="chartScroll"
描述:当图表滚动时触发,用于实现滚动加载数据
参数:
data:包含滚动方向和当前数据信息,结构如下:{ direction: String, // 滚动方向:"top" 或 "bottom" currentData: {} // 当前数据 }
示例:
chartScroll(data) {
if (data.direction == "top") {
console.log("触顶", data);
} else if (data.direction == "bottom") {
console.log("触底", data);
}
}6.1.5 设置更新
事件:@updateSettings="updateSettings"
描述:当设置发生变更时触发
参数:
data:包含变更的设置信息,结构如下:{ key: String, // 设置键名,如 "axisType"、"dataType" value: String, // 新的设置值 settings: Object, // 完整的设置对象 }
示例:
updateSettings(data) {
clearInterval(this.timeId);
this.timeId = null;
if (data.key == "axisType") {
// 切换曲线类型时,重置曲线数据
this.curveDatas = {
type: "replace",
data: testDatas,
};
// 判断如果是实时数据,则开始获取实时数据,否则清除定时器
if (data.settings.dataType == "real") {
this.getRealTimeData();
}
}
if (data.key == "dataType") {
// 切换数据类型时,重置曲线数据
this.curveDatas = {
type: "replace",
data: testDatas,
};
// 判断如果是实时数据,则开始获取实时数据,否则清除定时器
if (data.value == "real") {
this.getRealTimeData();
}
}
}6.1.6 可见数据变更
事件:@visibleDataChange="visibleDataChange"
描述:当可见数据范围发生变更时触发,用于更新岩性显示等插入的图表
参数:
data:包含可见数据范围信息,结构如下:{ firstValue: Number, // 起始值 lastValue: Number, // 结束值 }
示例:
async visibleDataChange(data) {
const depths = [];
for (let i = data.firstValue; i <= data.lastValue; i++) {
depths.push(i.toString());
}
const formations = this.generateFormations();
const seriesData = depths.map((d) => {
const depth = Number(d);
const layer = formations.find((f) => depth >= f.start && depth < f.end);
return {
value: 10,
name: layer && layer.name || "",
startDepth: layer && layer.start,
endDepth: layer && layer.end,
itemStyle: {
borderWidth: 0,
borderColor: "transparent",
color: layer && layer.color || "#000",
},
};
});
this.contentSlotOptions = {
formation: {
// ECharts配置...
},
};
this.$forceUpdate();
}6.1.7 弹窗功能
事件:@dialogFunction="dialogFunction"
描述:当需要显示弹窗时触发,如井深段选择、时间段选择、导出等
参数:
data:包含弹窗类型和相关信息,结构如下:{ type: Number, // 弹窗类型:1-井深段,2-时间段,3-导出 start: Number, // 起始值(井深或时间戳) end: Number, // 结束值(井深或时间戳) }
示例:
dialogFunction(data) {
console.log(data);
// type 1.井深段 depth 2.时间段 time 3.导出 export
if (data.type === 1) {
} else if (data.type === 2) {
} else if (data.type === 3) {
}
}6.1.8 刷新
事件:@refresh="refresh"
描述:当用户点击刷新按钮时触发
参数:无
示例:
refresh() {
// 关闭定时器,然后如果初始化为实时数据,重启定时器
clearInterval(this.timeId);
this.timeId = null;
}6.2 方法
6.2.1 主题切换
方法:changeTheme(themeName)
描述:切换应用主题
参数:
themeName:主题名称,可选值:"white"、"dark"、"gray"
示例:
changeTheme(themeName) {
this.themeName = themeName;
document.body.setAttribute("data-theme", themeName);
}6.2.2 获取实时数据
方法:getRealTimeData()
描述:获取实时数据并定时更新
参数:无
示例:
getRealTimeData() {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: 2199,
depthStep: 5,
startTime: 1769074462,
timeStep: 10,
});
this.timeId = setInterval(() => {
this.curveDatas = {
type: "append",
data: generator(),
};
}, 1000);
}6.2.3 生成岩性数据
方法:generateFormations()
描述:生成岩性数据,用于岩性显示
参数:无
返回值:岩性数据数组,结构如下:
[
{
start: Number, // 起始深度
end: Number, // 结束深度
name: String, // 岩性名称
color: String, // 岩性颜色
},
// 更多岩性...
]示例:
generateFormations() {
const rockTypes = [
{ name: "砂岩", color: "#f4c542" },
{ name: "泥岩", color: "#eb5757" },
{ name: "粉砂岩", color: "#f2994a" },
{ name: "砂质泥岩", color: "#6fcf97" },
{ name: "灰岩", color: "#9e9e9e" },
{ name: "白云岩", color: "#56ccf2" },
];
const formations = [];
let depth = 0;
let i = 0;
while (depth < 5000) {
const thickness = 50 + Math.floor(20 * Math.sin(i * 0.8));
const rock = rockTypes[i % rockTypes.length];
formations.push({
start: depth,
end: Math.min(depth + thickness, 5000),
name: rock.name,
color: rock.color,
});
depth += thickness;
i++;
}
return formations;
}6.2.4 获取顶部数据
方法:getTopData(content)
描述:获取顶部数据,用于滚动加载
参数:
content:包含当前数据信息,结构如下:{ depth: Number, // 当前深度 timestamp: Number, // 当前时间戳 }
示例:
getTopData(content) {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: content.depth - 250,
depthStep: 5,
startTime: content.timestamp - 500,
timeStep: 10,
});
let curveDatas = [];
for (let i = 0; i < 50; i++) {
curveDatas.push(generator());
}
this.curveDatas = {
type: "append",
data: curveDatas,
};
}6.2.5 获取底部数据
方法:getBottomData(content)
描述:获取底部数据,用于滚动加载
参数:
content:包含当前数据信息,结构如下:{ depth: Number, // 当前深度 timestamp: Number, // 当前时间戳 }
示例:
getBottomData(content) {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: content && content.depth || 0,
depthStep: 5,
startTime: content && content.timestamp || 0,
timeStep: 10,
});
let curveDatas = [];
for (let i = 0; i < 50; i++) {
curveDatas.push(generator());
}
this.curveDatas = {
type: "append",
data: curveDatas,
};
}6.2.6 自定义tooltip格式化
方法:customTooltipFormatter({series})
描述:自定义tooltip格式化函数
参数:
series:数据系列数组,每个元素包含系列名称、颜色、值等信息mousePositionData:鼠标位置数据,包含当前鼠标位置的深度和时间戳{ depth: Number, // 当前深度 timestamp: Number, // 当前时间戳 }
返回值:HTML元素,用于显示tooltip内容
示例:
customTooltipFormatter({series, mousePositionData}) {
// 创建一个容器div
const outerDiv = document.createElement("div");
// 设置容器样式
outerDiv.style.padding = "10px";
outerDiv.style.fontFamily = "Arial, sans-serif";
// 添加标题
const titleDiv = document.createElement("div");
titleDiv.style.fontWeight = "bold";
titleDiv.style.marginBottom = "8px";
titleDiv.style.color = "#fff";
titleDiv.innerText = "自定义数据信息";
outerDiv.appendChild(titleDiv);
// 处理每个数据系列
series.forEach((item) => {
// 创建数据行
const dataDiv = document.createElement("div");
dataDiv.style.display = "flex";
dataDiv.style.alignItems = "center";
dataDiv.style.marginBottom = "4px";
// 创建颜色标记
const markerDiv = document.createElement("div");
markerDiv.style.width = "12px";
markerDiv.style.height = "12px";
markerDiv.style.borderRadius = "50%";
markerDiv.style.backgroundColor = item.color;
markerDiv.style.marginRight = "8px";
dataDiv.appendChild(markerDiv);
// 创建数据文本
const textSpan = document.createElement("span");
textSpan.style.fontSize = "12px";
textSpan.style.color = "#fff";
// 处理不同类型的值
let displayValue = item.value;
if (Array.isArray(item.value)) {
// 对于数组类型的值(如[x, y]格式)
displayValue = item.value[0];
}
// 格式化显示内容
textSpan.innerText = `${item.seriesName}: ${displayValue}`;
dataDiv.appendChild(textSpan);
// 添加到容器
outerDiv.appendChild(dataDiv);
});
// 可以添加额外的自定义内容
const extraDiv = document.createElement("div");
extraDiv.style.marginTop = "8px";
extraDiv.style.fontSize = "11px";
outerDiv.appendChild(extraDiv);
return outerDiv;
}7. 示例代码
7.1 基本使用
<template>
<div id="app" ref="targetDom">
<frameLayout
class="container"
ref="frameLayout"
:warningData="warningData"
:timeConfig="timeConfig"
:depthConfig="depthConfig"
:customMenuList="customMenuList"
@onCustomMenuClicked="onCustomMenuClicked"
@template-change="templateChange"
@line-change="lineChange"
@chart-scroll="chartScroll"
@updateSettings="updateSettings"
@visibleDataChange="visibleDataChange"
@dialogFunction="dialogFunction"
@refresh="refresh"
:curveDatas="curveDatas"
:themeName="themeName"
:headerSlotName="headerSlotName"
:contentSlotName="contentSlotName"
:toolBarConfig="toolBarConfig"
:parameterPanelConfig="parameterPanelConfig"
:WellBitDepthTimePlotConfig="WellBitDepthTimePlotConfig"
>
<template v-for="lane in headerSlotName" :slot="lane.laneId">
<div class="header-slot" :style="{ minWidth: lane.laneKey == 'formation' ? '40px ' : '' }" v-if="true" :key="lane.laneId">
{{ lane.laneName }}
</div>
</template>
<template v-for="lane in contentSlotName" :slot="lane.laneId">
<div class="content-slot" v-if="true" :key="lane.laneId">
<resizeEcharts ref="resizeEcharts" autoresize :options="contentSlotOptions[lane.contentKey]"></resizeEcharts>
</div>
</template>
</frameLayout>
</div>
</template>
<script>
import convertedData from "@/mock/convertedData.json";
import { testDatas } from "@/mock/testData";
import Vue from "vue";
import frameLayout from "./components/frame-layout/index.js";
import resizeEcharts from "./components/resizeEcharts/index.vue";
import { colorToRGBA, createMockDataGenerator, getCssVariable } from "./components/util/index.js";
Vue.use(frameLayout);
export default {
name: "App",
components: {
resizeEcharts,
},
data() {
return {
themeName: "dark",
depthConfig: {
type: "local",
caseId: "depth",
versionCode: 5,
dataSource: {
templates: [
{
templateName: "井深",
lanes: [
{
laneName: "井深",
laneKey: "depth",
createUser: "SYSTEM_USER",
sort: 1,
},
{
laneName: "地层",
laneKey: "formation",
contentKey: "formation",
createUser: "SYSTEM_USER",
sort: 1,
},
// 更多车道配置...
],
},
],
params: [
{ paramId: "depth", paramName: "井深", paramUnit: "m" },
// 更多参数配置...
]
}
},
timeConfig: {
type: "local",
caseId: "timestamp",
versionCode: 3,
dataSource: {
templates: [
{
templateName: "时间",
lanes: [
{
laneName: "时间",
laneKey: "timestamp",
createUser: "SYSTEM_USER",
sort: 1,
},
// 更多车道配置...
],
},
],
params: [
{ paramId: "depth", paramName: "井深", paramUnit: "m" },
// 更多参数配置...
]
}
},
dataSource: {
templates: [
{
templateName: "井深",
lanes: [
{
laneName: "井深",
laneKey: "depth",
createUser: "SYSTEM_USER",
sort: 1,
},
// 更多车道配置...
],
},
],
params: [
{ paramId: "depth", paramName: "井深", paramUnit: "m" },
// 更多参数配置...
],
},
warningData: [2024],
headerSlotName: [],
contentSlotName: [],
contentSlotOptions: {},
customMenuList: [],
lanes: [],
toolBarConfig: {
show: true,
width: 120,
dataTypeList: {
history: "history",
real: "real"
},
axisTypeList: {
time: "timestamp",
depth: "depth"
},
timeRangeList: [
{ label: "5min", value: 5 },
{ label: "10min", value: 10 },
{ label: "30min", value: 30 },
{ label: "1h", value: 60 },
{ label: "12h", value: 720 },
{ label: "24h", value: 1440 },
],
depthRangeList: [
{ label: "1000m", value: 1000 },
{ label: "2000m", value: 2000 },
{ label: "3000m", value: 3000 },
{ label: "4000m", value: 4000 },
{ label: "5000m", value: 5000 },
{ label: "10000m", value: 10000 },
],
scaleList: [
{ label: "1:100", value: 1 },
{ label: "1:200", value: 2 },
{ label: "1:500", value: 5 },
{ label: "1:1000", value: 10 },
{ label: "10:2000", value: 20 },
],
timeRangeBtnShow: true,
depthRangeBtnShow: true,
alertBtnShow: true,
refreshBtnShow: true,
exportBtnShow: true,
form: {
axisType: "time",
dataType: "real",
displayType: "float",
scale: 5,
timeRange: 10,
depthRange: 1000,
},
},
parameterPanelConfig: {
show: true,
width: 140,
data: [
{ label: "出口流量(L/s)", value: 231.7 },
{ label: "入口温度(℃)", value: 12.3 },
// 更多参数...
],
},
WellBitDepthTimePlotConfig: {
show: true,
width: 280,
data: [
{
mode: "wellBitDepthTime",
modeName: "钻头位置-井深",
axisType: "time",
datas: [
{
xName: "时间",
yName: "井深",
data: convertedData,
},
{
xName: "时间",
yName: "钻头位置",
data: convertedData,
},
],
},
// 更多模式...
],
},
timeId: null,
curveDatas: {},
};
},
mounted() {
this.changeTheme(this.themeName);
this.curveDatas = {
type: "replace",
data: testDatas,
};
// this.getRealTimeData();
},
beforeDestroy() {
clearInterval(this.timeId);
this.timeId = null;
},
methods: {
// 自定义tooltip格式化函数
customTooltipFormatter({series}) {
// 实现自定义tooltip
},
// 弹窗处理
dialogFunction(data) {
// 处理弹窗事件
},
// 生成岩性数据
generateFormations() {
// 生成岩性数据
},
// 可见数据变更
visibleDataChange(data) {
// 处理可见数据变更
},
// 刷新
refresh() {
// 处理刷新事件
},
// 设置更新
updateSettings(data) {
// 处理设置更新
},
// 获取实时数据
getRealTimeData() {
// 获取实时数据
},
// 获取顶部数据
getTopData(content) {
// 获取顶部数据
},
// 获取底部数据
getBottomData(content) {
// 获取底部数据
},
// 图表滚动
chartScroll(data) {
// 处理图表滚动
},
// 曲线变更
lineChange(line) {
// 处理曲线变更
},
// 模板变更
templateChange(data) {
// 处理模板变更
},
// 主题切换
changeTheme(themeName) {
// 切换主题
},
// 自定义菜单点击
onCustomMenuClicked() {
// 处理自定义菜单点击
},
},
};
</script>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
width: 100%;
height: 100vh;
position: relative;
background: var(--app-background-color);
overflow: hidden;
.container {
height: 100%;
width: 100%;
overflow: hidden;
}
.header-slot {
min-width: 60px;
text-align: center;
font-size: 12px;
}
.content-slot {
width: 100%;
height: 100%;
overflow: hidden;
}
.draw-slot {
display: flex;
height: 100%;
width: 100%;
}
.lane-div {
flex: 1;
height: 100%;
}
}
/* 全局设置 box-sizing 为 border-box */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
</style>7.2 主题切换示例
// 切换到白色主题
this.changeTheme('white');
// 切换到深色主题
this.changeTheme('dark');
// 切换到灰色主题
this.changeTheme('gray');7.3 数据传递示例
7.3.1 初始化数据
// 初始化时设置曲线数据
mounted() {
this.changeTheme(this.themeName);
this.curveDatas = {
type: "replace",
data: testDatas, // 初始数据
};
// 启动实时数据(如果需要)
// this.getRealTimeData();
}7.3.2 实时数据更新
// 获取实时数据并定时更新
getRealTimeData() {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: 2199,
depthStep: 5,
startTime: 1769074462,
timeStep: 10,
});
this.timeId = setInterval(() => {
this.curveDatas = {
type: "append",
data: generator(), // 生成的实时数据
};
}, 1000);
}7.3.3 滚动加载数据
// 触顶加载数据
chartScroll(data) {
if (data.direction == "top") {
console.log("触顶", data);
this.getTopData(data.currentData);
} else if (data.direction == "bottom") {
console.log("触底", data);
this.getBottomData(data.currentData);
}
}
// 获取顶部数据
getTopData(content) {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: content.depth - 250,
depthStep: 5,
startTime: content.timestamp - 500,
timeStep: 10,
});
let curveDatas = [];
for (let i = 0; i < 50; i++) {
curveDatas.push(generator());
}
this.curveDatas = {
type: "append",
data: curveDatas, // 顶部数据
};
}
// 获取底部数据
getBottomData(content) {
const generator = createMockDataGenerator(this.dataSource, {
startDepth: content && content.depth || 0,
depthStep: 5,
startTime: content && content.timestamp || 0,
timeStep: 10,
});
let curveDatas = [];
for (let i = 0; i < 50; i++) {
curveDatas.push(generator());
}
this.curveDatas = {
type: "append",
data: curveDatas, // 底部数据
};
}7.3.4 设置变更时的数据处理
// 设置更新时的数据处理
updateSettings(data) {
clearInterval(this.timeId);
this.timeId = null;
if (data.key == "axisType") {
// 切换曲线类型时,重置曲线数据
this.curveDatas = {
type: "replace",
data: testDatas, // 重置数据
};
// 判断如果是实时数据,则开始获取实时数据,否则清除定时器
if (data.settings.dataType == "real") {
this.getRealTimeData();
}
}
if (data.key == "dataType") {
// 切换数据类型时,重置曲线数据
this.curveDatas = {
type: "replace",
data: testDatas, // 重置数据
};
// 判断如果是实时数据,则开始获取实时数据,否则清除定时器
if (data.value == "real") {
this.getRealTimeData();
}
}
}7.4 岩性显示示例
// 生成岩性数据
generateFormations() {
const rockTypes = [
{ name: "砂岩", color: "#f4c542" },
{ name: "泥岩", color: "#eb5757" },
{ name: "粉砂岩", color: "#f2994a" },
{ name: "砂质泥岩", color: "#6fcf97" },
{ name: "灰岩", color: "#9e9e9e" },
{ name: "白云岩", color: "#56ccf2" },
];
const formations = [];
let depth = 0;
let i = 0;
while (depth < 5000) {
const thickness = 50 + Math.floor(20 * Math.sin(i * 0.8));
const rock = rockTypes[i % rockTypes.length];
formations.push({
start: depth,
end: Math.min(depth + thickness, 5000),
name: rock.name,
color: rock.color,
});
depth += thickness;
i++;
}
return formations;
}
// 可见数据变更时更新岩性显示
async visibleDataChange(data) {
const depths = [];
for (let i = data.firstValue; i <= data.lastValue; i++) {
depths.push(i.toString());
}
const formations = this.generateFormations();
const seriesData = depths.map((d) => {
const depth = Number(d);
const layer = formations.find((f) => depth >= f.start && depth < f.end);
return {
value: 10,
name: layer && layer.name || "",
startDepth: layer && layer.start,
endDepth: layer && layer.end,
itemStyle: {
borderWidth: 0,
borderColor: "transparent",
color: layer && layer.color || "#000",
},
};
});
this.contentSlotOptions = {
formation: {
animation: false,
backgroundColor: getCssVariable("--bg-color"),
tooltip: {
trigger: "item",
appendTo: this.$refs.targetDom,
confine: true,
backgroundColor: colorToRGBA(getCssVariable("--bg-color"), 0.8),
borderWidth: 0,
textStyle: {
color: getCssVariable("--default-text-color"),
},
formatter: (params) => {
const outerDiv = document.createElement("div");
const d = params.data;
const innerDiv = document.createElement("div");
innerDiv.style = "display: flex; align-items: center;";
const markerDiv = document.createElement("div");
markerDiv.style = `height: 10px; width:10px;font-size:10px; border-radius:8px; gap: 5px; background-color:${d.itemStyle.color}`;
const textSpan = document.createElement("span");
textSpan.innerText = `岩性:${d.name}\n 深度:${d.startDepth} - ${d.endDepth} m`;
textSpan.style = `margin-left:8px;font-size:12px;color:${getCssVariable("--default-text-color")};`;
innerDiv.appendChild(markerDiv);
innerDiv.appendChild(textSpan);
outerDiv.appendChild(innerDiv);
return outerDiv;
},
},
grid: {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
xAxis: {
type: "value",
min: 0,
max: 10,
show: false,
},
yAxis: {
show: false,
type: "category",
inverse: true,
data: depths,
axisLabel: { show: false },
axisLine: { show: false },
axisTick: { show: false },
},
series: [
{
type: "bar",
data: seriesData,
barWidth: "200%",
barGap: "0%",
barCategoryGap: "0%",
emphasis: {
disabled: true,
},
silent: false,
animation: false,
},
],
},
};
this.$forceUpdate();
}