185 lines
4.5 KiB
JavaScript
185 lines
4.5 KiB
JavaScript
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, UserPivot>} number 为当前信标在数轴中的刻度
|
||
*/
|
||
export const UserPivots = reactive(new Map());
|
||
|
||
/**
|
||
* @type {Map<number, UserPivot>} number 为 id,id 是创建的 Unix 时间戳
|
||
*/
|
||
export const Id2Pivot = reactive(new Map());
|
||
|
||
/**
|
||
* @description 应该被渲染到当前屏幕中的
|
||
* @type {Set<number>}
|
||
*/
|
||
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<number, boolean>}
|
||
*/
|
||
export const UserPivotCtxShows = reactive(new Map());
|
||
|
||
export const currentPivotId = ref(0); |