完成信标功能
This commit is contained in:
parent
f74fc31aaf
commit
47e9e57c80
@ -1,6 +1,6 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4440655 */
|
||||
src: url('iconfont.woff2?t=1723382481292') format('woff2');
|
||||
src: url('iconfont.woff2?t=1725033317914') format('woff2');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -11,6 +11,10 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-axis:before {
|
||||
content: "\ed1f";
|
||||
}
|
||||
|
||||
.icon-add-line:before {
|
||||
content: "\e7b0";
|
||||
}
|
||||
|
Binary file not shown.
@ -2,8 +2,8 @@
|
||||
<!-- 上方的 toolbar -->
|
||||
<ToolBar></ToolBar>
|
||||
|
||||
<!-- 主渲染区 -->
|
||||
<MainRender></MainRender>
|
||||
<!-- 信标区域 -->
|
||||
<Pivot></Pivot>
|
||||
|
||||
<!-- 左上角的 sidebar,用于显示 -->
|
||||
<Sidebar></Sidebar>
|
||||
@ -27,7 +27,7 @@ import { getCrossOriginWorkerURL } from '@/hook/network';
|
||||
import ToolBar from '@/components/toolbar';
|
||||
import Sidebar from '@/components/sidebar';
|
||||
import RightNav from '@/components/right-nav.vue';
|
||||
import MainRender from '@/components/render';
|
||||
import Pivot from '@/components/pivot';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -2,30 +2,53 @@ import { globalLookup } from '@/hook/global';
|
||||
import formatTime from '@/hook/wave-view/format-time';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
export const StaticCursor = reactive({
|
||||
/**
|
||||
* @typedef {(event: MouseEvent) => void} MousemoveFn
|
||||
*/
|
||||
|
||||
export const MovingPivot = reactive({
|
||||
color: '#CB81DA',
|
||||
label: '',
|
||||
left: 0,
|
||||
currentTime: 0,
|
||||
show: true,
|
||||
|
||||
/**
|
||||
* @type {import('./pivot-view').UserPivot | undefined}
|
||||
*/
|
||||
currentTakenPivot: undefined,
|
||||
dragEnable: false
|
||||
});
|
||||
|
||||
export const SystemPivot = reactive({
|
||||
label: '',
|
||||
show: false,
|
||||
currentTime: 0,
|
||||
left: 0,
|
||||
color: '#CB81DA',
|
||||
updateLabel(timescale) {
|
||||
this.label = formatTime(this.currentTime, timescale);
|
||||
this.show = true;
|
||||
},
|
||||
updateLeft() {
|
||||
this.left = calcCursorLeft(this.currentTime);
|
||||
this.show = true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @description 左击改变系统信标的位置
|
||||
*/
|
||||
export function changeCursorLocation() {
|
||||
StaticCursor.show = true;
|
||||
if (MovingPivot.dragEnable) {
|
||||
return;
|
||||
}
|
||||
SystemPivot.show = true;
|
||||
const pstate = globalLookup.pstate;
|
||||
if (pstate) {
|
||||
const { xCursor, xOffset, xScale, tgcd, timescale } = pstate;
|
||||
const currentTime = Math.round((xCursor - xOffset) / xScale) * tgcd;
|
||||
StaticCursor.currentTime = currentTime;
|
||||
StaticCursor.updateLabel(timescale);
|
||||
StaticCursor.updateLeft();
|
||||
SystemPivot.currentTime = currentTime;
|
||||
SystemPivot.updateLabel(timescale);
|
||||
SystemPivot.updateLeft();
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +67,7 @@ export function calcCursorLeft(currentTime) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export const MovingCursor = reactive({
|
||||
|
||||
});
|
||||
/**
|
||||
* @type {Map<number, MousemoveFn>}
|
||||
*/
|
||||
export const mousemoveEventPipes = new Map();
|
@ -1,18 +1,47 @@
|
||||
<template>
|
||||
<!-- <VerticalCursor></VerticalCursor> -->
|
||||
<!-- <TimeScale></TimeScale> -->
|
||||
<div class="vcd-render-wrapper" @click="onRenderClick()">
|
||||
<VerticalCursor></VerticalCursor>
|
||||
<div
|
||||
class="vcd-render-wrapper"
|
||||
@mousedown="onRenderClick()"
|
||||
@mouseenter="onEnter()"
|
||||
:ref="el => pivotWrapper = el"
|
||||
>
|
||||
<Pivot
|
||||
v-show="SystemPivot.show"
|
||||
:color="SystemPivot.color"
|
||||
:label="SystemPivot.label"
|
||||
:x="SystemPivot.left"
|
||||
/>
|
||||
|
||||
<PivotView />
|
||||
<transition name="main-fade">
|
||||
<MovingPivotVue
|
||||
v-show="MovingPivot.show"
|
||||
/>
|
||||
</transition>
|
||||
|
||||
<transition name="collapse-from-top">
|
||||
<UserContextMenu
|
||||
v-show="pivotcontextmenu.show"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { defineComponent, reactive, ref } from 'vue';
|
||||
import { emitter, globalLookup, globalSetting } from '@/hook/global';
|
||||
import { defineComponent, onMounted, ref } from 'vue';
|
||||
import { updateWireCurrentValue } from '@/hook/utils';
|
||||
import VerticalCursor from '@/components/render/cursor.vue';
|
||||
import { changeCursorLocation } from './cursor';
|
||||
import { changeCursorLocation, SystemPivot, MovingPivot, mousemoveEventPipes } from './cursor';
|
||||
import { eventHandler, registerWheelEvent } from '@/hook/wave-view';
|
||||
|
||||
import PivotView from './pivot-view.vue';
|
||||
import Pivot from '@/components/pivot/system-pivot.vue';
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import MovingPivotVue from './moving-pivot.vue';
|
||||
import { pivotcontextmenu } from './user-context-menu';
|
||||
import UserContextMenu from './user-context-menu.vue';
|
||||
|
||||
|
||||
defineComponent({ name: 'main-render' });
|
||||
|
||||
@ -24,10 +53,34 @@ function onRenderClick() {
|
||||
changeCursorLocation();
|
||||
}
|
||||
|
||||
function onEnter() {
|
||||
MovingPivot.show = true;
|
||||
MovingPivot.currentTakenPivot = undefined;
|
||||
}
|
||||
|
||||
const pivotWrapper = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
const pivotContainer = pivotWrapper.value;
|
||||
if (pivotContainer instanceof HTMLElement) {
|
||||
pivotContainer.addEventListener('wheel',
|
||||
registerWheelEvent(null, globalLookup.pstate, globalLookup, eventHandler)
|
||||
);
|
||||
|
||||
pivotContainer.addEventListener('mousemove', event => {
|
||||
for (const pipeId of mousemoveEventPipes.keys()) {
|
||||
const fn = mousemoveEventPipes.get(pipeId);
|
||||
fn(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vcd-render-wrapper {
|
||||
user-select: none;
|
||||
height: 98vh;
|
||||
width: 98vw;
|
||||
cursor: crosshair;
|
||||
@ -81,7 +134,7 @@ function onRenderClick() {
|
||||
.vcd-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
z-index: 60;
|
||||
z-index: 80;
|
||||
}
|
||||
|
||||
.vcd-values text {
|
165
src/components/pivot/moving-pivot.vue
Normal file
165
src/components/pivot/moving-pivot.vue
Normal file
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div :ref="el => element = el">
|
||||
<div
|
||||
class="vertical-cursor-wrapper"
|
||||
:style="cursorStyle"
|
||||
>
|
||||
<div class="current-display-cursor-up">
|
||||
<div class="current-time-value" :style="colorStyle">{{ MovingPivot.label }}</div>
|
||||
<div class="cursor-down-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
<div class="vertical-line" :style="verticalLineStyle"></div>
|
||||
<div class="current-display-cursor-down">
|
||||
<div class="current-time-value" :style="colorStyle">{{ MovingPivot.label }}</div>
|
||||
<div class="cursor-up-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { emitter, globalLookup } from '@/hook/global';
|
||||
import { eventHandler, registerWheelEvent } from '@/hook/wave-view';
|
||||
import { computed, defineComponent, ref, onMounted } from 'vue';
|
||||
import { calcCursorLeft, MovingPivot } from './cursor';
|
||||
import formatTime from '@/hook/wave-view/format-time';
|
||||
import { getNearestUserPivot } from './pivot-view';
|
||||
|
||||
defineComponent({ name: 'user-pivot' });
|
||||
const element = ref(null);
|
||||
|
||||
const colorStyle = computed(() => ({
|
||||
backgroundColor: MovingPivot.color
|
||||
}));
|
||||
|
||||
const verticalLineStyle = computed(() => ({
|
||||
border: '2px dashed ' + MovingPivot.color
|
||||
}));
|
||||
|
||||
const borderStyle = computed(() => ({
|
||||
borderLeft: '5px solid ' + MovingPivot.color,
|
||||
borderTop: '5px solid ' + MovingPivot.color
|
||||
}));
|
||||
|
||||
const boxShift = 30;
|
||||
const cursorStyle = computed(() => ({
|
||||
left: MovingPivot.left - boxShift + 'px'
|
||||
}));
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
function onMousemove(event) {
|
||||
const pstate = globalLookup.pstate;
|
||||
const x = event.clientX || event.x;
|
||||
pstate.xCursor = x;
|
||||
const { xScale, xOffset, tgcd, timescale, xCursor } = pstate;
|
||||
const currentT = Math.round((xCursor - xOffset) / xScale) * tgcd;
|
||||
globalLookup.currentTime = currentT;
|
||||
MovingPivot.currentTime = currentT;
|
||||
MovingPivot.label = formatTime(currentT, timescale);
|
||||
MovingPivot.left = calcCursorLeft(currentT);
|
||||
|
||||
if (MovingPivot.currentTakenPivot !== undefined) {
|
||||
return;
|
||||
}
|
||||
// 通过计算距离最近的用户信标,来决定是否要消失,给与用户信标空间来执行额外操作
|
||||
const userPivot = getNearestUserPivot(currentT);
|
||||
|
||||
if (userPivot) {
|
||||
const marginX = Math.abs(x - userPivot.x);
|
||||
if (marginX < 25) {
|
||||
// 此时距离用户信标比较近,隐藏主信标
|
||||
MovingPivot.show = false;
|
||||
MovingPivot.currentTakenPivot = userPivot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitter.on('meta-ready', () => {
|
||||
const pivot = element.value;
|
||||
if (pivot instanceof HTMLElement) {
|
||||
document.addEventListener('mousemove', onMousemove);
|
||||
|
||||
// 添加光标初始位置
|
||||
const validWidth = globalLookup.pstate.width || window.innerWidth;
|
||||
onMousemove({ clientX: validWidth / 2 })
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vertical-cursor-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
cursor: crosshair;
|
||||
z-index: 55;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* 沿着横轴(水平方向)对齐 */
|
||||
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
|
||||
transform: translateY(var(--toolbar-height));
|
||||
}
|
||||
|
||||
.current-display-cursor-up {
|
||||
height: var(--time-scale-height);
|
||||
width: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
color: var(--sidebar-item-text);
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.current-display-cursor-down {
|
||||
height: var(--time-scale-height);
|
||||
width: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
color: var(--sidebar-item-text);
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.current-time-value {
|
||||
border-radius: .4em;
|
||||
color: var(--sidebar);
|
||||
padding: 5px;
|
||||
width: fit-content;
|
||||
font-size: 1.05rem;
|
||||
font-family: var(--vcd-value-font-family);
|
||||
white-space: nowrap;
|
||||
z-index: 60;
|
||||
}
|
||||
|
||||
.cursor-down-arrow {
|
||||
transform: rotate(225deg);
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
/* 30px - 10 * 2 / \sqrt{2} */
|
||||
left: 19.93px;
|
||||
bottom: -3px;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.vertical-line {
|
||||
height: calc(100vh - 2 * var(--time-scale-height) - 65px);
|
||||
}
|
||||
|
||||
.cursor-up-arrow {
|
||||
transform: rotate(45deg);
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
left: 19.93px;
|
||||
top: -3px;
|
||||
z-index: 50;
|
||||
}
|
||||
</style>
|
138
src/components/pivot/pivot-view.js
Normal file
138
src/components/pivot/pivot-view.js
Normal file
@ -0,0 +1,138 @@
|
||||
import { reactive, ref } from "vue";
|
||||
import { calcCursorLeft, SystemPivot } from "./cursor";
|
||||
import { globalLookup } from "@/hook/global";
|
||||
import formatTime from "@/hook/wave-view/format-time";
|
||||
|
||||
/**
|
||||
* @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>}
|
||||
*/
|
||||
export const UserPivots = reactive(new Map());
|
||||
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 = calcCursorLeft(time);
|
||||
const timescale = globalLookup.timescale;
|
||||
const label = formatTime(time, timescale);
|
||||
const show = true;
|
||||
|
||||
UserPivots.set(time, { time, x, id, label, show });
|
||||
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;
|
||||
}
|
||||
|
||||
UserPivots.delete(time);
|
||||
const i = searchOrderedTimeIndex(time);
|
||||
if (i !== undefined) {
|
||||
orderedTimes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export function updateAllPivots() {
|
||||
// 更新系统信标
|
||||
SystemPivot.updateLeft();
|
||||
|
||||
// 更新所有用户信标
|
||||
for (const time of UserPivots.keys()) {
|
||||
const pivot = UserPivots.get(time);
|
||||
pivot.x = calcCursorLeft(time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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);
|
||||
}
|
27
src/components/pivot/pivot-view.vue
Normal file
27
src/components/pivot/pivot-view.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div
|
||||
v-for="(pivot, index) in UserPivots"
|
||||
:key="pivot[1].id"
|
||||
>
|
||||
<UserPivot
|
||||
v-show="pivot[1].show"
|
||||
:color="UserPivotColor"
|
||||
:label="pivot[1].label"
|
||||
:x="pivot[1].x"
|
||||
:time="pivot[1].time"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* @description 该模块为创建新的信标采用的视图,可以看 makePivot 这个函数
|
||||
*/
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import { UserPivotColor, UserPivots } from './pivot-view';
|
||||
import UserPivot from './user-pivot.vue';
|
||||
|
||||
defineComponent({ name: 'pivot-view' });
|
||||
|
||||
</script>
|
@ -1,48 +1,65 @@
|
||||
<template>
|
||||
<div v-show="StaticCursor.show">
|
||||
<div class="vertical-cursor-wrapper"
|
||||
<div v-if="renderPivot">
|
||||
<div
|
||||
class="vertical-cursor-wrapper"
|
||||
:style="cursorStyle"
|
||||
>
|
||||
<div class="current-display-cursor-up">
|
||||
<div class="current-time-value" :style="colorStyle">{{ StaticCursor.label }}</div>
|
||||
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
|
||||
<div class="cursor-down-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
<div class="vertical-line" :style="colorStyle"></div>
|
||||
<div class="current-display-cursor-down">
|
||||
<div class="current-time-value" :style="colorStyle">{{ StaticCursor.label }}</div>
|
||||
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
|
||||
<div class="cursor-up-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { StaticCursor } from './cursor';
|
||||
|
||||
defineComponent({ name: 'vertical-cursor' });
|
||||
defineComponent({ name: 'system-pivot' });
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: 'var(--main-color)'
|
||||
},
|
||||
label: {
|
||||
type: String
|
||||
},
|
||||
x: {
|
||||
type: Number
|
||||
}
|
||||
});
|
||||
|
||||
const colorStyle = {
|
||||
const colorStyle = computed(() => ({
|
||||
backgroundColor: props.color
|
||||
};
|
||||
}));
|
||||
|
||||
const borderStyle = {
|
||||
const borderStyle = computed(() => ({
|
||||
borderLeft: '5px solid ' + props.color,
|
||||
borderTop: '5px solid ' + props.color
|
||||
};
|
||||
}));
|
||||
|
||||
const boxShift = 25;
|
||||
const cursorStyle = computed(() => ({
|
||||
left: StaticCursor.left - boxShift + 'px'
|
||||
left: props.x - boxShift + 'px'
|
||||
}));
|
||||
|
||||
const renderPivot = computed(() => {
|
||||
const x = props.x - boxShift;
|
||||
if (x > 0 && x < (globalLookup.pstate.width || window.innerWidth)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -50,12 +67,11 @@ const cursorStyle = computed(() => ({
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
cursor: crosshair;
|
||||
z-index: 55;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* 沿着横轴(水平方向)对齐 */
|
||||
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translateY(var(--toolbar-height));
|
||||
}
|
||||
|
||||
@ -86,6 +102,7 @@ const cursorStyle = computed(() => ({
|
||||
color: var(--sidebar-item-text);
|
||||
padding: 5px;
|
||||
width: fit-content;
|
||||
font-family: var(--vcd-value-font-family);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
17
src/components/pivot/user-context-menu.js
Normal file
17
src/components/pivot/user-context-menu.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { reactive } from "vue";
|
||||
import { getNearestUserPivot } from "./pivot-view";
|
||||
import { globalLookup } from "@/hook/global";
|
||||
|
||||
|
||||
export const pivotcontextmenu = reactive({
|
||||
show: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
|
||||
export function handleUserContextMenu(event) {
|
||||
const x = event.x;
|
||||
pivotcontextmenu.x = event.x;
|
||||
pivotcontextmenu.y = event.y;
|
||||
pivotcontextmenu.show = true;
|
||||
}
|
76
src/components/pivot/user-context-menu.vue
Normal file
76
src/components/pivot/user-context-menu.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div
|
||||
class="user-context-menu"
|
||||
:style="contextStyle"
|
||||
>
|
||||
<div class="menu-container">
|
||||
<div
|
||||
class="menu-item-container"
|
||||
@click="deleteUserPivot()"
|
||||
>
|
||||
<span class="menu-item-icon iconfont icon-delete"></span>
|
||||
<span class="menu-item-name">{{ t('pivot.context.delete') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="menu-item-container"
|
||||
@click="displayRelativeAxis()"
|
||||
>
|
||||
<span class="menu-item-icon iconfont icon-axis"></span>
|
||||
<span class="menu-item-name">{{ t('pivot.context.display-axis') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { MovingPivot } from './cursor';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { pivotcontextmenu } from './user-context-menu';
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import { getNearestUserPivot, orderedTimes, searchOrderedTimeIndex, UserPivots } from './pivot-view';
|
||||
|
||||
defineComponent({ name: 'user-context-menu' });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const contextStyle = computed(() => ({
|
||||
top: pivotcontextmenu.y + ' px',
|
||||
left: pivotcontextmenu.x + 20 + 'px'
|
||||
}));
|
||||
|
||||
function deleteUserPivot() {
|
||||
const x = pivotcontextmenu.x;
|
||||
const pstate = globalLookup.pstate;
|
||||
if (pstate) {
|
||||
const { xOffset, xScale, tgcd } = pstate;
|
||||
const currentTime = Math.round((x - xOffset) / xScale) * tgcd;
|
||||
const pivot = getNearestUserPivot(currentTime);
|
||||
if (pivot) {
|
||||
const i = searchOrderedTimeIndex(pivot.time);
|
||||
orderedTimes.splice(i, 1);
|
||||
UserPivots.delete(pivot.time);
|
||||
pivotcontextmenu.show = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function displayRelativeAxis() {
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.user-context-menu {
|
||||
z-index: 200;
|
||||
border-radius: .5em;
|
||||
padding: 10px;
|
||||
position: fixed;
|
||||
box-shadow: 0 0 10px 1px rgb(16, 16, 16);
|
||||
background-color: var(--sidebar);
|
||||
border: solid 1px var(--sidebar-border);
|
||||
}
|
||||
|
||||
</style>
|
232
src/components/pivot/user-pivot.vue
Normal file
232
src/components/pivot/user-pivot.vue
Normal file
@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="renderPivot"
|
||||
@mouseenter="onEnter()"
|
||||
@mouseleave="onLeave()"
|
||||
@contextmenu.prevent="handleUserContextMenu($event)"
|
||||
class="user-pivot"
|
||||
>
|
||||
<div
|
||||
class="vertical-cursor-wrapper"
|
||||
:style="cursorStyle"
|
||||
>
|
||||
<div class="current-display-cursor-up">
|
||||
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
|
||||
<div class="cursor-down-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
<div
|
||||
class="vertical-line"
|
||||
:style="colorStyle"
|
||||
:ref="el => vline.element = el"
|
||||
@mousedown.stop="onVLineMousedown()"
|
||||
@mouseup.stop="onVLineMouseup()"
|
||||
></div>
|
||||
<div class="current-display-cursor-down">
|
||||
<div class="current-time-value" :style="colorStyle">{{ props.label }}</div>
|
||||
<div class="cursor-up-arrow" :style="borderStyle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import { eventHandler, registerWheelEvent } from '@/hook/wave-view';
|
||||
import { computed, defineComponent, ref, onMounted, reactive, nextTick } from 'vue';
|
||||
import { calcCursorLeft, mousemoveEventPipes, MovingPivot } from './cursor';
|
||||
import { orderedTimes, searchOrderedTimeIndex, UserPivots } from './pivot-view';
|
||||
import formatTime from '@/hook/wave-view/format-time';
|
||||
import { handleUserContextMenu } from './user-context-menu';
|
||||
|
||||
defineComponent({ name: 'user-pivot' });
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: String,
|
||||
default: 'var(--main-color)'
|
||||
},
|
||||
label: {
|
||||
type: String
|
||||
},
|
||||
x: {
|
||||
type: Number
|
||||
},
|
||||
time: {
|
||||
type: Number
|
||||
}
|
||||
});
|
||||
|
||||
const colorStyle = computed(() => ({
|
||||
backgroundColor: props.color
|
||||
}));
|
||||
|
||||
const borderStyle = computed(() => ({
|
||||
borderLeft: '5px solid ' + props.color,
|
||||
borderTop: '5px solid ' + props.color
|
||||
}));
|
||||
|
||||
const boxShift = 25;
|
||||
const cursorStyle = computed(() => ({
|
||||
left: props.x - boxShift + 'px'
|
||||
}));
|
||||
|
||||
const renderPivot = computed(() => {
|
||||
const x = props.x - boxShift;
|
||||
if (x > 0 && x < (globalLookup.pstate.width || window.innerWidth)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
|
||||
|
||||
function onEnter() {
|
||||
}
|
||||
|
||||
function onLeave() {
|
||||
MovingPivot.show = true;
|
||||
MovingPivot.currentTakenPivot = undefined;
|
||||
}
|
||||
|
||||
const vline = reactive({
|
||||
dragEnable: false,
|
||||
element: undefined,
|
||||
originTime: 0
|
||||
});
|
||||
|
||||
|
||||
function onVLineMousedown() {
|
||||
const div = vline.element;
|
||||
if (!(div instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vline.dragEnable = true;
|
||||
MovingPivot.dragEnable = true;
|
||||
|
||||
vline.originTime = props.time;
|
||||
const pivot = UserPivots.get(vline.originTime);
|
||||
if (pivot === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先从 orderTimes 里面拿走
|
||||
const i = searchOrderedTimeIndex(vline.originTime);
|
||||
if (i !== undefined) {
|
||||
orderedTimes.splice(i, 1);
|
||||
}
|
||||
|
||||
// 开启拖拽
|
||||
console.log('begin to drag');
|
||||
|
||||
mousemoveEventPipes.set(pivot.id, event => {
|
||||
const x = event.clientX || event.x;
|
||||
pivot.x = x;
|
||||
const pstate = globalLookup.pstate;
|
||||
if (pstate) {
|
||||
const { xOffset, xScale, tgcd, timescale } = pstate;
|
||||
const t = Math.round((x - xOffset) / xScale) * tgcd;
|
||||
pivot.time = t;
|
||||
pivot.label = formatTime(t, timescale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onVLineMouseup() {
|
||||
const div = vline.element;
|
||||
if (!(div instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
const pivot = UserPivots.get(vline.originTime);
|
||||
|
||||
if (pivot) {
|
||||
mousemoveEventPipes.delete(pivot.id);
|
||||
UserPivots.delete(vline.originTime);
|
||||
UserPivots.set(pivot.time, pivot);
|
||||
orderedTimes.push(pivot.time);
|
||||
orderedTimes.sort((a, b) => a < b);
|
||||
}
|
||||
|
||||
vline.originTime = 0;
|
||||
vline.dragEnable = false;
|
||||
MovingPivot.currentTakenPivot = pivot;
|
||||
MovingPivot.show = false;
|
||||
MovingPivot.dragEnable = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.user-pivot {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vertical-cursor-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
z-index: 55;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; /* 沿着横轴(水平方向)对齐 */
|
||||
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
|
||||
transform: translateY(var(--toolbar-height));
|
||||
}
|
||||
|
||||
.current-display-cursor-up {
|
||||
height: var(--time-scale-height);
|
||||
width: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
color: var(--sidebar-item-text);
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.current-display-cursor-down {
|
||||
height: var(--time-scale-height);
|
||||
width: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
color: var(--sidebar-item-text);
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.current-time-value {
|
||||
border-radius: .4em;
|
||||
color: var(--sidebar-item-text);
|
||||
padding: 5px;
|
||||
width: fit-content;
|
||||
font-family: var(--vcd-value-font-family);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cursor-down-arrow {
|
||||
transform: rotate(225deg);
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
/* 25px - 10 * 2 / \sqrt{2} */
|
||||
left: 17.93px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.vertical-line {
|
||||
cursor: ew-resize;
|
||||
width: 2px;
|
||||
height: calc(100vh - 2 * var(--time-scale-height) - 60px);
|
||||
}
|
||||
|
||||
.cursor-up-arrow {
|
||||
transform: rotate(45deg);
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
left: 17.93px;
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
@ -1,135 +0,0 @@
|
||||
<template>
|
||||
<div class="time-scale-up-wrapper">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="time-scale-wrapper" :style="`left: ${currentX}px; width: ${300}px;`">
|
||||
<div class="current-display-cursor-up">
|
||||
<div class="time-scale-value">{{ currentX }} {{ timeScaleManage.unit }}</div>
|
||||
<div class="time-scale-down"></div>
|
||||
</div>
|
||||
<div class="time-scale-line"></div>
|
||||
<div class="current-display-cursor-down">
|
||||
<div class="time-scale-value">{{ currentX }} {{ timeScaleManage.unit }}</div>
|
||||
<div class="time-scale-up"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="time-scale-down-wrapper">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive } from 'vue';
|
||||
import { globalLookup, emitter } from '@/hook/global';
|
||||
import { wheelScale } from '@/hook/wheel';
|
||||
|
||||
export default {
|
||||
name: 'time-scale',
|
||||
|
||||
setup() {
|
||||
// see --sidebar-width
|
||||
const left = 280 + 20;
|
||||
|
||||
// see --right-nav-width
|
||||
const right = document.body.clientWidth - 60;
|
||||
|
||||
const timeScaleManage = reactive({
|
||||
scale: 1,
|
||||
unit: 'ns'
|
||||
});
|
||||
|
||||
// 此时有关波形的元信息已经加载完毕
|
||||
emitter.on('meta-ready', () => {
|
||||
});
|
||||
|
||||
// document.addEventListener('wheel', event => {
|
||||
// if ((event.wheelDelta && event.ctrlKey) || event.detail) {
|
||||
// event.preventDefault();
|
||||
// }
|
||||
|
||||
// if (event.ctrlKey) {
|
||||
// // console.log(event.wheelDelta);
|
||||
// wheelScale(event);
|
||||
// } else if (event.shiftKey) {
|
||||
// // console.log(event.wheelDelta);
|
||||
// console.log('deltaX', event.deltaX);
|
||||
// console.log('deltaY', event.deltaY);
|
||||
// }
|
||||
// }, { capture: false, passive: false });
|
||||
|
||||
|
||||
const currentX = 300;
|
||||
|
||||
return {
|
||||
currentX,
|
||||
timeScaleManage
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.time-scale-up-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--sidebar-width) + 20px);
|
||||
width: calc(100vw - var(--sidebar-width) - var(--right-nav-width) - 20px);
|
||||
height: var(--time-scale-height);
|
||||
background-color: var(--sidebar);
|
||||
z-index: 50;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.time-scale-down-wrapper {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: calc(100vw - var(--right-nav-width));
|
||||
height: var(--time-scale-height);
|
||||
background-color: var(--sidebar);
|
||||
z-index: 50;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.time-scale-down {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
height: 10px;
|
||||
border: 1px solid var(--scrollbar-hover);
|
||||
background-color: var(--scrollbar-hover);
|
||||
}
|
||||
|
||||
.time-scale-up {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
height: 10px;
|
||||
border: 1px solid var(--scrollbar-hover);
|
||||
background-color: var(--scrollbar-hover);
|
||||
}
|
||||
|
||||
.time-scale-wrapper {
|
||||
position: absolute;
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
cursor: crosshair;
|
||||
z-index: 55;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
/* 沿着横轴(水平方向)对齐 */
|
||||
justify-content: center;
|
||||
/* 沿着纵轴(垂直方向)对齐 */
|
||||
}
|
||||
|
||||
|
||||
.time-scale-line {
|
||||
width: 1px;
|
||||
background-color: var(--scrollbar-hover);
|
||||
height: calc(100vh - 2 * var(--time-scale-height));
|
||||
}
|
||||
</style>
|
@ -10,6 +10,7 @@
|
||||
name="language-setting"
|
||||
class="language-setting"
|
||||
v-model="locale"
|
||||
@change="onlanguagechange"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in languageSetting.options"
|
||||
@ -19,6 +20,22 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="languageDialogShow"
|
||||
class="language-dialog"
|
||||
:title="t('tips')"
|
||||
width="500"
|
||||
>
|
||||
<span>{{ t('setting.language.change-dialog') }}</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="confirmLanguageDialog()">
|
||||
{{ t('confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<br>
|
||||
<!-- <div class="setting-option">
|
||||
@ -98,14 +115,14 @@
|
||||
<span class="option-title" style="width: 100px;">{{ t('wavecolor') }}</span>
|
||||
<div style="width: 120px">
|
||||
<el-select
|
||||
v-model="wavecolor.currentOptionIndex"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="Select"
|
||||
>
|
||||
<el-option v-for="option in wavecolor.options" :key="option.value"
|
||||
:label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
v-model="wavecolor.currentOptionIndex"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="Select"
|
||||
>
|
||||
<el-option v-for="option in wavecolor.options" :key="option.value"
|
||||
:label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div style="height: 20px; width: 20px;"></div>
|
||||
<el-color-picker
|
||||
@ -115,6 +132,30 @@
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="setting-option">
|
||||
<span class="option-title" style="width: 100px;">{{ t('setting.appearance.pivot-color') }}</span>
|
||||
<div style="width: 120px">
|
||||
<el-select
|
||||
v-model="pivotColor.currentOptionIndex"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="Select"
|
||||
>
|
||||
<el-option v-for="option in pivotColor.options" :key="option.value"
|
||||
:label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div style="height: 20px; width: 20px;"></div>
|
||||
<el-color-picker
|
||||
v-model="pivotColor.colors[pivotColor.currentOptionIndex]"
|
||||
show-alpha
|
||||
:predefine="predefinedColors"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
@ -159,13 +200,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, defineComponent, watch } from 'vue';
|
||||
import { reactive, defineComponent, watch, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { globalSetting, globalLookup } from '@/hook/global';
|
||||
import { debounceWrapper, scopes, variables, predefinedColors, webglColor2rgba, rgba2WebglColor } from '@/hook/utils';
|
||||
import { gl_Colors } from '@/hook/wave-view/render-utils';
|
||||
|
||||
import HelpIcon from '../help-icon.vue';
|
||||
import { UserPivotColor } from '../pivot/pivot-view';
|
||||
import { MovingPivot, SystemPivot } from '../pivot/cursor';
|
||||
|
||||
defineComponent({ name: "dide-setting" });
|
||||
|
||||
@ -180,6 +222,16 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
const languageDialogShow = ref(false);
|
||||
|
||||
function confirmLanguageDialog() {
|
||||
languageDialogShow.value = false;
|
||||
}
|
||||
|
||||
function onlanguagechange() {
|
||||
languageDialogShow.value = true;
|
||||
}
|
||||
|
||||
const wavecolor = reactive({
|
||||
options: [
|
||||
{
|
||||
@ -210,10 +262,31 @@ const wavecolor = reactive({
|
||||
reset() {}
|
||||
});
|
||||
|
||||
watch(() => wavecolor.currentOptionIndex, () => {
|
||||
console.log(wavecolor.currentOptionIndex);
|
||||
const pivotColor = reactive({
|
||||
options: [
|
||||
{
|
||||
value: 0,
|
||||
label: t('setting.appearance.moving-pivot')
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: t('setting.appearance.user-pivot')
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: t('setting.appearance.system-pivot')
|
||||
}
|
||||
],
|
||||
currentOptionIndex: 0,
|
||||
colors: [
|
||||
MovingPivot.color,
|
||||
UserPivotColor.value,
|
||||
SystemPivot.color
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 更新默认波形颜色
|
||||
watch(() => wavecolor.colors, () => {
|
||||
const colorString = wavecolor.colors[wavecolor.currentOptionIndex];
|
||||
@ -231,6 +304,23 @@ watch(() => wavecolor.colors, () => {
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 更新信标颜色
|
||||
watch(() => pivotColor.colors, () => {
|
||||
const colorString = pivotColor.colors[pivotColor.currentOptionIndex];
|
||||
switch (pivotColor.currentOptionIndex) {
|
||||
case 0:
|
||||
MovingPivot.color = colorString;
|
||||
break;
|
||||
case 1:
|
||||
UserPivotColor.value = colorString;
|
||||
break;
|
||||
case 2:
|
||||
SystemPivot.color = colorString;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
const languageSetting = reactive({
|
||||
options: [
|
||||
@ -252,6 +342,9 @@ function modifySignalTrackHeight() {
|
||||
}
|
||||
|
||||
const safeModifySignalTrackHeight = debounceWrapper(modifySignalTrackHeight, 200);
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -313,4 +406,14 @@ const safeModifySignalTrackHeight = debounceWrapper(modifySignalTrackHeight, 200
|
||||
transition: var(--animation-3s);
|
||||
-webkit-transition: var(--animation-3s);
|
||||
}
|
||||
|
||||
.language-dialog {
|
||||
color: var(--sidebar-item-text);
|
||||
background-color: var(--sidebar) !important;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
color: var(--sidebar-item-text) !important;
|
||||
}
|
||||
|
||||
</style>
|
@ -220,8 +220,4 @@ function makeSignalIconClass(signal) {
|
||||
box-shadow: 0 0 10px 1px rgb(16, 16, 16);
|
||||
}
|
||||
|
||||
.el-color-picker__panel button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,7 +1,8 @@
|
||||
import { globalLookup } from "@/hook/global";
|
||||
import { calcCursorLeft, StaticCursor } from "../render/cursor";
|
||||
import { calcCursorLeft, SystemPivot } from "../pivot/cursor";
|
||||
import { sidebarSelectedWires } from "@/hook/sidebar-select-wire";
|
||||
import { updateWireCurrentValue } from "@/hook/utils";
|
||||
import { createPivot } from "../pivot/pivot-view";
|
||||
|
||||
|
||||
/**
|
||||
@ -11,8 +12,8 @@ import { updateWireCurrentValue } from "@/hook/utils";
|
||||
* @param {Pstate} pstate
|
||||
*/
|
||||
export function moveto(time, leftMargin, pstate) {
|
||||
StaticCursor.show = true;
|
||||
StaticCursor.currentTime = time;
|
||||
SystemPivot.show = true;
|
||||
SystemPivot.currentTime = time;
|
||||
|
||||
const { width, xOffset, xScale, tgcd, timescale } = pstate;
|
||||
let nextOffsetX = leftMargin - (time / tgcd) * xScale;
|
||||
@ -26,8 +27,8 @@ export function moveto(time, leftMargin, pstate) {
|
||||
pstate.xOffset = nextOffsetX;
|
||||
|
||||
// 改变静态信标
|
||||
StaticCursor.updateLeft();
|
||||
StaticCursor.updateLabel(pstate.timescale);
|
||||
SystemPivot.updateLeft();
|
||||
SystemPivot.updateLabel(pstate.timescale);
|
||||
|
||||
// 更新所有轨道的数字
|
||||
updateWireCurrentValue(time);
|
||||
@ -76,7 +77,7 @@ export function toPrevChange() {
|
||||
if (wave.length === 1) {
|
||||
toBegin();
|
||||
} else {
|
||||
const currentT = StaticCursor.currentTime;
|
||||
const currentT = SystemPivot.currentTime;
|
||||
let pivot = bisearch(wave, currentT);
|
||||
|
||||
const pwave = wave[pivot];
|
||||
@ -109,7 +110,7 @@ export function toNextChange() {
|
||||
if (wave.length === 1) {
|
||||
toEnd();
|
||||
} else {
|
||||
const currentT = StaticCursor.currentTime;
|
||||
const currentT = SystemPivot.currentTime;
|
||||
let pivot = bisearch(wave, currentT);
|
||||
let targetT;
|
||||
if (pivot === wave.length - 1) {
|
||||
@ -135,10 +136,10 @@ const locationManager = {
|
||||
};
|
||||
|
||||
|
||||
export function makeLocation() {
|
||||
const currentT = StaticCursor.currentTime;
|
||||
export function makePivot() {
|
||||
const currentT = SystemPivot.currentTime;
|
||||
// 在 currentT 创建新的信标
|
||||
|
||||
createPivot(currentT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,6 +64,8 @@
|
||||
>
|
||||
<div
|
||||
class="item iconfont icon-add-line"
|
||||
:class="{ 'disable' : !SystemPivot.show }"
|
||||
@click="makePivot()"
|
||||
/>
|
||||
</el-tooltip>
|
||||
|
||||
@ -73,8 +75,9 @@
|
||||
<script setup>
|
||||
import { defineComponent } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toBegin, toEnd, toNextChange, toPrevChange } from './cursor-location';
|
||||
import { makePivot, toBegin, toEnd, toNextChange, toPrevChange } from './cursor-location';
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import { SystemPivot } from '../pivot/cursor';
|
||||
|
||||
defineComponent({ name: 'cursor-location' });
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -13,7 +13,7 @@ import { globalLookup } from "@/hook/global";
|
||||
import { sidebarSelectedWires } from "@/hook/sidebar-select-wire";
|
||||
import { reactive, ref } from "vue";
|
||||
import { bisearch, moveto } from "./cursor-location";
|
||||
import { StaticCursor } from "../render/cursor";
|
||||
import { SystemPivot } from "../pivot/cursor";
|
||||
import { FormatValueRender, JSValueRender } from "@/hook/wave-view/toolbar/renderFormat";
|
||||
import { ElMessage } from "element-plus";
|
||||
import i18n from '@/i18n/index';
|
||||
@ -49,9 +49,9 @@ function toPrevValue() {
|
||||
// TODO: 空间换时间,提升性能
|
||||
const prevTimes = [];
|
||||
|
||||
const currentT = StaticCursor.currentTime;
|
||||
// StaticCursor.updateLabel(currentT);
|
||||
// StaticCursor.updateLeft();
|
||||
const currentT = SystemPivot.currentTime;
|
||||
// SystemPivot.updateLabel(currentT);
|
||||
// SystemPivot.updateLeft();
|
||||
|
||||
const searchContent = toolbarValueSearch.content.trim();
|
||||
|
||||
@ -93,9 +93,9 @@ function toPrevValue() {
|
||||
function toNextValue() {
|
||||
const prevTimes = [];
|
||||
|
||||
const currentT = StaticCursor.currentTime;
|
||||
// StaticCursor.updateLabel(currentT);
|
||||
// StaticCursor.updateLeft();
|
||||
const currentT = SystemPivot.currentTime;
|
||||
// SystemPivot.updateLabel(currentT);
|
||||
// SystemPivot.updateLeft();
|
||||
|
||||
const searchContent = toolbarValueSearch.content.trim();
|
||||
|
||||
|
@ -47,6 +47,14 @@ export const sidebarSelectedWires = {
|
||||
|
||||
clear() {
|
||||
this.lastLink = undefined;
|
||||
for (const link of globalLookup.sidebarSelectedWireLinks) {
|
||||
globalLookup.setRenderOption(link, 'highlight', 0);
|
||||
}
|
||||
|
||||
if (globalLookup.sidebarSelectedWireLinks.size > 0) {
|
||||
globalLookup.render({ type: 'wave-only' });
|
||||
}
|
||||
|
||||
globalLookup.sidebarSelectedWireLinks.clear();
|
||||
this.togglePipe();
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { globalLookup } from '../global';
|
||||
import WebGL2WaveRender from './render-wave';
|
||||
|
||||
import renderCursor from './render-cursor';
|
||||
import genResizeHandler from './gen-resize-handler';
|
||||
import mTree from './mount-tree';
|
||||
|
||||
@ -15,29 +14,6 @@ const setTime = (pstate, str) => {
|
||||
}
|
||||
};
|
||||
|
||||
const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
|
||||
// 这是上面展示当前 time 的圆角矩形框框的宽度
|
||||
const xmargin = 160;
|
||||
// 这是上面展示当前 time 的圆角矩形内的字体大小
|
||||
const fontHeight = 20;
|
||||
const fontWidth = fontHeight / 2;
|
||||
const sidebarWidth = pstate.sidebarWidth;
|
||||
|
||||
const handler = event => {
|
||||
const x = pstate.xCursor = event.clientX;
|
||||
const left = x - xmargin;
|
||||
// 不能进入左侧,也不能进入右侧
|
||||
if (left > sidebarWidth - 195) {
|
||||
cursor.style.left = (x - xmargin) + 'px';
|
||||
cursor.innerHTML = renderCursor({ xmargin, fontWidth, fontHeight }, pstate);
|
||||
}
|
||||
};
|
||||
// 添加初始鼠标位置
|
||||
handler({ clientX: pstate.width / 2 });
|
||||
document.addEventListener('mousemove', handler);
|
||||
};
|
||||
|
||||
|
||||
const getFullView = desc => {
|
||||
// console.log(desc);
|
||||
if (desc.waveql) {
|
||||
@ -100,7 +76,6 @@ class DomContainer {
|
||||
const elementInfos = this.elementInfos;
|
||||
for (const elName of Reflect.ownKeys(elementInfos)) {
|
||||
const elementInfo = elementInfos[elName];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,7 +176,6 @@ const domContainer = (obj) => {
|
||||
resizeObserver.observe(document.body);
|
||||
|
||||
resizeHandler(elo.container.clientWidth, elo.container.clientHeight);
|
||||
mouseMoveHandler(elo.cursor, elo.container, pstate, deso.render);
|
||||
deso.render();
|
||||
}
|
||||
};
|
||||
|
@ -1,59 +0,0 @@
|
||||
import genSVG from 'onml/gen-svg.js';
|
||||
import stringify from 'onml/stringify.js';
|
||||
|
||||
import formatTime from './format-time';
|
||||
import { globalLookup } from '../global';
|
||||
|
||||
const renderCursor = (cfg, pstate) => {
|
||||
const { xmargin, fontWidth, fontHeight } = cfg;
|
||||
const { height, xScale, xOffset, tgcd, timescale, xCursor } = pstate;
|
||||
|
||||
const xx = Math.round((xCursor - xOffset) / xScale) * tgcd;
|
||||
globalLookup.currentTime = xx;
|
||||
const label = formatTime(xx, timescale);
|
||||
const lWidth = (label.length + 1) * fontWidth;
|
||||
|
||||
const body = [
|
||||
// vertical line
|
||||
['line', {
|
||||
class: 'wd-cursor-line',
|
||||
x1: xmargin + 0.5,
|
||||
x2: xmargin + 0.5,
|
||||
y1: 0,
|
||||
y2: height
|
||||
}],
|
||||
// top time label
|
||||
['rect', {
|
||||
class: 'wd-cursor-time',
|
||||
x: xmargin - lWidth / 2,
|
||||
y: 0,
|
||||
rx: 9,
|
||||
ry: 9,
|
||||
width: lWidth,
|
||||
height: fontHeight * 1.25
|
||||
}],
|
||||
['text', {
|
||||
class: 'wd-cursor-time',
|
||||
x: xmargin,
|
||||
y: fontHeight
|
||||
}, label],
|
||||
// bottom time label
|
||||
['rect', {
|
||||
class: 'wd-cursor-time',
|
||||
x: xmargin - lWidth / 2,
|
||||
y: height - fontHeight * 1.25,
|
||||
rx: 9,
|
||||
ry: 9,
|
||||
width: lWidth,
|
||||
height: fontHeight * 1.25
|
||||
}],
|
||||
['text', {
|
||||
class: 'wd-cursor-time',
|
||||
x: xmargin,
|
||||
y: height - fontHeight * .25
|
||||
}, label]
|
||||
];
|
||||
return stringify(genSVG(2 * xmargin, height).concat(body));
|
||||
};
|
||||
|
||||
export default renderCursor;
|
@ -3,7 +3,7 @@ import { globalLookup, globalSetting, globalStyle } from '../global';
|
||||
import { gl_Colors, gl_Shifts, gl_Shifts_for_bar, gl_WidthShifts, barShift, getRatio, screenHeightPixel, maskColorIndexOffset, posYFactor, glslInputLength, prettyPrint, ladderAnalog_GL_WidthShifts, lineAnlog_GL_WidthShifts } from './render-utils.js';
|
||||
import { vertexShader, fragmentShader } from './render-shader.js';
|
||||
import { renderAsBit, renderAsCommonDigital, renderAsLadderAnalog, renderAsLineAnalog } from './toolbar/renderModal';
|
||||
import { StaticCursor } from '@/components/render/cursor';
|
||||
import { updateAllPivots } from '@/components/pivot/pivot-view';
|
||||
|
||||
/**
|
||||
* @description
|
||||
@ -404,7 +404,7 @@ class WebGL2WaveRender {
|
||||
}
|
||||
|
||||
// 更新静态 cursor
|
||||
StaticCursor.updateLeft();
|
||||
updateAllPivots();
|
||||
|
||||
function linearAnimation(delta, oldVal, newVal) {
|
||||
return (1 - delta) * oldVal + delta * newVal;
|
||||
|
@ -9,6 +9,9 @@
|
||||
* @param {WheelEvent} event
|
||||
*/
|
||||
function windowsWheel(element, pstate, deso, eventHandler, event) {
|
||||
if (pstate === undefined) {
|
||||
pstate = deso.pstate;
|
||||
}
|
||||
const { deltaX, deltaY } = event;
|
||||
if (event.ctrlKey) {
|
||||
const key = (deltaY < 0)
|
||||
@ -50,6 +53,9 @@ function windowsWheel(element, pstate, deso, eventHandler, event) {
|
||||
* @param {WheelEvent} event
|
||||
*/
|
||||
function macOsWheel(element, pstate, deso, eventHandler, event) {
|
||||
if (pstate === undefined) {
|
||||
pstate = deso.pstate;
|
||||
}
|
||||
let { deltaX, deltaY } = event;
|
||||
if (event.ctrlKey) {
|
||||
const key = (deltaY < 0)
|
||||
@ -90,6 +96,9 @@ function macOsWheel(element, pstate, deso, eventHandler, event) {
|
||||
* @param {WheelEvent} event
|
||||
*/
|
||||
function linuxWheel(element, pstate, deso, eventHandler, event) {
|
||||
if (pstate === undefined) {
|
||||
pstate = deso.pstate;
|
||||
}
|
||||
const { deltaX, deltaY } = event;
|
||||
if (event.ctrlKey) {
|
||||
const key = (deltaY < 0)
|
||||
|
@ -100,6 +100,19 @@
|
||||
"toolbar.search.value.already-to-tail": "already to tail",
|
||||
"toolbar.search.value.searching": "searching",
|
||||
|
||||
"pivot.context.delete": "delete pivot",
|
||||
"pivot.context.display-axis": "create relative axis",
|
||||
|
||||
"setting.appearance.pivot-color": "pivot color",
|
||||
"setting.appearance.moving-pivot": "moving pivot",
|
||||
"setting.appearance.user-pivot": "user pivot",
|
||||
"setting.appearance.system-pivot": "system pivot",
|
||||
|
||||
"setting.language.change-dialog": "You've switched language to English, we recommend you reload Wave Viewer",
|
||||
"confirm": "confirm",
|
||||
"cancel": "cancel",
|
||||
"tips": "Tips",
|
||||
|
||||
"current-version": "current version",
|
||||
"copyright": "The copyright of this software belongs to <a href=\"https://github.com/Digital-EDA\" target=\"_blank\">Digital-IDE</a> project team. Welcome to <a href=\"https://github.com/Digital-EDA/Digital-IDE\">Star</a>."
|
||||
}
|
@ -98,6 +98,19 @@
|
||||
"toolbar.search.value.already-to-tail": "已经到结尾了",
|
||||
"toolbar.search.value.searching": "搜索中",
|
||||
|
||||
"pivot.context.delete": "删除信标",
|
||||
"pivot.context.display-axis": "创建相对坐标轴",
|
||||
|
||||
"setting.appearance.pivot-color": "信标颜色",
|
||||
"setting.appearance.moving-pivot": "移动信标",
|
||||
"setting.appearance.user-pivot": "用户信标",
|
||||
"setting.appearance.system-pivot": "系统信标",
|
||||
|
||||
"setting.language.change-dialog": "您已经更换语言为简体中文,我们建议您重启 Wave Viewer",
|
||||
"confirm": "确定",
|
||||
"cancel": "取消",
|
||||
"tips": "提示",
|
||||
|
||||
"current-version": "当前版本",
|
||||
"copyright": "本软件版权归 <a href=\"https://github.com/Digital-EDA\" target=\"_blank\">Digital-IDE</a> 项目组所有,欢迎 <a href=\"https://github.com/Digital-EDA/Digital-IDE\">Star</a>。"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user