355 lines
9.3 KiB
Vue
355 lines
9.3 KiB
Vue
<template>
|
|
<div
|
|
v-if="VisibleUserPivotIds.has(props.id)"
|
|
@mouseenter="onEnter()"
|
|
@mouseleave="onLeave()"
|
|
@contextmenu.prevent="handleUserContextMenu($event)"
|
|
class="user-pivot"
|
|
:style="userPivotStyle"
|
|
>
|
|
<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()"
|
|
></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>
|
|
|
|
<teleport to='body'>
|
|
<transition name="collapse-from-top">
|
|
<div
|
|
v-show="UserPivotCtxShows.get(props.id)"
|
|
class="user-context-menu"
|
|
:style="contextStyle"
|
|
>
|
|
<div class="menu-container">
|
|
<div
|
|
class="menu-item-container"
|
|
@click="deletePivot(props.time)"
|
|
>
|
|
<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
|
|
class="menu-item-container"
|
|
:class="{ 'disable': !RelativeAxis.show }"
|
|
@click="cancelRelativeAxis()"
|
|
>
|
|
<span class="menu-item-icon iconfont icon-delete"></span>
|
|
<span class="menu-item-name">{{ t('pivot.context.cancel-axis') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</teleport>
|
|
</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 { time2cursorX, mousemoveEventPipes, MovingPivot, cursorX2time } from './cursor';
|
|
import { boxShift, currentPivotId, deletePivot, getNearestUserPivot, orderedTimes, searchOrderedTimeIndex, UserPivotCtxShows, UserPivots, VisibleUserPivotIds } from './pivot-view';
|
|
import formatTime from '@/hook/wave-view/format-time';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { increaseBrightness, parseColor } from '@/hook/color';
|
|
import { RelativeAxis } from './relative-axis';
|
|
|
|
// import { handleUserContextMenu } from './user-context-menu';
|
|
|
|
defineComponent({ name: 'user-pivot' });
|
|
|
|
const { t } = useI18n();
|
|
|
|
const props = defineProps({
|
|
color: {
|
|
type: String,
|
|
default: 'var(--main-color)'
|
|
},
|
|
label: {
|
|
type: String
|
|
},
|
|
x: {
|
|
type: Number
|
|
},
|
|
time: {
|
|
type: Number
|
|
},
|
|
id: {
|
|
type: Number
|
|
}
|
|
});
|
|
|
|
const currentColor = computed(() => {
|
|
if (props.id === currentPivotId.value) {
|
|
const rgbColor = parseColor(props.color);
|
|
const brighterColor = increaseBrightness(rgbColor, 20);
|
|
return `rgb(${brighterColor.r}, ${brighterColor.g}, ${brighterColor.b})`;
|
|
}
|
|
return props.color;
|
|
});
|
|
|
|
const userPivotStyle = computed(() => ({
|
|
cursor: vline.dragEnable ? 'ew-resize': 'pointer'
|
|
}));
|
|
|
|
const colorStyle = computed(() => ({
|
|
backgroundColor: currentColor.value
|
|
}));
|
|
|
|
const borderStyle = computed(() => ({
|
|
borderLeft: '5px solid ' + currentColor.value,
|
|
borderTop: '5px solid ' + currentColor.value
|
|
}));
|
|
|
|
|
|
const cursorStyle = computed(() => ({
|
|
left: props.x - boxShift + 'px'
|
|
}));
|
|
|
|
|
|
function onEnter() {
|
|
MovingPivot.enterUserPivot = true;
|
|
}
|
|
|
|
function onLeave() {
|
|
MovingPivot.show = true;
|
|
MovingPivot.currentTakenPivot = undefined;
|
|
MovingPivot.enterUserPivot = false;
|
|
}
|
|
|
|
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;
|
|
currentPivotId.value = props.id;
|
|
|
|
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);
|
|
}
|
|
|
|
mousemoveEventPipes.set(pivot.id, event => {
|
|
if (vline.dragEnable === false) {
|
|
return;
|
|
}
|
|
const x = event.clientX || event.x;
|
|
pivot.x = x;
|
|
const pstate = globalLookup.pstate;
|
|
if (pstate) {
|
|
const { timescale } = pstate;
|
|
const t = cursorX2time(x);
|
|
pivot.time = t;
|
|
pivot.label = formatTime(t, timescale);
|
|
}
|
|
});
|
|
}
|
|
|
|
function onVLineMouseup() {
|
|
MovingPivot.dragEnable = false;
|
|
mousemoveEventPipes.delete(props.id);
|
|
|
|
const div = vline.element;
|
|
if (!(div instanceof HTMLElement)) {
|
|
return;
|
|
}
|
|
const pivot = UserPivots.get(vline.originTime);
|
|
|
|
if (pivot) {
|
|
UserPivots.delete(vline.originTime);
|
|
UserPivots.set(pivot.time, pivot);
|
|
orderedTimes.push(pivot.time);
|
|
orderedTimes.sort((a, b) => a - b);
|
|
}
|
|
|
|
currentPivotId.value = 0;
|
|
vline.originTime = 0;
|
|
vline.dragEnable = false;
|
|
// MovingPivot.currentTakenPivot = pivot;
|
|
// MovingPivot.show = false;
|
|
}
|
|
|
|
const contextmenu = reactive({
|
|
x: 0,
|
|
y: 0,
|
|
});
|
|
|
|
const contextStyle = computed(() => ({
|
|
top: contextmenu.y + 'px',
|
|
left: contextmenu.x + 20 + 'px'
|
|
}));
|
|
|
|
function handleUserContextMenu(event) {
|
|
contextmenu.x = event.x;
|
|
contextmenu.y = event.y;
|
|
for (const id of UserPivotCtxShows.keys()) {
|
|
UserPivotCtxShows.set(id, false);
|
|
}
|
|
UserPivotCtxShows.set(props.id, true);
|
|
currentPivotId.value = props.id;
|
|
}
|
|
|
|
|
|
|
|
function displayRelativeAxis() {
|
|
RelativeAxis.currentPivotId = props.id;
|
|
RelativeAxis.show = true;
|
|
|
|
currentPivotId.value = 0;
|
|
UserPivotCtxShows.delete(props.id);
|
|
}
|
|
|
|
function cancelRelativeAxis() {
|
|
if (RelativeAxis.show === false) {
|
|
return;
|
|
}
|
|
|
|
RelativeAxis.show = false;
|
|
currentPivotId.value = 0;
|
|
UserPivotCtxShows.set(props.id, false);
|
|
}
|
|
|
|
onMounted(() => {
|
|
UserPivotCtxShows.set(props.id, false);
|
|
const wrapper = document.getElementById('vcd-render-wrapper');
|
|
if (wrapper instanceof HTMLElement) {
|
|
wrapper.addEventListener('mouseup', onVLineMouseup);
|
|
}
|
|
});
|
|
|
|
</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(--vscode-foreground);
|
|
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(--vscode-foreground);
|
|
font-size: 14px;
|
|
position: relative;
|
|
}
|
|
|
|
.current-time-value {
|
|
border-radius: .4em;
|
|
color: var(--vscode-foreground);
|
|
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;
|
|
}
|
|
|
|
.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);
|
|
}
|
|
|
|
.menu-item-container.disable {
|
|
opacity: 0.5;
|
|
cursor: not-allowed !important;
|
|
}
|
|
|
|
.menu-item-container.disable:hover {
|
|
transition: unset;
|
|
color: unset !important;
|
|
background: unset !important;
|
|
animation: unset;
|
|
}
|
|
</style> |