time-axis-plus 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023-present
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # vue-time-axis
2
+
3
+ 基于 **Canvas 双层渲染**的 Vue 3 时间轴组件,专为**监控录像回放**场景设计:支持录像片段可视化、点击/拖动定位、播放指针跟随、跨空白续播、双进度条概览、移动端手势缩放。**零运行时依赖**、**CSS 已内联**、**组件与原生 class 双模式**。
4
+
5
+ ## ✨ 特性
6
+
7
+ - **双层 Canvas 架构**:静态层(边框 / 片段 / 刻度)仅在数据或视野变化时重绘,动态层(播放指针 / 悬浮提示)高频重绘成本低。
8
+ - **监控回放优化**:片段自动去重叠、播放指针居中跟随、点击空白跨段自动续播(`snap` + `nextBegin`)。
9
+ - **双进度条**:主时间轴 + 底部全天概览条(显示片段分布、可视窗口、播放位置,可点击 / 拖动跳转)。
10
+ - **移动端适配**:双指捏合缩放,粗指针设备自动降级(隐藏悬浮提示、调整缩放极限)。
11
+ - **零运行时依赖**:原生 `Date` + `ResizeObserver` 实现,不依赖 dayjs / element-resize-detector。
12
+ - **CSS 内联注入**:`es` / `cjs` / `umd` 全格式自包含样式,无需单独引入 css 文件。
13
+ - **双模式使用**:Vue 组件 `VueTimeAxis`,或脱离 Vue 直接操作 canvas 的原生 class `timeAxis`。
14
+
15
+ ## 📦 安装
16
+
17
+ ```bash
18
+ npm install vue-time-axis
19
+ # 或
20
+ pnpm add vue-time-axis
21
+ ```
22
+
23
+ > **peer 依赖**:`vue ^3.2.0`(由使用方提供;组件仅使用稳定的 Options API 特性)。
24
+
25
+ ## 🚀 快速开始
26
+
27
+ ```vue
28
+ <template>
29
+ <VueTimeAxis
30
+ :start-time="startTime"
31
+ :segments="segments"
32
+ :height="60"
33
+ @changeTime="onChangeTime"
34
+ />
35
+ </template>
36
+
37
+ <script>
38
+ import VueTimeAxis from 'vue-time-axis';
39
+
40
+ export default {
41
+ components: { VueTimeAxis },
42
+ data() {
43
+ // 建议用本地时区构造时间戳,避免 new Date('YYYY-MM-DD') 的 UTC 解析偏差
44
+ const t = (h, m = 0, s = 0) => new Date(2022, 3, 14, h, m, s).getTime();
45
+ return {
46
+ startTime: t(0),
47
+ segments: [
48
+ { begin: t(0), end: t(0, 0, 10), style: { background: 'rgba(24,208,217,0.5)' } },
49
+ { begin: t(6), end: t(7), style: { background: 'rgba(24,208,217,0.5)' } },
50
+ { begin: t(6, 30), end: t(7, 50), style: { background: 'rgba(255,77,79,0.6)' } },
51
+ ],
52
+ };
53
+ },
54
+ methods: {
55
+ onChangeTime(data) {
56
+ // { mode, timestamp, valid, nextBegin }
57
+ console.log(data.mode, data.timestamp, data.valid, data.nextBegin);
58
+ },
59
+ },
60
+ };
61
+ </script>
62
+ ```
63
+
64
+ ## 🧩 引入方式
65
+
66
+ 组件默认导出即 `VueTimeAxis`,同时提供具名导出 `VueTimeAxis`(组件)与 `timeAxis`(原生 class)。
67
+
68
+ ```js
69
+ // ① 局部注册(默认导出)
70
+ import VueTimeAxis from 'vue-time-axis';
71
+ export default { components: { VueTimeAxis } };
72
+
73
+ // ② 局部注册(具名导出,可同时拿 class)
74
+ import { VueTimeAxis, timeAxis } from 'vue-time-axis';
75
+
76
+ // ③ 全局注册(install 注册名即 VueTimeAxis)
77
+ import { createApp } from 'vue';
78
+ import VueTimeAxis from 'vue-time-axis';
79
+ createApp(App).use(VueTimeAxis).mount('#app');
80
+ // 之后模板中可直接用 <VueTimeAxis />
81
+ ```
82
+
83
+ **UMD(浏览器 `<script>`,无构建工具)**:
84
+
85
+ ```html
86
+ <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
87
+ <script src="https://unpkg.com/vue-time-axis/index.umd.js"></script>
88
+ <script>
89
+ const { VueTimeAxis, timeAxis } = window.VueTimeAxis; // 命名空间对象
90
+ const app = Vue.createApp({ /* ... */ });
91
+ app.use(VueTimeAxis); // 或 app.component('VueTimeAxis', VueTimeAxis.default)
92
+ </script>
93
+ ```
94
+
95
+ > CSS 已内联进 JS,**无需**再 `import 'vue-time-axis/style.css'`。
96
+
97
+ ## 📥 Props
98
+
99
+ | 属性 | 说明 | 类型 | 默认值 |
100
+ |------|------|------|--------|
101
+ | `width` | 宽度,数字按 px,字符串原样(如 `'100%'`) | `Number \| String` | `'100%'` |
102
+ | `height` | 高度,数字按 px | `Number \| String` | `40` |
103
+ | `startTime` | 轴起始时间(画布左缘对应的毫秒时间戳) | `Number` | 当天 0 点 |
104
+ | `segments` | 录像片段数组 `[{ begin, end, style? }]`,内部自动去重叠 | `Array` | `[]` |
105
+ | `visibleHours` | 可见时长(小时),即当前视口跨度 | `Number` | `24` |
106
+ | `maxVisibleHours` | PC 端缩小极限(可见时长上限) | `Number` | `24` |
107
+ | `mobileMaxVisibleHours` | 移动端缩小极限(默认更小,避免刻度拥挤) | `Number` | `12` |
108
+ | `minTime` | 可视边界起始(ms),`null` 不限制 | `Number` | `null` |
109
+ | `maxTime` | 可视边界结束(ms),`null` 不限制 | `Number` | `null` |
110
+ | `snapToNearest` | 点击空白区是否吸附到最近片段起点(跨空白续播) | `Boolean` | `false` |
111
+ | `hoverTip` | 悬浮十字线 + 时间提示;`null` 按设备自动(PC 开 / 移动关) | `Boolean` | `null` |
112
+ | `centerPointer` | 播放指针居中:`updateTime` 推进时自动滚动视口使指针居中 | `Boolean` | `false` |
113
+ | `centerResumeDelay` | 手势让位后自动恢复居中跟随的延迟(ms) | `Number` | `3000` |
114
+ | `overview` | 是否显示底部全天概览条(双进度条),**支持运行时动态开关** | `Boolean` | `false` |
115
+ | `overviewHeight` | 概览条高度(px) | `Number` | `20` |
116
+ | `overviewStart` | 概览范围起始(ms),`null` 自动推导(取边界或起始日全天) | `Number` | `null` |
117
+ | `overviewEnd` | 概览范围结束(ms),`null` 自动推导 | `Number` | `null` |
118
+ | `backgroundColor` | 画布背景色 | `String` | `'#000'` |
119
+ | `axisStyle` | 轴样式配置,支持只传部分字段逐项覆盖(见下表) | `Object` | `{}` |
120
+
121
+ > `startTime` / `minTime` / `maxTime` / `segments` / `visibleHours` / `overviewStart` / `overviewEnd` 变化会自动重绘;`axisStyle` / `snapToNearest` / `centerPointer` 等变化即时生效。
122
+
123
+ ## 📤 Events
124
+
125
+ | 事件 | 回调参数 | 触发时机 |
126
+ |------|----------|----------|
127
+ | `changeTime` | `{ mode, timestamp, valid, nextBegin }` | 用户交互改变选中时间(点击 / 拖动 / 吸附) |
128
+ | `playTime` | `{ timestamp, valid }` | 播放指针推进(调用 `updateTime` 时触发) |
129
+
130
+ **`changeTime` 参数详解**:
131
+
132
+ - `mode`:触发方式,`'click'`(点击)\| `'drag'`(拖动)\| `'snap'`(点击空白被吸附到下一段起点)。
133
+ - `timestamp`:选中的毫秒时间戳。
134
+ - `valid`:选中点是否落在有效录像片段内。
135
+ - `nextBegin`:从选中时间往后最近一段录像的**完整信息**(含 `id` / `style` 等业务字段),无则 `null`。
136
+
137
+ **`playTime` 参数详解**:
138
+
139
+ - `timestamp`:当前播放毫秒时间戳。
140
+ - `valid`:是否处于有效录像区。
141
+ - 该回调**不控制自动续播**:`valid` 为 `false`(进入空白)时由业务侧决定如何处理,需要续播可调用 `getNextSegment(timestamp)` 查询下一段。
142
+
143
+ ## 🛠 Methods(通过 `ref` 调用)
144
+
145
+ ```vue
146
+ <VueTimeAxis ref="timeline" ... />
147
+ <!-- this.$refs.timeline.updateTime(Date.now()) -->
148
+ ```
149
+
150
+ | 方法 | 说明 |
151
+ |------|------|
152
+ | `updateTime(time)` | 更新播放指针到 `time`(ms),触发 `playTime` 回调 |
153
+ | `getViewport()` | 返回当前视口 `{ startTime, visibleHours }` |
154
+ | `setViewport(startTime?, visibleHours?)` | 设置视口,两个参数均可省略 |
155
+ | `scrollTo(time)` | 把指定时间滚动到画布中央 |
156
+ | `resumeCenter()` | 立即结束手势让位并恢复居中跟随 |
157
+ | `zoomIn()` | 放大一档 |
158
+ | `zoomOut()` | 缩小一档 |
159
+ | `getNextSegment(time)` | 从 `time` 往后最近的一个片段,找不到返回 `null` |
160
+ | `getNextSegments(time)` | 从 `time` 往后的全部片段(`begin` 升序,完整信息),可作续播播放列表 |
161
+ | `updateOptions(json)` | 运行时更新配置:传入 json 对象逐项合并,支持动态开关 `overview`、改样式/边界/片段/视口等 |
162
+
163
+ ### 运行时动态更新配置
164
+
165
+ 除了通过 props 响应式更新,也可调用 `updateOptions(json)` 主动更新任意配置(组件与原生 class 均支持)。典型场景是**动态开关概览条**:
166
+
167
+ ```vue
168
+ <template>
169
+ <VueTimeAxis ref="timeline" :segments="segments" />
170
+ <button @click="$refs.timeline.updateOptions({ overview: true })">显示概览条</button>
171
+ <button @click="$refs.timeline.updateOptions({ overview: false })">隐藏概览条</button>
172
+ <button @click="$refs.timeline.updateOptions({ axisStyle: { tickTextColor: '#ff0' } })">换肤</button>
173
+ </template>
174
+ ```
175
+
176
+ > `overview` 也可直接用 prop 动态绑定(`:overview="show"`),组件内部 `watch` 会自动调用 `updateOptions` 完成概览层的挂载/卸载与画布高度重算。
177
+ > `updateOptions` 内部会自动处理:`axisStyle` 逐项合并、`segments` 规范化去重叠、`visibleHours`/`startTime` 边界钳制、`overview` 结构重建,并在最后统一重绘。
178
+
179
+ ## 🎨 axisStyle 样式配置
180
+
181
+ `axisStyle` 支持只传部分字段,逐项覆盖默认值:
182
+
183
+ | 字段 | 默认值 | 说明 |
184
+ |------|--------|------|
185
+ | `borderColor` | `rgb(151, 158, 167)` | 上下边框线 |
186
+ | `graduationColor` | `rgba(151, 158, 167, 1)` | 刻度线 |
187
+ | `tickTextColor` | `#ffffff` | 刻度文字 |
188
+ | `hoverLineColor` | `rgb(194, 202, 215)` | 悬浮十字线 |
189
+ | `hoverTextColor` | `rgb(0, 255, 0)` | 悬浮时间文字 |
190
+ | `overviewBg` | `rgb(43, 47, 51)` | 概览条背景 |
191
+ | `overviewTickColor` | `rgba(151, 158, 167, 0.35)` | 概览条小时参考刻度 |
192
+ | `overviewWindowColor` | `rgba(64, 196, 255, 0.15)` | 概览条可视窗口填充 |
193
+ | `overviewWindowBorder` | `rgb(64, 196, 255)` | 概览条可视窗口描边 |
194
+ | `overviewPlayColor` | `rgb(255, 92, 92)` | 概览条播放位置线 |
195
+
196
+ ```vue
197
+ <VueTimeAxis :axis-style="{ tickTextColor: '#ccc', overviewPlayColor: '#ff5c5c' }" />
198
+ ```
199
+
200
+ ## 📊 segments 数据格式
201
+
202
+ ```js
203
+ segments: [
204
+ {
205
+ begin: 1649865600000, // 起始毫秒时间戳(必填)
206
+ end: 1649869200000, // 结束毫秒时间戳(必填)
207
+ id: 'cam-01', // 业务字段(可选,会原样带回 nextBegin)
208
+ style: { background: 'rgba(24,208,217,0.5)' } // 片段样式(可选)
209
+ }
210
+ ]
211
+ ```
212
+
213
+ **去重叠规则**(无需预先处理,组件内部自动规范化):
214
+
215
+ - **完全重叠**:舍弃后段,以前段样式为准。
216
+ - **部分重叠**:按重叠起始位置分割,各自保留自身样式。
217
+ - **邻接**(首尾相接):不合并。
218
+ - 回调里返回的片段(如 `nextBegin`)均为**规范化后**的结果。
219
+
220
+ 未传 `style` 的片段使用默认样式 `rgba(24,208,217,0.5)`。
221
+
222
+ ## ⚙️ 原生 class 用法(脱离 Vue)
223
+
224
+ `timeAxis` 是底层的纯原生 canvas 类,可在任意环境(不限 Vue)使用:
225
+
226
+ ```js
227
+ import { timeAxis } from 'vue-time-axis';
228
+
229
+ const axis = new timeAxis({
230
+ container: document.getElementById('timeline'), // DOM 元素或元素 id 字符串(必填)
231
+ startTime: new Date(2022, 3, 14).getTime(),
232
+ segments: [{ begin: /* ... */, end: /* ... */, style: { background: 'rgba(24,208,217,0.5)' } }],
233
+ minTime: new Date(2022, 3, 14, 0, 0, 0).getTime(),
234
+ maxTime: new Date(2022, 3, 14, 23, 59, 59).getTime(),
235
+ centerPointer: true,
236
+ changeCallback: (data) => console.log('change', data), // 对应组件 changeTime
237
+ playCallback: (data) => console.log('play', data), // 对应组件 playTime
238
+ });
239
+
240
+ axis.updateTime(Date.now()); // 推进播放指针
241
+ axis.zoomIn(); // 放大
242
+ axis.updateOptions({ overview: true }); // 传入 json 动态更新配置(如开启概览条)
243
+ // ... 组件的全部 methods(getViewport/setViewport/scrollTo/resumeCenter/
244
+ // zoomIn/zoomOut/getNextSegment/getNextSegments/updateTime/updateOptions)class 同样具备
245
+
246
+ axis.destroy(); // 用完销毁,释放 canvas 与事件监听
247
+ ```
248
+
249
+ class 额外可配置项:`segmentStyle`(片段默认样式)、`pointerOptions`(指针样式 `{ beginY, endY, color, width }`)、`minVisibleHours`(放大极限,默认 `0.02` 小时≈秒级刻度)、`overviewGap`(概览条与主轴间距,默认 `4`px)等。
250
+
251
+ ## 📖 完整示例(监控回放)
252
+
253
+ ```vue
254
+ <template>
255
+ <div>
256
+ <VueTimeAxis
257
+ ref="timeline"
258
+ :start-time="startTime"
259
+ :min-time="minTime"
260
+ :max-time="maxTime"
261
+ :segments="segments"
262
+ :snap-to-nearest="true"
263
+ :center-pointer="true"
264
+ :height="40"
265
+ @changeTime="onChangeTime"
266
+ @playTime="onPlayTime"
267
+ />
268
+ <button @click="togglePlay">{{ playing ? '暂停' : '播放' }}</button>
269
+ <button @click="$refs.timeline.zoomIn()">放大</button>
270
+ <button @click="$refs.timeline.zoomOut()">缩小</button>
271
+ <button @click="$refs.timeline.scrollTo(playTime)">定位到播放位置</button>
272
+ </div>
273
+ </template>
274
+
275
+ <script>
276
+ import VueTimeAxis from 'vue-time-axis';
277
+
278
+ const DAY = '2022-04-14';
279
+ // 按本地时区把 'YYYY-MM-DD HH:mm:ss' 解析为时间戳
280
+ const toTime = (str) => {
281
+ const [date, time = '00:00:00'] = str.split(' ');
282
+ const [y, mo, d] = date.split('-').map(Number);
283
+ const [h, mi, s] = time.split(':').map(Number);
284
+ return new Date(y, mo - 1, d, h, mi, s).getTime();
285
+ };
286
+
287
+ export default {
288
+ components: { VueTimeAxis },
289
+ data() {
290
+ return {
291
+ startTime: toTime(DAY),
292
+ minTime: toTime(DAY),
293
+ maxTime: toTime(`${DAY} 23:59:59`) + 999,
294
+ segments: [
295
+ { id: '1', begin: toTime(`${DAY} 06:00:00`), end: toTime(`${DAY} 07:00:00`), style: { background: 'rgba(24,208,217,0.5)' } },
296
+ { id: '2', begin: toTime(`${DAY} 06:30:00`), end: toTime(`${DAY} 07:50:00`), style: { background: 'rgba(255,77,79,0.6)' } },
297
+ ],
298
+ playing: false,
299
+ playTimer: null,
300
+ playTime: toTime(DAY),
301
+ };
302
+ },
303
+ beforeUnmount() {
304
+ this.stopPlay();
305
+ },
306
+ methods: {
307
+ onChangeTime(data) {
308
+ // 用户点击/拖动/吸附:通知播放器 seek 到 data.timestamp
309
+ this.playTime = data.timestamp;
310
+ if (this.playing) { this.stopPlay(); this.startPlay(); }
311
+ },
312
+ onPlayTime(data) {
313
+ // 播放进入空白(valid=false)时,可查下一段实现自动续播
314
+ if (!data.valid) {
315
+ const next = this.$refs.timeline.getNextSegment(data.timestamp);
316
+ if (next) this.playTime = next.begin;
317
+ }
318
+ },
319
+ togglePlay() { this.playing ? this.stopPlay() : this.startPlay(); },
320
+ startPlay() {
321
+ this.playing = true;
322
+ this.playTimer = setInterval(() => {
323
+ this.playTime += 1000;
324
+ if (this.playTime >= this.maxTime) return this.stopPlay();
325
+ this.$refs.timeline.updateTime(this.playTime);
326
+ }, 1000);
327
+ },
328
+ stopPlay() {
329
+ this.playing = false;
330
+ if (this.playTimer) { clearInterval(this.playTimer); this.playTimer = null; }
331
+ },
332
+ },
333
+ };
334
+ </script>
335
+ ```
336
+
337
+ ## ⚠️ 注意事项
338
+
339
+ - **时间单位**:所有时间相关的 props / 参数 / 回调字段均为**毫秒时间戳**(`Number`)。
340
+ - **时区**:构造时间戳建议用 `new Date(y, m - 1, d, h, mi, s).getTime()`(本地时区),避免 `new Date('YYYY-MM-DD')` 被按 UTC 解析导致偏移。
341
+ - **CSS 已内联**:无需单独引入样式文件。
342
+ - **自动清理**:组件卸载时会自动 `destroy()`,释放 canvas、`ResizeObserver` 与 `window.resize` 监听,无内存泄漏。
343
+ - **容器尺寸**:`width` 默认 `'100%'`(撑满父容器宽度);`height` 默认 `40`(px 固定高度),若显式设为 `'100%'` 则依赖父容器有确定高度;组件通过 `ResizeObserver` 自动响应容器尺寸变化重绘。
344
+ - **预留字段**:源码中的 `movePlay`、`clickPlay` 为历史预留 prop,当前版本**未接线生效**,请勿依赖。
345
+
346
+ ## 📄 License
347
+
348
+ MIT
package/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".timeline-group[data-v-b90b2c6f]{font-size:0}.timeline-group .timeline-canvas[data-v-b90b2c6f]{background-color:#2b2f33}.timeline-group canvas[data-v-b90b2c6f]{display:block;touch-action:none}")),document.head.appendChild(e)}}catch(t){console.error("vite-plugin-css-injected-by-js",t)}})();
2
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const w=require("vue"),b={borderColor:"rgb(151, 158, 167)",graduationColor:"rgba(151, 158, 167, 1)",tickTextColor:"#ffffff",hoverLineColor:"rgb(194, 202, 215)",hoverTextColor:"rgb(0, 255, 0)",overviewBg:"rgb(43, 47, 51)",overviewTickColor:"rgba(151, 158, 167, 0.35)",overviewWindowColor:"rgba(64, 196, 255, 0.15)",overviewWindowBorder:"rgb(64, 196, 255)",overviewPlayColor:"rgb(255, 92, 92)"};class T{constructor(t){if(!t)throw new Error("timeAxis: options is required");let e=typeof t.container=="string"?document.getElementById(t.container):t.container;if(!e)throw new Error("timeAxis: options.container is required(DOM 元素或 id 字符串)");let i={visibleHours:24,minVisibleHours:.02,maxVisibleHours:24,graduationMinStep:10,secondsPerStep:[1,2,6,12,60,120,240,360,720,3600,7200,14400,21600,43200,86400],segmentStyle:{background:"rgba(24,208,217,0.5)"},pointerOptions:{beginY:0,endY:30,color:"rgb(64, 196, 255)",width:2},minTime:null,maxTime:null,startTime:this.dayStartOf(Date.now()),backgroundColor:"#000",snapToNearest:!1,hoverTip:!0,centerPointer:!1,centerResumeDelay:3e3,overview:!1,overviewHeight:20,overviewGap:4,overviewStart:null,overviewEnd:null,segments:[]};this.options=Object.assign({},i,t),this.options.container=e,this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,this.options.visibleHours)),this.configMinVisibleHours=this.options.minVisibleHours,this.options.segments=this.normalizeSegments(this.options.segments),this.options.segments.length&&(this.currentTimestamp=this.options.segments[0].begin),this.options.segmentStyle&&this.options.segmentStyle.background||(this.options.segmentStyle={background:"rgba(24,208,217,0.5)"}),this.options.axisStyle=Object.assign({},b,this.options.axisStyle||{}),this.options.startTime=this.clampStartTime(this.options.startTime),this.options.overviewStart==null&&(this.options.overviewStart=this.options.minTime!=null?this.options.minTime:this.dayStartOf(this.options.startTime)),this.options.overviewEnd==null&&(this.options.overviewEnd=this.options.maxTime!=null?this.options.maxTime:this.options.overviewStart+24*60*60*1e3),this.isClick=!1,this.button=0,this.isPressDown=!1,this.isDragPointer=!1,this.currentChecked="",this.pinchStartDistance=0,this.hoverState=null,this.centerPaused=!1,this.lastInteractTime=0,this.initCanvas(),this.drawStatic()}initCanvas(){this.options.container.style.position="relative",this.canvas=document.createElement("canvas"),this.canvas.style.position="absolute",this.canvas.style.left="0",this.canvas.style.top="0",this.overlayCanvas=document.createElement("canvas"),this.overlayCanvas.style.position="absolute",this.overlayCanvas.style.left="0",this.overlayCanvas.style.top="0",this.options.container.appendChild(this.canvas),this.options.container.appendChild(this.overlayCanvas),this.canvasCtx=this.canvas.getContext("2d"),this.overlayCtx=this.overlayCanvas.getContext("2d"),this.options.overview&&this.mountOverview(),this.initCanvasSize(),this.canvas.style.backgroundColor=this.options.backgroundColor,this.initEvents()}initCanvasSize(){let t=window.devicePixelRatio||1,e=this.options.container.clientWidth,i=this.options.container.clientHeight,s=this.options.overview?Math.max(0,i-this.options.overviewHeight-this.options.overviewGap):i,o=(a,u,v)=>{a.width=Math.round(e*t),a.height=Math.round(v*t),a.style.width=e+"px",a.style.height=v+"px",u.setTransform(t,0,0,t,0,0)};o(this.canvas,this.canvasCtx,s),o(this.overlayCanvas,this.overlayCtx,s),this.overviewCanvas&&(o(this.overviewCanvas,this.overviewCtx,this.options.overviewHeight),this.overviewCanvas.style.top=s+this.options.overviewGap+"px"),this.canvasWidth=e,this.canvasHeight=s,this.options.minVisibleHours=Math.min(this.configMinVisibleHours,this.canvasWidth/(this.options.graduationMinStep+2)/3600)}resize(){this.initCanvasSize(),this.drawStatic()}drawStatic(){this.pxPerMs=this.canvasWidth/(this.options.visibleHours*60*60*1e3),this.clearCanvas(),this.initBorders(),this.initSegments(this.options.segments||[]),this.initGraduationsLines(this.options.startTime),this.drawOverlay()}drawOverlay(){if(this.clearOverlay(),this.options.hoverTip&&this.hoverState){let{x:t,time:e}=this.hoverState;this.drawLine(this.overlayCtx,{beginX:t,beginY:0,endX:t,endY:this.canvasHeight,color:this.options.axisStyle.hoverLineColor,width:1,center:!0}),this.overlayCtx.fillStyle=this.options.axisStyle.hoverTextColor,this.overlayCtx.textAlign="center",this.overlayCtx.font="normal normal 12px Arial,sans-serif",this.overlayCtx.fillText(this.formatDate("yyyy-MM-dd hh:mm:ss",e),t,18)}this.isClick&&this.currentTimestamp!=null&&this.drawPointer(),this.drawOverview()}initBorders(){let t=this.options.axisStyle.borderColor;this.drawLine(this.canvasCtx,{beginX:0,beginY:0,endX:this.canvasWidth,endY:0,color:t,width:1}),this.drawLine(this.canvasCtx,{beginX:0,beginY:this.canvasHeight,endX:this.canvasWidth,endY:this.canvasHeight,color:t,width:1})}drawLine(t,{beginX:e,beginY:i,endX:s,endY:o,color:a,width:u,center:v}){let h=!v&&u%2===1?.5:0;t.beginPath(),t.moveTo(e+h,i+h),t.lineTo(s+h,o+h),t.strokeStyle=a,t.lineWidth=u,t.stroke()}initSegments(t){t.forEach((e,i)=>{this.drawSegment(e,i)}),this.canvasCtx.font="normal normal 12px Arial,sans-serif",this.canvasCtx.fillStyle=this.options.axisStyle.tickTextColor}drawSegment(t,e){let i=this.options.segmentStyle.background;t.style&&t.style.background&&(i=t.style.background);let s=this.pxPerMs*(t.begin-this.options.startTime),o=(t.end-t.begin)*this.pxPerMs;this.canvasCtx.fillStyle=i,this.canvasCtx.font="normal normal 12px Arial,sans-serif",this.canvasCtx.fillRect(s,0,o,this.canvasHeight),this.canvasCtx.fillStyle=this.options.axisStyle.tickTextColor}initGraduationsLines(t){let e=this.canvasWidth,i=e/(this.options.visibleHours*60*60),s=this.options.graduationMinStep/i,o=this.options.secondsPerStep.find(l=>l>s),a=o*i,u=e/a,v=this.ms_to_next_step(t,o),h=v*this.pxPerMs,r=o<60&&i*60>=50;for(let l=0;l<=u;l++){let m=t+v+l*o*1e3,d=h+l*a,c=new Date(Math.round(m)),g=10,x=1;if(c.getHours()===0&&c.getMinutes()===0&&c.getSeconds()===0){g=24,x=2;let p=this.formatDate("MM-dd",m);this.canvasCtx.textAlign="center",this.canvasCtx.fillStyle=this.options.axisStyle.tickTextColor,this.canvasCtx.font="normal normal 12px Arial,sans-serif",this.canvasCtx.fillText(p,d,34)}else if(c.getMinutes()===0&&c.getSeconds()===0){g=19,x=2;let p=this.formatDate(o<60?"hh:mm:ss":"hh:mm",m);this.canvasCtx.fillStyle=this.options.axisStyle.tickTextColor,this.canvasCtx.textAlign="center",this.canvasCtx.font="normal normal 12px Arial,sans-serif",this.canvasCtx.fillText(p,d,29)}else if(r&&c.getSeconds()===0){g=14,x=2;let p=this.formatDate("hh:mm:ss",m);this.canvasCtx.fillStyle=this.options.axisStyle.tickTextColor,this.canvasCtx.textAlign="center",this.canvasCtx.font="normal normal 12px Arial,sans-serif",this.canvasCtx.fillText(p,d,24)}this.drawLine(this.canvasCtx,{beginX:d,beginY:0,endX:d,endY:g,color:this.options.axisStyle.graduationColor,width:x,center:!0})}}drawPointer(){let t=this.pxPerMs*(this.currentTimestamp-this.options.startTime),e=this.overlayCtx;e.beginPath(),e.moveTo(t,0),e.lineTo(t,this.options.pointerOptions.endY),e.strokeStyle=this.options.pointerOptions.color,e.lineWidth=this.options.pointerOptions.width,e.stroke(),e.beginPath();let i=12/Math.sin(Math.PI/3.5);e.moveTo(t,this.options.pointerOptions.endY-1),e.lineTo(t-i/2,40),e.lineTo(t+i/2,40),e.closePath(),e.fillStyle=this.options.pointerOptions.color,e.fill()}dayStartOf(t){let e=new Date(t);return e.setHours(0,0,0,0),e.getTime()}drawOverview(){if(!this.overviewCanvas)return;let t=this.overviewCtx,e=this.canvasWidth,i=this.options.overviewHeight;t.clearRect(0,0,e,i);let s=this.options.overviewEnd-this.options.overviewStart;if(s<=0)return;let o=e/s;t.fillStyle=this.options.axisStyle.overviewBg,t.fillRect(0,0,e,i),t.strokeStyle=this.options.axisStyle.overviewTickColor,t.lineWidth=1;let a=60*60*1e3;for(let r=this.dayStartOf(this.options.overviewStart);r<=this.options.overviewEnd;r+=a){if(r<this.options.overviewStart)continue;let l=(r-this.options.overviewStart)*o;t.beginPath(),t.moveTo(l,0),t.lineTo(l,4),t.stroke()}let u=i/2-3;(this.options.segments||[]).forEach(r=>{let l=Math.max(r.begin,this.options.overviewStart),m=Math.min(r.end,this.options.overviewEnd);m<=l||(t.fillStyle=r.style&&r.style.background||this.options.segmentStyle.background,t.fillRect((l-this.options.overviewStart)*o,u,Math.max((m-l)*o,1),6))});let v=(this.options.startTime-this.options.overviewStart)*o,h=this.options.visibleHours*60*60*1e3*o;if(t.fillStyle=this.options.axisStyle.overviewWindowColor,t.fillRect(v,0,h,i),t.strokeStyle=this.options.axisStyle.overviewWindowBorder,t.strokeRect(v+.5,.5,Math.max(h-1,0),i-1),this.isClick&&this.currentTimestamp!=null){let r=(this.currentTimestamp-this.options.overviewStart)*o;r>=0&&r<=e&&this.drawLine(t,{beginX:r,beginY:0,endX:r,endY:i,color:this.options.axisStyle.overviewPlayColor,width:1,center:!0})}}ms_to_next_step(t,e){let i=new Date(t),o=(i.getHours()*3600+i.getMinutes()*60+i.getSeconds())%e;return(o?e-o:0)*1e3-i.getMilliseconds()}clampStartTime(t){if(this.options.minTime==null&&this.options.maxTime==null)return t;let e=this.options.visibleHours*60*60*1e3;return this.options.maxTime!=null&&t+e>this.options.maxTime&&(t=this.options.maxTime-e),this.options.minTime!=null&&t<this.options.minTime&&(t=this.options.minTime),t}clampTime(t){return this.options.minTime!=null&&t<this.options.minTime&&(t=this.options.minTime),this.options.maxTime!=null&&t>this.options.maxTime&&(t=this.options.maxTime),t}initEvents(){this.overlayCanvas&&(this.contextmenuHandler=t=>{t.preventDefault()},this.mousemoveHandler=this.canvasMousemoveFunc.bind(this),this.wheelHandler=this.mousewheelFunc.bind(this),this.mousedownHandler=this.mousedownFunc.bind(this),this.mouseupHandler=this.mouseupFunc.bind(this),this.mouseoutHandler=this.mouseoutFunc.bind(this),this.touchstartHandler=this.touchStartFunc.bind(this),this.touchmoveHandler=this.touchMoveFunc.bind(this),this.touchendHandler=this.touchEndFunc.bind(this),this.overlayCanvas.addEventListener("contextmenu",this.contextmenuHandler),this.overlayCanvas.addEventListener("mousemove",this.mousemoveHandler),this.overlayCanvas.addEventListener("wheel",this.wheelHandler,{passive:!1}),this.overlayCanvas.addEventListener("mousedown",this.mousedownHandler),this.overlayCanvas.addEventListener("mouseup",this.mouseupHandler),this.overlayCanvas.addEventListener("mouseout",this.mouseoutHandler),this.overlayCanvas.addEventListener("touchstart",this.touchstartHandler,{passive:!1}),this.overlayCanvas.addEventListener("touchmove",this.touchmoveHandler,{passive:!1}),this.overlayCanvas.addEventListener("touchend",this.touchendHandler))}mountOverview(){this.overviewCanvas||(this.overviewCanvas=document.createElement("canvas"),this.overviewCanvas.style.position="absolute",this.overviewCanvas.style.left="0",this.options.container.appendChild(this.overviewCanvas),this.overviewCtx=this.overviewCanvas.getContext("2d"),this.bindOverviewEvents())}bindOverviewEvents(){this.overviewCanvas&&(this.overviewMousedownHandler=this.overviewMousedownFunc.bind(this),this.overviewMousemoveHandler=()=>{this.overviewCanvas.style.cursor="pointer"},this.overviewTouchstartHandler=this.overviewTouchFunc.bind(this),this.overviewTouchmoveHandler=this.overviewTouchFunc.bind(this),this.overviewCanvas.addEventListener("mousedown",this.overviewMousedownHandler),this.overviewCanvas.addEventListener("mousemove",this.overviewMousemoveHandler),this.overviewCanvas.addEventListener("touchstart",this.overviewTouchstartHandler,{passive:!1}),this.overviewCanvas.addEventListener("touchmove",this.overviewTouchmoveHandler,{passive:!1}))}unmountOverview(){this.overviewCanvas&&(this.overviewCanvas.removeEventListener("mousedown",this.overviewMousedownHandler),this.overviewCanvas.removeEventListener("mousemove",this.overviewMousemoveHandler),this.overviewCanvas.removeEventListener("touchstart",this.overviewTouchstartHandler),this.overviewCanvas.removeEventListener("touchmove",this.overviewTouchmoveHandler),this.overviewCanvas.remove(),this.overviewCanvas=null,this.overviewCtx=null)}destroy(){this.overlayCanvas&&(this.overlayCanvas.removeEventListener("contextmenu",this.contextmenuHandler),this.overlayCanvas.removeEventListener("mousemove",this.mousemoveHandler),this.overlayCanvas.removeEventListener("wheel",this.wheelHandler),this.overlayCanvas.removeEventListener("mousedown",this.mousedownHandler),this.overlayCanvas.removeEventListener("mouseup",this.mouseupHandler),this.overlayCanvas.removeEventListener("mouseout",this.mouseoutHandler),this.overlayCanvas.removeEventListener("touchstart",this.touchstartHandler),this.overlayCanvas.removeEventListener("touchmove",this.touchmoveHandler),this.overlayCanvas.removeEventListener("touchend",this.touchendHandler),this.overlayCanvas.remove(),this.overlayCanvas=null),this.unmountOverview(),this.canvas&&(this.canvas.remove(),this.canvas=null),document.onmousemove=null,document.onmouseup=null}canDragPointer(t){let e=t.offsetX,i=t.offsetY,s=window.devicePixelRatio||1;return this.overlayCtx.isPointInPath(e*s,i*s)}setPointer(t){this.canDragPointer(t)?(this.options.container.style.cursor="pointer",this.isDragPointer=!0,this.isMoveTriangle=!0):(!this.isPressDown||this.button)&&(this.isPressDown&&this.isMoveTriangle||(this.isDragPointer=!1,this.isMoveTriangle=!1,this.options.container.style.cursor=""))}mousedownFunc(t){t.button===0?(this.isPressDown=!0,this.button=t.button,this.canDragPointer(t)?this.currentChecked="pointer":this.currentChecked="axis",document.onmousemove=e=>{this.mousemoveFunc(e)},document.onmouseup=e=>{this.mouseupFunc(e),document.onmousemove=null,document.onmouseup=null},this.isDown=!0,this.g_mousedownCursor=this.getCursorPositionX(t)):t.button}canvasMousemoveFunc(t){if(this.isPressDown)return;let e=this.getCursorPositionX(t);this.setPointer(t),this.hoverState={x:e,time:this.options.startTime+e/this.pxPerMs},this.drawOverlay()}mousemoveFunc(t){let e=this.getCursorPositionX(t);if(this.setPointer(t),this.isMove=!0,this.markUserInteract(),this.currentChecked==="axis"){let i=e-this.g_mousedownCursor;this.options.startTime=this.clampStartTime(this.options.startTime-Math.round(i/this.pxPerMs)),this.g_mousedownCursor=e,this.hoverState={x:e,time:this.options.startTime+e/this.pxPerMs},this.drawStatic()}else this.currentChecked==="pointer"&&(this.currentTimestamp=this.clampTime(this.options.startTime+e/this.pxPerMs),this.g_mousedownCursor=e,this.hoverState={x:e,time:this.currentTimestamp},this.drawOverlay())}mouseupFunc(t){if(this.isPressDown&&this.button===0)if(this.isPressDown=!1,this.isMove)this.isMove=!1,this.currentChecked==="pointer"&&(this.returnTime=this.currentTimestamp,this.returnCheckTime("drag",this.returnTime),this.drawOverlay()),this.currentChecked="";else{this.isClick=!0;let e=this.getCursorPositionX(t),i=this.clampTime(this.options.startTime+e/this.pxPerMs);this.currentTimestamp=this.returnTime=i,this.returnCheckTime("click",this.returnTime),this.drawOverlay()}}mousewheelFunc(t){t.preventDefault(),this.markUserInteract();let e=t.deltaY<0?1:-1,i=this.getCursorPositionX(t),s=this.options.startTime+i/this.pxPerMs;e<0?this.options.visibleHours=Math.min(this.options.maxVisibleHours,this.options.visibleHours*1.25):e>0&&(this.options.visibleHours=Math.max(this.options.minVisibleHours,this.options.visibleHours/1.25));let o=this.canvasWidth/(this.options.visibleHours*60*60*1e3);this.options.startTime=this.clampStartTime(s-i/o),this.drawStatic()}mouseoutFunc(t){this.hoverState=null,this.drawOverlay()}touchStartFunc(t){if(t.preventDefault(),t.touches.length===1)this.mousedownFunc(this.normalizeTouchEvent(t.touches[0]));else if(t.touches.length===2){this.isPressDown=!1,this.isMove=!1,this.currentChecked="",document.onmousemove=null,document.onmouseup=null,this.pinchStartDistance=this.getTouchDistance(t.touches),this.pinchStartVisibleHours=this.options.visibleHours;let e=this.getTouchCenterX(t.touches)-this.overlayCanvas.getBoundingClientRect().left;this.pinchCenterPosX=e,this.pinchCenterTime=this.options.startTime+e/this.pxPerMs}}touchMoveFunc(t){if(t.preventDefault(),t.touches.length===1&&this.isPressDown)this.mousemoveFunc(this.normalizeTouchEvent(t.touches[0]));else if(t.touches.length===2&&this.pinchStartDistance){this.markUserInteract();let e=this.getTouchDistance(t.touches)/this.pinchStartDistance;this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,this.pinchStartVisibleHours/(e*e)));let i=this.canvasWidth/(this.options.visibleHours*60*60*1e3);this.options.startTime=this.clampStartTime(this.pinchCenterTime-this.pinchCenterPosX/i),this.drawStatic()}}touchEndFunc(t){if(this.pinchStartDistance&&t.touches.length<2){this.pinchStartDistance=0,this.isPressDown=!1,this.isMove=!1,this.currentChecked="",document.onmousemove=null,document.onmouseup=null;return}this.isPressDown&&t.changedTouches.length&&(this.mouseupFunc(this.normalizeTouchEvent(t.changedTouches[0])),document.onmousemove=null,document.onmouseup=null)}normalizeTouchEvent(t){let e=this.overlayCanvas.getBoundingClientRect();return{button:0,pageX:t.pageX,pageY:t.pageY,clientX:t.clientX,clientY:t.clientY,offsetX:t.clientX-e.left,offsetY:t.clientY-e.top}}getTouchDistance(t){let e=t[0].clientX-t[1].clientX,i=t[0].clientY-t[1].clientY;return Math.sqrt(e*e+i*i)}getTouchCenterX(t){return(t[0].clientX+t[1].clientX)/2}overviewSeek(t){let e=this.overviewCanvas.getBoundingClientRect();if(e.width<=0)return;this.markUserInteract();let i=Math.min(e.width,Math.max(0,t-e.left)),s=this.options.overviewStart+i/e.width*(this.options.overviewEnd-this.options.overviewStart);this.options.startTime=this.clampStartTime(s-this.options.visibleHours*60*60*1e3/2),this.drawStatic()}overviewMousedownFunc(t){t.button===0&&(this.overviewSeek(t.clientX),document.onmousemove=e=>{this.overviewSeek(e.clientX)},document.onmouseup=()=>{document.onmousemove=null,document.onmouseup=null})}overviewTouchFunc(t){t.preventDefault(),t.touches.length&&this.overviewSeek(t.touches[0].clientX)}getCursorPositionX(t){let e=0;return t||(t=window.event),t.pageX||t.pageY?e=t.pageX:(t.clientX||t.clientY)&&(e=t.clientX+document.body.scrollLeft+document.documentElement.scrollLeft),e-=this.overlayCanvas.getBoundingClientRect().left,e}clearCanvas(){this.canvasCtx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}clearOverlay(){this.overlayCtx.clearRect(0,0,this.canvasWidth,this.canvasHeight)}returnCheckTime(t,e){var o,a,u,v;let i=Math.floor(e);if(this.options.segments.findIndex(h=>i>=h.begin&&i<=h.end)>=0)(a=(o=this.options).changeCallback)==null||a.call(o,{mode:t,timestamp:i,valid:!0,nextBegin:this.getNextSegment(i)});else{let h=i,r=!1,l=t;if(this.options.snapToNearest&&this.options.segments&&this.options.segments.length){let m=this.getNextSegment(i);m&&(h=Math.floor(m.begin),r=!0,l="snap",this.currentTimestamp=this.clampTime(h))}(v=(u=this.options).changeCallback)==null||v.call(u,{mode:l,timestamp:h,valid:r,nextBegin:this.getNextSegment(i)})}}formatDate(t,e){let i=e?new Date(e):new Date;t=t||"yyyy-MM-dd";const s={"M+":i.getMonth()+1,"d+":i.getDate(),"h+":i.getHours(),"m+":i.getMinutes(),"s+":i.getSeconds(),"q+":Math.floor((i.getMonth()+3)/3),S:i.getMilliseconds()};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(i.getFullYear()+"").substr(4-RegExp.$1.length)));for(const o in s)new RegExp("("+o+")").test(t)&&(t=t.replace(RegExp.$1,RegExp.$1.length==1?s[o]:("00"+s[o]).substr((""+s[o]).length)));return t}updateDatas(t){this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,t.visibleHours)),this.options.startTime=t.startTime,t.minTime!==void 0&&(this.options.minTime=t.minTime),t.maxTime!==void 0&&(this.options.maxTime=t.maxTime),t.overviewStart!=null&&(this.options.overviewStart=t.overviewStart),t.overviewEnd!=null&&(this.options.overviewEnd=t.overviewEnd),this.options.startTime=this.clampStartTime(this.options.startTime),this.options.segments=this.normalizeSegments(t.segments),!this.options.segments.some(i=>this.currentTimestamp>=i.begin&&this.currentTimestamp<=i.end)&&this.options.segments.length&&(this.currentTimestamp=this.options.segments[0].begin),this.drawStatic()}updateOptions(t){if(!t||typeof t!="object")return;const e=this.options.overview,i=["axisStyle","segments","visibleHours","startTime"];Object.keys(t).forEach(s=>{t[s]===void 0||i.includes(s)||(this.options[s]=t[s])}),t.axisStyle&&(this.options.axisStyle=Object.assign({},this.options.axisStyle,t.axisStyle)),t.segments!==void 0&&(this.options.segments=this.normalizeSegments(t.segments)),t.visibleHours!==void 0&&(this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,t.visibleHours))),t.startTime!==void 0&&(this.options.startTime=t.startTime),(t.startTime!==void 0||t.minTime!==void 0||t.maxTime!==void 0)&&(this.options.startTime=this.clampStartTime(this.options.startTime)),t.overview!==void 0&&t.overview!==e&&(this.options.overview?this.mountOverview():this.unmountOverview()),["overview","overviewHeight","overviewGap"].some(s=>t[s]!==void 0)&&this.initCanvasSize(),t.backgroundColor!==void 0&&this.canvas&&(this.canvas.style.backgroundColor=t.backgroundColor),t.segments!==void 0&&!this.options.segments.some(o=>this.currentTimestamp>=o.begin&&this.currentTimestamp<=o.end)&&this.options.segments.length&&(this.currentTimestamp=this.options.segments[0].begin),this.drawStatic()}updateTime(t){var s,o;let e=this.clampTime(t);this.currentTimestamp=e,this.returnTime=e,this.isClick=!0,this.options.centerPointer&&!this.isCenterPaused()?(this.options.startTime=this.clampStartTime(e-this.options.visibleHours*60*60*1e3/2),this.drawStatic()):this.drawOverlay();let i=(this.options.segments||[]).some(a=>e>=a.begin&&e<=a.end);(o=(s=this.options).playCallback)==null||o.call(s,{timestamp:Math.floor(e),valid:i})}markUserInteract(){this.centerPaused=!0,this.lastInteractTime=Date.now()}isCenterPaused(){return this.centerPaused?this.isPressDown||this.pinchStartDistance?!0:Date.now()-this.lastInteractTime>=this.options.centerResumeDelay?(this.centerPaused=!1,!1):!0:!1}getViewport(){return{startTime:this.options.startTime,visibleHours:this.options.visibleHours}}setViewport(t,e){e!=null&&(this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,e))),t!=null&&(this.options.startTime=this.clampStartTime(t)),this.drawStatic()}scrollTo(t){this.options.startTime=this.clampStartTime(t-this.options.visibleHours*60*60*1e3/2),this.drawStatic()}resumeCenter(){this.centerPaused=!1,this.lastInteractTime=0,this.scrollTo(this.currentTimestamp)}zoomBy(t){if(!(t>0))return;let e=this.options.startTime+this.options.visibleHours*60*60*1e3/2;this.options.visibleHours=Math.min(this.options.maxVisibleHours,Math.max(this.options.minVisibleHours,this.options.visibleHours/t)),this.options.startTime=this.clampStartTime(e-this.options.visibleHours*60*60*1e3/2),this.drawStatic()}zoomIn(){this.zoomBy(1.25)}zoomOut(){this.zoomBy(.8)}getNextSegments(t){return(this.options.segments||[]).filter(e=>e.begin>=t).sort((e,i)=>e.begin-i.begin)}getNextSegment(t){return this.getNextSegments(t)[0]||null}normalizeSegments(t){if(!Array.isArray(t))return[];let e=t.filter(s=>s&&s.end>s.begin).sort((s,o)=>s.begin-o.begin||o.end-s.end),i=[];return e.forEach(s=>{let o=i[i.length-1];if(!o||s.begin>=o.end){i.push(Object.assign({},s));return}s.end<=o.end||(o.end=s.begin,o.end>o.begin?i.push(Object.assign({},s)):i[i.length-1]=Object.assign({},s))}),i}}const y=(n,t)=>{const e=n.__vccOpts||n;for(const[i,s]of t)e[i]=s;return e},C={name:"TimeAxisPlus",props:{width:{type:[Number,String],default:"100%"},height:{type:[Number,String],default:40},startTime:{type:Number,default:()=>{const n=new Date;return n.setHours(0,0,0,0),n.getTime()}},segments:{type:Array,default:()=>[]},visibleHours:{type:Number,default:24},maxVisibleHours:{type:Number,default:24},mobileMaxVisibleHours:{type:Number,default:12},minTime:{type:Number,default:null},maxTime:{type:Number,default:null},snapToNearest:{type:Boolean,default:!1},hoverTip:{type:Boolean,default:null},centerPointer:{type:Boolean,default:!1},centerResumeDelay:{type:Number,default:3e3},overview:{type:Boolean,default:!1},overviewHeight:{type:Number,default:20},overviewStart:{type:Number,default:null},overviewEnd:{type:Number,default:null},movePlay:{type:Boolean,default:!1},clickPlay:{type:Boolean,default:!0},backgroundColor:{type:String,default:"#000"},axisStyle:{type:Object,default:()=>({})}},data(){return{axis:null,ro:null,isMobile:!1}},computed:{effectiveMaxVisibleHours(){return this.isMobile?this.mobileMaxVisibleHours:this.maxVisibleHours},effectiveHoverTip(){return this.hoverTip==null?!this.isMobile:this.hoverTip}},watch:{segments:{deep:!0,handler(){this.updateAxis()}},startTime(){this.updateAxis()},visibleHours(){this.updateAxis()},effectiveMaxVisibleHours(n){this.axis&&(this.axis.options.maxVisibleHours=n)},effectiveHoverTip(n){this.axis&&(this.axis.options.hoverTip=n)},minTime(){this.updateAxis()},maxTime(){this.updateAxis()},snapToNearest(n){this.axis&&(this.axis.options.snapToNearest=n)},centerPointer(n){this.axis&&(this.axis.options.centerPointer=n)},centerResumeDelay(n){this.axis&&(this.axis.options.centerResumeDelay=n)},axisStyle:{deep:!0,handler(n){this.axis&&(this.axis.options.axisStyle=Object.assign({},this.axis.options.axisStyle,n),this.axis.drawStatic())}},overview(n){console.log(9999887),this.axis&&this.axis.updateOptions({overview:n})},overviewStart(){this.updateAxis()},overviewEnd(){this.updateAxis()}},created(){this.isMobile=window.matchMedia("(pointer: coarse)").matches||/Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent)},mounted(){this.$nextTick(()=>{this.initTimeAxis()}),window.addEventListener("resize",this.resizeHandler),this.watchSize()},beforeUnmount(){window.removeEventListener("resize",this.resizeHandler),this.ro&&(this.ro.disconnect(),this.ro=null),this.axis&&(this.axis.destroy(),this.axis=null)},methods:{formatSize(n){return typeof n=="number"?`${n}px`:n},watchSize(){typeof ResizeObserver>"u"||(this.ro=new ResizeObserver(()=>{this.$nextTick(()=>{this.axis&&this.axis.resize()})}),this.ro.observe(this.$refs.TimelineGroup))},initTimeAxis(){this.axis=new T({container:this.$refs.TimelineGroup,backgroundColor:this.backgroundColor,width:this.width,height:this.height,startTime:this.startTime,visibleHours:this.visibleHours,maxVisibleHours:this.effectiveMaxVisibleHours,minTime:this.minTime,maxTime:this.maxTime,snapToNearest:this.snapToNearest,hoverTip:this.effectiveHoverTip,centerPointer:this.centerPointer,centerResumeDelay:this.centerResumeDelay,axisStyle:this.axisStyle,overview:this.overview,overviewHeight:this.overviewHeight,overviewStart:this.overviewStart,overviewEnd:this.overviewEnd,segmentStyle:{background:"rgba(24,208,217,0.5)"},segments:this.segments,changeCallback:n=>{this.$emit("changeTime",n)},playCallback:n=>{this.$emit("playTime",n)}}),console.log(this.axis)},updateAxis(){this.axis&&this.axis.updateDatas({visibleHours:this.visibleHours,startTime:this.startTime,segments:this.segments,minTime:this.minTime,maxTime:this.maxTime,overviewStart:this.overviewStart,overviewEnd:this.overviewEnd})},updateTime(n){this.axis.updateTime(n)},getViewport(){return this.axis?this.axis.getViewport():null},setViewport(n,t){this.axis&&this.axis.setViewport(n,t)},scrollTo(n){this.axis&&this.axis.scrollTo(n)},resumeCenter(){this.axis&&this.axis.resumeCenter()},zoomIn(){this.axis&&this.axis.zoomIn()},zoomOut(){this.axis&&this.axis.zoomOut()},getNextSegment(n){return this.axis?this.axis.getNextSegment(n):null},getNextSegments(n){return this.axis?this.axis.getNextSegments(n):[]},updateOptions(n){this.axis&&this.axis.updateOptions(n)},resizeHandler(){this.axis&&this.axis.resize()}}};function S(n,t,e,i,s,o){return w.openBlock(),w.createElementBlock("div",{class:"timeline-group",ref:"TimelineGroup",style:w.normalizeStyle({width:o.formatSize(e.width),height:o.formatSize(e.height)})},null,4)}const f=y(C,[["render",S],["__scopeId","data-v-b90b2c6f"]]);f.install=n=>{n.component(f.name,f)};exports.TimeAxisPlus=f;exports.default=f;exports.timeAxis=T;