kd-lane-container
v0.0.6
Published
kd-lane-chart-container
Readme
KdLaneChartContainer 组件使用文档
1. 组件概述
KdLaneChartContainer 是一个基于 Vue 开发的泳道图容器组件,用于展示和管理泳道模板、线条配置等。
1.1 设计思路
- 逻辑分离:将模板、泳道、参数的设置逻辑和绘制逻辑完全剥离,提高组件的可维护性和扩展性
- 接口兼容:提供了不依赖接口但是兼容接口实现的模板配置逻辑,既支持本地静态数据直接使用,也支持对接后端接口
- 使用场景:
- 适合静态数据展示场景,无需后端接口即可运行
- 适合合作单位使用,提供灵活的数据接入方式
- 技术栈无关:不限制绘制区技术栈,绘制逻辑完全由外部实现,只需要监听组件事件即可动态调整绘制内容
2. 组件功能
- 加载和展示泳道模板
- 支持自定义泳道头部
- 提供上下文菜单操作
- 支持自定义菜单扩展
- 实时曲线配置功能
- 模板和线条的增删改查操作
3. 组件引入
3.1 安装与注册
// 安装依赖
// npm install kd-lane-container --save
// 引入组件
import KdLaneChartContainer from "kd-lane-container";
import Vue from "vue";
// 注册组件
Vue.use(KdLaneChartContainer);3.2 在组件中使用
export default {
// 组件已全局注册,无需再局部注册
// components: {},
// ...
};4. 组件使用
4.1 基本使用
<KdLaneChartContainer class="container" :config="config" :customMenuList="customMenuList" @onCustomMenuClicked="onCustomMenuClicked">
<!-- 自定义插槽内容 -->
</KdLaneChartContainer>4.2 场景与版本控制
4.1.1 场景唯一标识规则
- caseId (场景 ID):用于唯一标识不同的应用场景或业务模块。
- 必须确保在同一应用中唯一,否则会导致数据混淆。
- 建议使用业务模块名称或唯一的 UUID。
- 所有数据操作都将与该场景 ID 绑定,确保数据隔离。
4.1.2 版本号管理
- versionCode (版本号):用于管理不同版本的初始配置。
- 当业务需求发生重大变更时,可以通过升级版本号来重置数据。
- 版本号升级后,系统会自动清理旧版本数据并重新初始化。
- 版本号必须为整数,建议从 1 开始递增。
4.1.3 数据初始化策略
- 首次初始化:系统会将传入的
dataSource保存为当前版本的初始配置。 - 版本冲突:当检测到版本号变更时,系统会自动重置数据并使用新版本的配置。
- 异常恢复:如果初始化过程中出现错误,系统会自动执行重置操作。
4.2 配置参数
4.2.1 数据源类型选择说明
KdLaneChartContainer 支持两种数据源类型:
- local:无后台配置接口,仅需前端单方面维护配置时使用
- custom:需要本组件 + 后台实时曲线配置接口组合使用时使用
4.2.2 本地数据源 (Local)
config: {
type: "local", // 数据源类型,可选值: "local" | "custom"
caseId: "demo", // 案例ID
versionCode: 2, // 版本号
dataSource: { // 数据源
// 支持两种数据结构:
// 1. 扁平结构 (推荐用于数据量大的场景)
templates: [], // 模板数据
lanes: [], // 泳道数据
lines: [], // 线条数据
params: [] // 参数数据
// 2. 树形结构 (直观易读,不用关心数据ID,组件会自己补全和维护)
// templates: [{
// lanes: [{
// lines: []
// }]
// }],
// params: []
}
}local 模式下 datasource 参数说明:
- templates:只需提供
templateName属性 - lane:不需要提供任何属性
- line:需要提供以下属性:
paramId,min,lineSort,max,lineSize,lineColor,lineType,isUsed可选属性:themeConfig- 线条级别主题颜色配置,支持为不同主题设置不同的线条颜色;isGradient- 是否为渐变线条。当设置为 true 时:- lineType 必须为 "area"避免歧义
- lineColor 和 themeConfig 中的 lineColor 应使用 linear-gradient 格式
- LineEdit 组件中的颜色选择器和线型选择器将被禁用
示例:
{ paramId: "52", min: 0.001, max: 100, lineSort: 1, lineSize: "2", lineColor: "linear-gradient(to bottom, blue, red)", lineType: "area", isUsed: "1", isGradient: true, themeConfig: { white: { lineColor: "linear-gradient(to bottom, black, red)" }, dark: { lineColor: "linear-gradient(to bottom, yellow, red)" }, gray: { lineColor: "linear-gradient(to bottom, #E5360B, red)" } } }
- params:需要提供以下属性:
paramId,paramName,paramUnit示例:{ paramId: "12", paramName: "钻头位置", paramUnit: "m" }
完整 local 模式示例配置:
config: {
type: "local",
caseId: "demo",
versionCode: 2,
dataSource: {
// 嵌套结构示例
templates: [
{
templateName: "测试",
lanes: [
{
lines: [
{ paramId: "51", min: 0.001, lineSort: 1, max: 100, lineSize: "2", lineColor: "#E5360B", lineType: "solid", isUsed: "1", isGradient: false, themeConfig: { white: { lineColor: "blue" }, dark: { lineColor: "black" }, gray: { lineColor: "yellow" } } },
{ paramId: "52", min: 0.001, lineSort: 2, max: 100, lineSize: "2", lineColor: "linear-gradient(to bottom, blue, red)", lineType: "area", isUsed: "1", isGradient: true, themeConfig: { white: { lineColor: "linear-gradient(to bottom, black, red)" }, dark: { lineColor: "linear-gradient(to bottom, yellow, red)" }, gray: { lineColor: "linear-gradient(to bottom, #E5360B, red)" } } }
]
}
]
}
],
params: [
{ paramId: "51", paramName: "钻头位置", paramUnit: "m" },
{ paramId: "52", paramName: "钻压", paramUnit: "kN" }
]
}
}4.2.3 自定义数据源 (Custom)
config: {
type: "custom", // 数据源类型,可选值: "local" | "custom"
caseId: "demo", // 案例ID
versionCode: 2, // 版本号
// 自定义数据源必须实现的7个方法,需按照要求的返回格式设置
getUserTemplates() { /* 加载所有模板、泳道和线条数据 */ },
upsertTemplate(data) { /* 新增或更新模板 */ },
delTemplate(data) { /* 删除模板 */ },
upsertLane(data) { /* 新增或更新泳道 */ },
delLane(data) { /* 删除泳道 */ },
upsertLine(data) { /* 新增或更新线条 */ },
delLine(data) { /* 删除线条 */ },
// 可选方法:恢复默认设置 【**在local模式下,可以通过this.$refs[xxx].restoreSetting()方法恢复默认设置**】
restoreSetting() { /* 恢复默认设置 */ }
}各方法参数和返回值说明:
getUserTemplates()- 返回值:
Promise<Object>- 包含所有模板、泳道和线条数据的配置对象 - 示例:
{ "caseVersion": { "caseId": "case123", "versionCode": "v1.0" }, "templates": [ /* 模板数组 */ ], "params": [] }
- 返回值:
upsertTemplate(data)- 参数:
data- 模板数据 - 返回值:
Promise<Object>- 插入或更新后的完整模板对象
- 参数:
delTemplate(data)- 参数:
data- 模板数据(需包含templateId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLane(data)- 参数:
data- 泳道数据 - 返回值:
Promise<Object>- 插入或更新后的完整泳道对象
- 参数:
delLane(lane)- 参数:
lane- 泳道数据(需包含laneId和lines数组) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLine(data)- 参数:
data- 线条数据 - 返回值:
Promise<Object>- 插入或更新后的完整线条对象
- 参数:
delLine(data)- 参数:
data- 线条数据(需包含lineId和laneId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
restoreSetting()(可选)- 返回值:
Promise<void>- 恢复默认设置的 Promise
- 返回值:
4.3 自定义菜单
customMenuList 用于在上下文菜单中添加自定义操作选项。当用户在泳道头部或线条上右键点击时,这些自定义选项会出现在上下文菜单中。
4.3.1 菜单结构
customMenuList: [
{
name: "单屏时长", // 菜单项显示名称
key: "timeRange", // 菜单项唯一标识
},
{
name: "导出数据",
key: "exportData",
},
];4.3.2 点击事件
当用户点击自定义菜单项时,会触发 onCustomMenuClicked 事件,并传递以下参数:
event: 事件对象,包含option和item属性option: 被点击的菜单项配置item: 右键点击时的目标对象(可能是泳道或线条)
4.3.3 使用示例
<kd-lane-chart-container
:customMenuList=\"[{ name: '单屏时长', key: 'timeRange' }]\"
@onCustomMenuClicked=\"handleCustomMenuClick\">
</kd-lane-chart-container>handleCustomMenuClick(event) {
const { option, item } = event;
console.log('自定义菜单项被点击:', option.name);
console.log('点击的目标对象:', item);
if (option.key === 'timeRange') {
// 处理单屏时长操作
}
}5. 组件 API
5.1 Props
| 属性名 | 类型 | 默认值 | 说明 | | ---------------- | ------ | ------- | ------------------ | | config | Object | 必填 | 组件配置对象 | | headerPadding | Number | 4 | 泳道头部内边距 | | headerItemHeight | Number | 20 | 头部线条项高度 | | itemGap | Number | 2 | 线条项之间的间距 | | customMenuList | Array | [] | 自定义菜单列表 | | themeName | String | "white" | 当前使用的主题名称 |
5.2 事件
| 事件名 | 参数 | 说明 | | ------------------- | -------- | ------------------ | | onCustomMenuClicked | event | 自定义菜单点击事件 | | line-change | line | 线条变化事件 | | template-change | template | 模板变化事件 |
5.3 方法
注:以下方法仅在使用 custom 模式时需要了解和实现,local 模式下不需要考虑。
组件内部提供的方法主要用于模板和线条的管理:
upsertTemplate(data) - 新增或更新模板
- 参数:
data- 模板数据 - 返回值:
Promise<Object>- 插入或更新后的完整模板对象
- 参数:
delTemplate(data) - 删除模板
- 参数:
data- 模板数据(需包含templateId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLane(data) - 新增或更新泳道
- 参数:
data- 泳道数据 - 返回值:
Promise<Object>- 插入或更新后的完整泳道对象
- 参数:
delLane(lane) - 删除泳道
- 参数:
lane- 泳道数据(需包含laneId和lines数组) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
upsertLine(data) - 新增或更新线条
- 参数:
data- 线条数据 - 返回值:
Promise<Object>- 插入或更新后的完整线条对象
- 参数:
delLine(data) - 删除线条
- 参数:
data- 线条数据(需包含lineId和laneId) - 返回值:
Promise<void>- 操作成功或失败的 Promise
- 参数:
restoreSetting() - 恢复默认设置
- 功能:将当前场景的数据重置为初始配置状态
- 实现逻辑:使用构造函数传入的初始 dataSource 重新初始化数据
- 返回值:
Promise<void>- 恢复默认设置的 Promise
6. 自定义插槽
组件支持根据泳道 ID 动态生成的插槽,用于自定义泳道头部:
<KdLaneChartContainer ...>
<!-- 动态slot名称 -->
<template v-if="slotName">
<div :slot="slotName" class="demo-slot">
{{ slotName }}
</div>
</template>
<!-- 带参数的插槽 -->
<template v-if="slotName2" :slot="slotName2" slot-scope="slotData">
<div class="demo-slot">{{ typeof slotData }}</div>
</template>
</KdLaneChartContainer>插槽名称格式为 lane${laneId},例如:lane1556bdbfd0f24c11948b14999947c556。
6.2 draw-slot 画布插槽
组件提供 draw-slot 插槽用于自定义绘制内容,该插槽占据泳道下方的整个绘制区域:
<KdLaneChartContainer ...>
<template slot="draw-slot">
<div style="height: 100%; width: 100%; padding: 10px">
<!-- 自定义绘制内容 -->
</div>
</template>
</KdLaneChartContainer>6.3 插槽布局与尺寸注意事项
布局方式:
- 自定义插槽与泳道区域采用 flex 布局
- 自定义插槽会占据剩余位置后,与其他泳道进行平分
- 确保自定义插槽内容的宽度和高度设置正确,以保证与泳道对齐
尺寸单位:
- 组件内的自定义插槽使用 style 绑定形式
- 宽度和高度单位必须使用 px,以确保精确对齐
- 避免使用其他单位(如 %、rem、em 等),否则可能导致布局错位
样式处理:
- 不要使用全局样式处理插件对自定义插槽的尺寸单位进行转换
- 直接使用 px 单位编写插槽内容的尺寸样式
- 确保插槽内容的 box-sizing 为 border-box,以避免 padding 和 border 影响实际尺寸
<!-- 推荐的插槽内容样式 -->
<template slot="draw-slot">
<div style="height: 100%; width: 100%; box-sizing: border-box; padding: 10px">
<!-- 自定义绘制内容 -->
</div>
</template>7. 主题颜色设置
7.1 组件主题属性
组件支持通过 themeName 属性设置当前主题,可选值包括 white、dark 和 gray。
<KdLaneChartContainer
:themeName="themeName"
...
>7.2 线条级别主题配置
每个线条对象可以通过 themeConfig 属性配置不同主题下的颜色,格式为:
themeConfig: {
[themeName]: { lineColor: "颜色值" },
...
}示例:
lines: [
{
paramId: "51",
lineColor: "#E5360B", // 默认颜色
themeConfig: {
white: { lineColor: "blue" }, // 白色主题颜色
dark: { lineColor: "black" }, // 暗黑主题颜色
gray: { lineColor: "yellow" }, // 灰色主题颜色
},
},
];当组件的 themeName 变化时,线条会自动应用对应主题的颜色。如果未配置 themeConfig,则使用默认的 lineColor。
7.3 主题切换示例
<template>
<div id="app">
<KdLaneChartContainer class="container" :config="config" :themeName="themeName" ...>
<!-- 插槽内容 -->
</KdLaneChartContainer>
<div style="display: flex">
<button @click="changeCheme('white')">white</button>
<button @click="changeCheme('dark')">dark</button>
<button @click="changeCheme('gray')">gray</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
themeName: "white", // 默认主题
// ...其他配置
};
},
methods: {
changeCheme(themeName) {
this.themeName = themeName;
// 可选:给body设置data-theme属性,用于全局样式切换
document.body.setAttribute("data-theme", themeName);
},
},
};
</script>
## 8. 样式定制 可以通过 CSS 变量或直接覆盖样式来自定义组件外观: ```css .kd-lane-chart-container { --kd-lane-container-border-color: white;
--kd-lane-container-context-background-color: darkgray; --kd-lane-container-context-hover-color: darkgray;
--kd-lane-container-header-item-color: white; --app-background-color: gray; }8. 使用示例
<template>
<div id="app">
<KdLaneChartContainer class="container" :config="config" :customMenuList="customMenuList" @onCustomMenuClicked="onCustomMenuClicked">
<!-- 动态slot名称,这里全部使用的是旧语法 -->
<template v-if="slotName">
<div :slot="slotName" class="demo-slot">
{{ slotName }}
</div>
</template>
<template v-if="slotName2" :slot="slotName2" slot-scope="slotData">
<div class="demo-slot">{{ typeof slotData }}</div>
</template>
</KdLaneChartContainer>
</div>
</template>
<script>
import Vue from "vue";
import KdLaneChartContainer from "kd-lane-container";
Vue.use(KdLaneChartContainer);
import { data } from "./mock/mockData.js";
export default {
name: "App",
components: {},
data() {
return {
config: {
type: "local",
caseId: "demo",
versionCode: 2,
// for with server
dataSource: { templates: data.templates, lanes: data.lanes, lines: data.lines, params: data.params },
},
slotName: "",
slotName2: "",
customMenuList: [{ name: "单屏时长", key: "timeRange" }],
};
},
mounted() {
setTimeout(() => {
this.slotName = "lane1556bdbfd0f24c11948b14999947c556";
}, 2000);
},
methods: {
onCustomMenuClicked(event) {
console.log(event);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
height: 100vh;
position: relative;
padding: 10px;
.container {
margin-left: 100px;
margin-top: 50px;
height: 600px;
width: 800px;
}
.demo-slot {
width: 80px;
}
}
/* 全局设置 box-sizing 为 border-box */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
</style>