import { reactive, ref } from "vue"; import { time2cursorX, SystemPivot } from "./cursor"; import { globalLookup } from "@/hook/global"; import formatTime from "@/hook/wave-view/format-time"; import { RelativeAxis } from './relative-axis'; /** * @description 每一个动态信标 * @typedef {Object} UserPivot * @property {number} id * @property {string} label * @property {number} x * @property {number} time * @property {boolean} show */ /** * @description 该数据结构描述了所有通过 makePivot 创建的 用户信标 * @type {Map} number 为当前信标在数轴中的刻度 */ export const UserPivots = reactive(new Map()); /** * @type {Map} number 为 id,id 是创建的 Unix 时间戳 */ export const Id2Pivot = reactive(new Map()); /** * @description 应该被渲染到当前屏幕中的 * @type {Set} */ export const VisibleUserPivotIds = reactive(new Set()); export const orderedTimes = []; export const UserPivotColor = ref('#1e90ff'); /** * @description 创建一个信标 * @param {number} time 需要创建的轴的时间点 */ export function createPivot(time) { if (UserPivots.has(time)) { return; } const id = Date.now(); const x = time2cursorX(time); const timescale = globalLookup.timescale; const label = formatTime(time, timescale); const show = true; const pivot = { time, x, id, label, show }; UserPivots.set(time, pivot); Id2Pivot.set(id, pivot); orderedTimes.push(time); orderedTimes.sort((a, b) => a < b); } export function searchOrderedTimeIndex(time) { for (let i = 0; i < orderedTimes.length; ++ i) { if (orderedTimes[i] === time) { return i; } } return undefined; } export function deletePivot(time) { if (!UserPivots.has(time)) { return; } const i = searchOrderedTimeIndex(time); if (i !== undefined) { orderedTimes.splice(i, 1); } if (UserPivots.has(time)) { const pivot = UserPivots.get(time); UserPivots.delete(time); Id2Pivot.delete(pivot.id); UserPivotCtxShows.delete(pivot.id); // 如果当前的删除的信标刚好是相对坐标轴的,那么把相对坐标轴也隐藏 if (RelativeAxis.show && RelativeAxis.currentPivotId === pivot.id) { RelativeAxis.show = false; currentPivotId.value = 0; } } currentPivotId.value = 0; } export const boxShift = 25; export function updateAllPivots() { // 更新系统信标 SystemPivot.updateLeft(); // 维护可见 Pivots VisibleUserPivotIds.clear(); // 更新所有用户信标 for (const time of UserPivots.keys()) { const pivot = UserPivots.get(time); const x = time2cursorX(time); const cx = x - boxShift; // 25 是 boxShift,也就是展示数字圆形的一半宽度 if (cx > 0 && cx < (globalLookup.pstate.width || window.innerWidth)) { VisibleUserPivotIds.add(pivot.id); } pivot.x = x; } } /** * * @param {number[]} times * @param {number} target 目标时间 * @returns */ function bisearch(times, target) { let i = 0, j = times.length - 1; while (i < j) { if (times[i] === target) { break; } if (times[j] <= target) { i = j; break; } if (j - i === 1) { break; } const mid = (i + j) >> 1; if (times[mid] > target) { j = mid; } else { i = mid; } } return i; } /** * @description 高效获取距离 time 最近的时间点 t,时间复杂度 O(logn) * @param {number} time * @returns {UserPivot | undefined} */ export function getNearestUserPivot(time) { const pivotNum = UserPivots.size; if (pivotNum === 0) { return undefined; } if (pivotNum === 1) { for (const [time, pivot] of UserPivots) { return pivot; } } const i = bisearch(orderedTimes, time); // console.log(i, orderedTimes, time); if (i === pivotNum - 1) { return UserPivots.get(orderedTimes[i]); } const prevT = orderedTimes[i]; const nextT = orderedTimes[i + 1]; if (nextT - time > time - prevT) { return UserPivots.get(prevT); } return UserPivots.get(nextT); } /** * @type {Map} */ export const UserPivotCtxShows = reactive(new Map()); export const currentPivotId = ref(0);