# timeline-canvas **Repository Path**: wusyJava/timeline-canvas ## Basic Information - **Project Name**: timeline-canvas - **Description**: 一个基于 vue 框架使用 canvas 绘制的时间轴组件,可用于视频、录像播放或实时数据展示等业务。 - **Primary Language**: JavaScript - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 14 - **Created**: 2023-03-21 - **Last Updated**: 2024-12-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # **timeline-canvas** 一个基于 vue 框架使用 canvas 绘制的时间轴组件,可用于视频、录像播放或实时数据展示等业务。 ## **组件特点** ### 1. 高性能 组件使用纯原生的 canvas 绘图未使用第三库,所以组件体积很小; 同时相比于使用 div 方案需要频繁操作 Dom 性能上更高、体验更好。 ### 2. 全端自适配 组件可以在电脑、移动端自适应,无需额外的配置。 - 宽度自适应,由于canvas 必须设置固定宽度,根据父容器的宽度动态计算 canvas 宽度,让组件宽度支持百分比设置; ```javascript //自适应父容器宽度 this.width参数支持百分比设置 let parentWidth = canvas.parentElement.clientWidth; if (/^(\d|[1-9]\d|100)%$/.test(this.width)) { width = Math.floor((this.width.replace("%", "") / 100) * parentWidth); } ``` - 画布与图像比例自适应,通过 devicePixelRatio 像素比计算 canvas 画布与图像的比例,解决移动模糊的问题; ```javascript //移动端像素模糊问题是由于dpr像素比造成的,扩大canvas画布的像素,使1个canvas像素和1个物理像素相等 this.dpr = window.devicePixelRatio; // // 设置图像大小 canvas.style.width = `${width}px`; canvas.style.height = `${this.height}px`; // 设置画布大小 canvas.width = Math.round(width * this.dpr); canvas.height = Math.round(this.height * this.dpr); // 由于画布扩大,canvas的坐标系也跟着扩大, // 按照原先的坐标系绘图内容会缩小, 所以需要将绘制比例放大 this.ctx.scale(this.dpr, this.dpr); ``` - 刻度线自适应,不管 canvas 缩小到什么宽度,都能保证刻度线不会挤压在一起; ```javascript // 每个像素点对应多少秒(像素转时间和刻度) px_second() { let second = (this.whole_hour * 60 * 60) / this.canvasWidth; // 保证不管缩小到什么宽度,刻度线都不会挤压在一起 if (second > this.minPxSecond) second = this.minPxSecond; return second; } ``` - 事件自动适配,电脑端和移动端分别自动注册事件; ```javascript //是否为手机端 this.isMobile = /Mobi/i.test(navigator.userAgent); //移动端如不禁止,在滑动时会触发鼠标事件与滑动事件冲突 if (!this.isMobile) { canvas.addEventListener("mousewheel", this.mousewheel); canvas.addEventListener("mousemove", this.mousemove); canvas.addEventListener("mousedown", this.mousedown); canvas.addEventListener("mouseup", this.mouseup); canvas.addEventListener("mouseleave", this.mouseleave); } ``` - 参数监听,当参与组件绘制的参数发生变化时会立马响应重新绘制; ```javascript computed: { //计算需要重新绘制的参数,方便统一监听 changeProps() { let { startMeddleTime, markTime, timeRange } = this; this.meddleTime = this.startMeddleTime; return { startMeddleTime, markTime, timeRange }; } }, watch: { // 监听需要重新绘制的参数 changeProps: function (newV) { // 绘制 this.drow(); }, }, ``` - 窗口或屏幕宽自适应,组件会随着电脑端的窗口、手机的屏幕宽的大小变化而自动缩放。 ```javascript // 监听窗口大小 resize() { let canvas = this.$refs.canvas; //有时屏幕尺寸变化了,而容器的尺寸还未改变的情况下的处理 if (canvas.style.width === canvas.parentElement.clientWidth + "px") { setTimeout(() => { this.resize(); }, 10); } else { //重新初始化 this.init(); } } ``` ### 3. 功能丰富 **1.拖动或点击时间轴** 在释放的时候可以获得时间数据; **2.设置时间点** 通过 `startMeddleTime` 参数可以设置起点时间,可将设置的时间切换到时间轴的中间; **3.设置时间区域** 通过 `timeRange` 参数可以指定录像时间段,时间轴只绘制这段时间内的刻度线,并且只能在这段时间里进行拖动; **4.设置区域标记** 通过 `markTime` 参数可以对时间轴的某个或某几个区域进行标记,标记的区域可以自定义背景颜色和文本说明; **5.刻度缩放** 时间轴刻度支持多级显示,可以通过鼠标滚轮或双指对刻度进行缩小放大; **6.自动播放** 设置参数 `isAutoPlay = true` 可以开启自动播放,开启后时间轴将以 1s 的速度前进; **7.事件监听** 可以绑定 `change` 事件来监听时间轴的时间变化和状态变化; **8.hover 显示时间** 鼠标放在时间轴上移动可以显示时间; **9.自定义样式** 可以设置 `colors` 参数对颜色自定义; **10.组件独立** 可以在同一页面内使用多个时间轴组件互干扰; **11.时间轴绘制** 通过 canvas 动态绘制刻度、录像段、时间点。 ### 4. 使用简单 1.时间轴已组件化,可以在 vue 框架直接使用,甚至可做到无参使用; 2.所有代码开源,并且代码注释详细,文档使用说明和示例齐全; 3.API 操作灵活,可以灵活的适用各种应用场景和定制化的二次开发。 ## **动画演示** ![图片加载失败](./src/assets/doc/imgs/demo/dome.gif) ## **安装** ```JS npm install ``` ## **运行** ```JS npm run serve ``` ## **配置** ### 引入组件 `main.js`: ```js // 全局注册 import TimeLineCanvas from "./components/timeline-canvas.vue"; Vue.use(TimeLineCanvas); ``` 在 `script` 中引用组件: ```javascript // 如采用全局注册,页面就不需要再引用注册,可以直接使用 import TimeLineCanvas from "./components/timeline-canvas.vue"; export default { components: { TimeLineCanvas, }, .... } ``` 在 `template` 中使用组件: ```html ``` 或 ```html ``` ### 组件数据 ```js export default { data() { return { isAutoPlay: false, width: "100%", startMeddleTime: "2023-01-02 08:54:56", time_range: ["2023-01-02 00:00:00", "2023-01-02 23:59:59"], markTime: [ { beginTime: "2023-01-02 01:01:00", endTime: "2023-01-02 02:02:00", bgColor: "red", text: "困人", }, { beginTime: "2023-01-02 08:01:00", endTime: "2023-01-02 10:02:00", bgColor: "pink", text: "非法闯入", }, { beginTime: "2023-01-02 15:01:00", endTime: "2023-01-02 16:02:00", bgColor: "yellow", text: "故障", }, ], }; }, methods: { clickCanvas(date) { console.log(date); }, changeDate(date, status) { console.log("选择时间:" + date + " 播放状态:" + status); }, }, }; ``` ### Props | 名称 | 说明 | 类型 | 默认 | | --------------- | ---------------------------------------------------------------------- | :--------------: | :-----: | | width | 时间轴宽度,支持固定(不需要带单位)和百分比,默认自适应父容器 | Number String | 100% | | height | 时间轴高度,非必要可以忽略 | Number String | 60 | | startMeddleTime | 启动时间,未传参时会根据`timeRange` 计算;`timeRange` 参数也未传采用当前时间| String | | | timeRange | 时间轴绘制的时间范,当参数为`String` 时传某天的日期;当为`Array`时传时间范围 | Array String | 当天 | | markTime | 区域进行标记,可以自定义背景颜色和文说明本 | Array | | | isAutoPlay | 开启后时间轴将以 `1s` 的速度前进进 | Boolean | | | colors | 自定义颜色 | Object | | ### Props [markTime] 结构 | 名称 | 说明 | 类型 | | --------- | ----------- | :----: | | beginTime | 开始位置 | String | | endTime | 结束位置 | String | | bgColor | 背景颜色 | String | | text | 文本说明 | String | ### Props [colors] 结构 | 名称 | 说明 | 类型 | 默认值 | | --------- | ----------- | :----: |----- | | background | 背景 | String | #2b2f33 | | meddleLine | 中间线 | String | #33CC33 | | meddleDate | 中间时间 | String | #33CC33 | | moveLine | 移动线 | String | #808080 | | moveDate | 移动时间 | String | #009966 | | scaleLine | 刻度线 | String | #808080 | | scaleBar | 刻度条 | String | #45484c | ### Methods | 名称 | 说明 | 参数 | | -------- | ----------- | ------ | | play | 自动播放未开启,时可以手动播放 | `date`:播放的起始时间| | stop | 手动暂停播放 | | ### Events | 名称 | 说明 | 回调参数 | | ------ | ----------- | ------ | | click | 拖动或点击时间轴释放的时候触发 | `date`:选择的时间 | change | 当时间和播放状态发生变化时触发,只有当开启 `isAutoPlay=true` 才有状态变化 | `date`:选择的时间 `status`:播放状态 *(`start`:开始 `play`:播放 `stop`:暂停 `end`:结束)* ## **最后说明** 在刚开始有考虑用div方案,后面使用起来发现每一次重绘就要操作上百个dom节点,性能很差,所以决定最后决定采用canvas来写时间轴。 以上就是本文的全部内容,希望对大家有所帮助,也希望大家多多支持。 ## **update(更新内容)** - 2023-02-16 完善文档 - 2023-02-13 发布 1.0.0 开源版本 - 2023-02-10 优化代码规范和完善注释 - 2023-02-05 优化功能准备开源 - 2022年底 完成初版