完成搜索

This commit is contained in:
锦恢 2024-08-28 23:04:05 +08:00
parent 948370b644
commit 9f50214cbb
27 changed files with 832 additions and 204 deletions

View File

@ -6,7 +6,7 @@
--main-light-color: var(--main-color); --main-light-color: var(--main-color);
--sidebar-width: 330px; --sidebar-width: 330px;
--right-nav-width: 60px; --right-nav-width: 60px;
--time-scale-height: 50px; --time-scale-height: 30px;
--sidebar-padding: 10px; --sidebar-padding: 10px;
--sidebar-item-margin: 5px; --sidebar-item-margin: 5px;
--toolbar-height: 50px; --toolbar-height: 50px;

View File

@ -71,7 +71,7 @@ onMounted(async () => {
// document.body.style.setProperty('--el-color-white', 'var(--background)'); // document.body.style.setProperty('--el-color-white', 'var(--background)');
// //
document.body.style.setProperty('--time-scale-height', '50px'); document.body.style.setProperty('--time-scale-height', '30px');
document.body.style.setProperty('--vcd-render-padding', '30px'); document.body.style.setProperty('--vcd-render-padding', '30px');
document.body.style.setProperty('--sidebar-width', '330px'); document.body.style.setProperty('--sidebar-width', '330px');
document.body.style.setProperty('--toolbar-height', '60px'); document.body.style.setProperty('--toolbar-height', '60px');

View File

@ -0,0 +1,47 @@
import { globalLookup } from '@/hook/global';
import formatTime from '@/hook/wave-view/format-time';
import { reactive } from 'vue';
export const StaticCursor = reactive({
label: '',
show: false,
currentTime: 0,
left: 0,
updateLabel(timescale) {
this.label = formatTime(this.currentTime, timescale);
},
updateLeft() {
this.left = calcCursorLeft(this.currentTime);
}
});
export function changeCursorLocation() {
StaticCursor.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();
}
}
/**
* @description 给出当前的时间比如 23ns计算当前这个点应该相对于左侧偏移多少
* @param {number} currentTime
* @returns {number}
*/
export function calcCursorLeft(currentTime) {
const pstate = globalLookup.pstate;
if (pstate) {
const { xOffset, xScale, tgcd, timescale } = pstate;
const xCursor = (currentTime / tgcd) * xScale + xOffset;
return xCursor;
}
return 0;
}
export const MovingCursor = reactive({
});

View File

@ -1,94 +1,62 @@
<template> <template>
<div> <div v-show="StaticCursor.show">
<div class="vertical-cursor-wrapper" <div class="vertical-cursor-wrapper"
@click="makeCursor" :style="cursorStyle"
:style="`left: ${currentX}px`"> >
<div class="current-display-cursor-up"> <div class="current-display-cursor-up">
<div class="current-time-value">{{ currentX }} px</div> <div class="current-time-value" :style="colorStyle">{{ StaticCursor.label }}</div>
<div class="cursor-down-arrow"></div> <div class="cursor-down-arrow" :style="borderStyle"></div>
</div> </div>
<div class="vertical-line"></div> <div class="vertical-line" :style="colorStyle"></div>
<div class="current-display-cursor-down"> <div class="current-display-cursor-down">
<div class="current-time-value">{{ currentX }} px</div> <div class="current-time-value" :style="colorStyle">{{ StaticCursor.label }}</div>
<div class="cursor-up-arrow"></div> <div class="cursor-up-arrow" :style="borderStyle"></div>
</div> </div>
</div> </div>
<div v-show="showFixedOne"
class="vertical-cursor-wrapper"
@click="makeCursor"
:style="`left: ${fixedLeft}px`">
<div class="fix-current-display-cursor-up">
{{ globalLookup.view.currentX }} px
</div>
<div class="fix-vertical-line"></div>
<div class="fix-current-display-cursor-down">
{{ globalLookup.view.currentX }} px
</div>
</div>
</div> </div>
</template> </template>
<script> <script setup>
import { reactive, ref } from 'vue'; import { computed, defineComponent } from 'vue';
import { globalLookup } from '../../hook/global'; import { StaticCursor } from './cursor';
export default { defineComponent({ name: 'vertical-cursor' });
name: 'vertical-cursor',
setup() {
// see --sidebar-width
const left = 280 + 20;
// see --right-nav-width const props = defineProps({
const right = document.body.clientWidth - 60; color: {
type: String,
const showFixedOne = ref(false); default: 'var(--main-color)'
const fixedLeft = ref(0);
const currentX = ref(left);
const boxShift = 25;
document.onmousemove = event => {
const x = event.x;
if (x < left || x > right) {
return;
}
currentX.value = x - boxShift;
}
/**
* @param { PointerEvent } event
*/
function makeCursor(event) {
// console.log(event.x);
showFixedOne.value = true;
fixedLeft.value = event.x - boxShift;
globalLookup.view.currentX = event.x - boxShift;
}
return {
makeCursor,
fixedLeft,
showFixedOne,
boxShift,
globalLookup,
currentX
}
} }
} });
const colorStyle = {
backgroundColor: props.color
};
const borderStyle = {
borderLeft: '5px solid ' + props.color,
borderTop: '5px solid ' + props.color
};
const boxShift = 25;
const cursorStyle = computed(() => ({
left: StaticCursor.left - boxShift + 'px'
}));
</script> </script>
<style> <style scoped>
.vertical-cursor-wrapper { .vertical-cursor-wrapper {
position: absolute; position: absolute;
height: 100vh;
padding: 0;
top: 0; top: 0;
padding: 0;
cursor: crosshair; cursor: crosshair;
z-index: 55; z-index: 55;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; /* 沿着横轴(水平方向)对齐 */ align-items: center; /* 沿着横轴(水平方向)对齐 */
justify-content: center; /* 沿着纵轴(垂直方向)对齐 */ justify-content: center; /* 沿着纵轴(垂直方向)对齐 */
transform: translateY(var(--toolbar-height));
} }
.current-display-cursor-up { .current-display-cursor-up {
@ -115,7 +83,6 @@ export default {
.current-time-value { .current-time-value {
border-radius: .4em; border-radius: .4em;
background-color: var(--color-deepPurple);
color: var(--sidebar-item-text); color: var(--sidebar-item-text);
padding: 5px; padding: 5px;
width: fit-content; width: fit-content;
@ -123,8 +90,6 @@ export default {
} }
.cursor-down-arrow { .cursor-down-arrow {
border-left: 5px solid var(--color-deepPurple);
border-top: 5px solid var(--color-deepPurple);
transform: rotate(225deg); transform: rotate(225deg);
position: absolute; position: absolute;
width: 10px; width: 10px;
@ -134,9 +99,12 @@ export default {
bottom: 0; bottom: 0;
} }
.vertical-line {
width: 2px;
height: calc(100vh - 2 * var(--time-scale-height) - 60px);
}
.cursor-up-arrow { .cursor-up-arrow {
border-left: 5px solid var(--color-deepPurple);
border-top: 5px solid var(--color-deepPurple);
transform: rotate(45deg); transform: rotate(45deg);
position: absolute; position: absolute;
width: 10px; width: 10px;
@ -144,40 +112,4 @@ export default {
left: 17.93px; left: 17.93px;
top: 0; top: 0;
} }
.vertical-line {
width: 1px;
height: calc(100vh - 2 * var(--time-scale-height));
}
.fix-vertical-line {
width: 1px;
height: calc(100vh - 2 * var(--time-scale-height));
background-color: var(--color-deepPurple);
}
.fix-current-display-cursor-up {
height: var(--time-scale-height);
width: 50px;
background-color: var(--color-deepPurple);
border-radius: .5em .5em .5em .5em;
display: flex;
align-items: center;
justify-content: space-around;
color: var(--sidebar-item-text);
font-size: 14px;
}
.fix-current-display-cursor-down {
height: var(--time-scale-height);
width: 50px;
background-color: var(--color-deepPurple);
border-radius: .5em .5em .5em .5em;
display: flex;
align-items: center;
justify-content: space-around;
color: var(--sidebar-item-text);
font-size: 14px;
}
</style> </style>

View File

@ -1,35 +1,27 @@
<template> <template>
<!-- <VerticalCursor></VerticalCursor> --> <!-- <VerticalCursor></VerticalCursor> -->
<!-- <TimeScale></TimeScale> --> <!-- <TimeScale></TimeScale> -->
<div class="vcd-render-wrapper" @click="updateWireCurrentValue()"> <div class="vcd-render-wrapper" @click="onRenderClick()">
<VerticalCursor></VerticalCursor>
</div> </div>
</template> </template>
<script> <script setup>
import { reactive, ref } from 'vue'; import { defineComponent, reactive, ref } from 'vue';
import { emitter, globalLookup, globalSetting } from '@/hook/global'; import { emitter, globalLookup, globalSetting } from '@/hook/global';
import { updateWireCurrentValue } from '@/hook/utils'; import { updateWireCurrentValue } from '@/hook/utils';
import VerticalCursor from '@/components/render/cursor.vue'; import VerticalCursor from '@/components/render/cursor.vue';
import TimeScale from '@/components/render/time-scale.vue'; import { changeCursorLocation } from './cursor';
export default { defineComponent({ name: 'main-render' });
name: 'main-render',
components: {
// VerticalCursor,
// TimeScale
},
setup() {
/**
* @description 渲染区域被鼠标点击时
return { */
globalLookup, function onRenderClick() {
updateWireCurrentValue updateWireCurrentValue();
} changeCursorLocation();
}
} }
</script> </script>
@ -89,6 +81,7 @@ export default {
.vcd-cursor { .vcd-cursor {
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
z-index: 60;
} }
.vcd-values text { .vcd-values text {

View File

@ -150,7 +150,7 @@ function handleSidebarGlobalClick() {
border-radius: 0 .8em .8em 0; border-radius: 0 .8em .8em 0;
border: solid 1px var(--sidebar-border); border: solid 1px var(--sidebar-border);
width: var(--sidebar-width); width: var(--sidebar-width);
height: calc(100vh - var(--toolbar-height)); height: calc(100vh - var(--toolbar-height) - 50px);
box-shadow: 0 0 15px 1px rgb(16, 16, 16); box-shadow: 0 0 15px 1px rgb(16, 16, 16);
overflow: hidden; overflow: hidden;
} }
@ -165,6 +165,14 @@ function handleSidebarGlobalClick() {
transition: var(--animation-5s); transition: var(--animation-5s);
} }
.group-children .display-signal-item {
width: calc(200px - 8px - 10px) !important;
}
.group-children .signal-color-vendor > span {
font-size: 12px;
}
.display-signal-item-container { .display-signal-item-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View File

@ -17,7 +17,9 @@
<span>{{ signalInfo.name }}</span> <span>{{ signalInfo.name }}</span>
</div> </div>
<div class="signal-info-width" v-show="showWidth"> <div class="signal-info-width" v-show="showWidth">
<div :class="signalInfo.size > 1 ? 'signal-info-caption' : ''"> <div
:class="{ 'signal-info-caption': signalInfo.size > 1 }"
>
{{ makeSignalCaption(signalInfo) }} {{ makeSignalCaption(signalInfo) }}
</div> </div>
</div> </div>
@ -70,7 +72,7 @@ const signalInfo = computed(() => {
/** /**
* @param {WireItemBaseInfo} signal * @param {WireItemBaseInfo} signal
*/ */
function makeSignalIconClass(signal) { function makeSignalIconClass(signal) {
const realSignal = globalLookup.link2CurrentWires.get(signal.link); const realSignal = globalLookup.link2CurrentWires.get(signal.link);
return 'iconfont ' + makeIconClass(realSignal); return 'iconfont ' + makeIconClass(realSignal);
} }

View File

@ -0,0 +1,160 @@
import { globalLookup } from "@/hook/global";
import { calcCursorLeft, StaticCursor } from "../render/cursor";
import { sidebarSelectedWires } from "@/hook/sidebar-select-wire";
/**
* @description 某时间点 移动到指定位置
* @param {number} time 需要移动到的时间点
* @param {number} leftMargin 移动后的该时间点距离左侧多少px
* @param {Pstate} pstate
*/
function moveto(time, leftMargin, pstate) {
StaticCursor.show = true;
StaticCursor.currentTime = time;
pstate.oldXOffset = pstate.xOffset;
const { width, xOffset, xScale, tgcd, timescale } = pstate;
pstate.xOffset = leftMargin - (time / tgcd) * xScale;
StaticCursor.updateLeft();
StaticCursor.updateLabel(pstate.timescale);
globalLookup.render();
}
export function toBegin() {
const pstate = globalLookup.pstate;
if (pstate) {
moveto(0, pstate.sidebarWidth - 20, pstate);
}
}
export function toEnd() {
const pstate = globalLookup.pstate;
if (pstate) {
moveto(globalLookup.time, pstate.width - pstate.sidebarWidth, pstate);
}
}
function clip(v, min, max) {
if (v < min) {
v = min;
}
if (v > max) {
v = max;
}
return v;
}
export function toPrevChange() {
const link = sidebarSelectedWires.lastLink;
const pstate = globalLookup.pstate;
if (link === undefined || pstate === undefined) {
return;
}
const chango = globalLookup.chango[link];
if (chango && chango.wave && chango.wave.length > 0) {
const wave = chango.wave;
// 如果长度为 1直接到前面或者后面即可
if (wave.length === 1) {
toBegin();
} else {
const currentT = StaticCursor.currentTime;
let pivot = bisearch(wave, currentT);
const pwave = wave[pivot];
if (pwave[0] === currentT) {
pivot = clip(pivot - 1, 0, wave.length - 1);
} else {
pivot = clip(pivot, 0, wave.length - 1);
}
const targetT = wave[pivot][0];
moveto(targetT, (pstate.width + pstate.sidebarWidth) / 2, pstate);
}
}
}
export function toNextChange() {
const link = sidebarSelectedWires.lastLink;
const pstate = globalLookup.pstate;
if (link === undefined || pstate === undefined) {
return;
}
const chango = globalLookup.chango[link];
if (chango && chango.wave && chango.wave.length > 0) {
const wave = chango.wave;
// 如果长度为 1直接到前面或者后面即可
if (wave.length === 1) {
toEnd();
} else {
const currentT = StaticCursor.currentTime;
let pivot = bisearch(wave, currentT);
let targetT;
if (pivot === wave.length - 1) {
pivot = clip(pivot + 1, 0, wave.length - 1);
targetT = globalLookup.time;
} else {
pivot = clip(pivot + 1, 0, wave.length - 1);
targetT = wave[pivot][0];
}
moveto(targetT, (pstate.width + pstate.sidebarWidth) / 2, pstate);
}
}
}
const locationManager = {
/**
* @description 记录所有的信标
* @type {Map<number, HTMLElement>} 时间点到元素的映射
*/
pivots: new Map(),
};
export function makeLocation() {
const currentT = StaticCursor.currentTime;
// 在 currentT 创建新的信标
}
/**
* @description 二分查找找到最近的索引下标
* @param {number[][]} wave
* @param {number} time
* @return {number}
*/
function bisearch(wave, time) {
const times = wave.map(p => p[0]);
// 二分查找,并将结果存入 i
let i = 0, j = wave.length - 1;
while (i < j) {
if (times[i] === time) {
break;
}
if (times[j] <= time) {
i = j;
break;
}
if (j - i === 1) {
break;
}
const mid = (i + j) >> 1;
if (times[mid] > time) {
j = mid;
} else {
i = mid;
}
}
return i;
}

View File

@ -1,35 +1,86 @@
<template> <template>
<div class="location"> <div class="location">
<div <el-tooltip
class="item iconfont icon-beginning" effect="dark"
:content="t('toolbar.location.to-begin')"
placement="bottom"
raw-content
>
<div
class="item iconfont icon-beginning"
@click="toBegin()"
/>
</el-tooltip>
/>
<div
class="item iconfont icon-ending"
/> <el-tooltip
effect="dark"
:content="t('toolbar.location.to-end')"
placement="bottom"
raw-content
>
<div
class="item iconfont icon-ending"
@click="toEnd()"
/>
</el-tooltip>
<el-divider direction="vertical"></el-divider> <el-divider direction="vertical"></el-divider>
<div
class="item iconfont icon-arrow-to-previous"
/> <el-tooltip
<div effect="dark"
class="item iconfont icon-arrow-to-next" :content="t('toolbar.location.to-prev-change')"
placement="bottom"
raw-content
>
<div
class="item iconfont icon-arrow-to-previous"
:class="{ 'disable' : globalLookup.sidebarSelectedWireLinks.size === 0 }"
@click="toPrevChange()"
/>
</el-tooltip>
<el-tooltip
effect="dark"
:content="t('toolbar.location.to-next-change')"
placement="bottom"
raw-content
>
<div
class="item iconfont icon-arrow-to-next"
:class="{ 'disable' : globalLookup.sidebarSelectedWireLinks.size === 0 }"
@click="toNextChange()"
/>
</el-tooltip>
/>
<el-divider direction="vertical"></el-divider> <el-divider direction="vertical"></el-divider>
<div
class="item iconfont icon-add-line"
/> <el-tooltip
effect="dark"
:content="t('toolbar.location.make-location')"
placement="bottom"
raw-content
>
<div
class="item iconfont icon-add-line"
/>
</el-tooltip>
</div> </div>
</template> </template>
<script setup> <script setup>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
import { toBegin, toEnd, toNextChange, toPrevChange } from './cursor-location';
import { globalLookup } from '@/hook/global';
defineComponent({ name: 'cursor-location' }); defineComponent({ name: 'cursor-location' });
const { t } = useI18n();
</script> </script>
@ -62,4 +113,15 @@ defineComponent({ name: 'cursor-location' });
color: var(--sidebar); color: var(--sidebar);
transition: var(--animation-3s); transition: var(--animation-3s);
} }
.disable {
opacity: 0.5;
cursor: not-allowed !important;
}
.location .item.disable:hover {
background-color: unset !important;
color: unset !important;
}
</style> </style>

View File

@ -37,6 +37,7 @@ defineComponent({ name: 'toolbar' });
width: 100%; width: 100%;
height: var(--toolbar-height); height: var(--toolbar-height);
background-color: var(--background); background-color: var(--background);
z-index: 60;
} }
.toolbar-body { .toolbar-body {

View File

@ -0,0 +1 @@

View File

@ -54,14 +54,15 @@ const signalModal = ref(0);
const disabled = ref(true); const disabled = ref(true);
function onSignalModalUpdate() { function onSignalModalUpdate() {
console.log('enter change');
const links = globalLookup.sidebarSelectedWireLinks; const links = globalLookup.sidebarSelectedWireLinks;
if (links.size > 0) { if (links.size > 0) {
const modal = signalModal.value; const modal = signalModal.value;
// //
for (const link of links) { for (const link of links) {
globalLookup.setRenderOption(link, 'renderModal', modal); const realChange = globalLookup.setRenderOption(link, 'renderModal', modal);
globalLookup.waveRender.resetVertice(link); if (realChange) {
globalLookup.waveRender.resetVertice(link);
}
} }
// //

View File

@ -37,9 +37,6 @@ const { t } = useI18n();
const currentOption = ref(2); const currentOption = ref(2);
const disabled = ref(true); const disabled = ref(true);
function onChange() {
console.log(currentOption.value);
}
onMounted(() => { onMounted(() => {
formatOptions.push({ formatOptions.push({
@ -95,6 +92,23 @@ onMounted(() => {
const formatOptions = reactive([]); const formatOptions = reactive([]);
function onChange() {
const links = globalLookup.sidebarSelectedWireLinks;
if (links.size > 0) {
const valueFormat = currentOption.value;
//
for (const link of links) {
const realChange = globalLookup.setRenderOption(link, 'valueFormat', valueFormat);
if (realChange) {
globalLookup.waveRender.resetVertice(link);
}
}
//
globalLookup.render({ type: 'value' });
}
}
sidebarSelectedWires.addToPipe(lastLink => { sidebarSelectedWires.addToPipe(lastLink => {
if (lastLink) { if (lastLink) {
const option = globalLookup.currentSignalRenderOptions.get(lastLink); const option = globalLookup.currentSignalRenderOptions.get(lastLink);

View File

@ -14,20 +14,132 @@
</el-radio-group> </el-radio-group>
</div> </div>
<div class="value-input-wrapper"> <div class="value-input-wrapper">
<el-input></el-input> <el-input
v-model="searchManage.content"
@input="safeSearch"
@focus="searchManage.displayResult = true"
@blur="searchManage.displayResult = false"
></el-input>
<transition name="collapse-from-top">
<div
v-show="searchManage.displayResult || searchManage.mouseOnResult"
class="toolbar-search-container"
>
<el-scrollbar
height="300px"
width="100%"
@mouseenter="searchManage.mouseOnResult = true"
@mouseleave="searchManage.mouseOnResult = false"
class="search-result"
>
<div v-if="searchManage.searchResult.length > 0">
<div v-for="(signal, index) in searchManage.searchResult"
:key="index"
@click="clickSearchItem(signal)"
class="toolbar-search"
>
<span :class="makeSignalIconClass(signal)"></span>
<span class="signal-name">{{ signal.name }}</span>
<span
class="signal-width"
>
<span :class="{ 'vec': signal.width > 1 }">{{ makeSignalCaption(signal) }}</span>
</span>
<span class="signal-value">{{ signal.value }}</span>
</div>
</div>
<div v-else class="toolbar-search-nothing">
<span class="iconfont icon-empty"></span>
<span>{{ t('search-nothing') }}</span>
</div>
</el-scrollbar>
</div>
</transition>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { defineComponent, ref } from 'vue'; import { globalLookup } from '@/hook/global';
import { debounceWrapper, makeIconClass } from '@/hook/utils';
import { defineComponent, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
defineComponent({ name: 'value-search' }) defineComponent({ name: 'value-search' })
const { t } = useI18n(); const { t } = useI18n();
const searchMode = ref(1);
const searchMode = ref(0); const searchManage = reactive({
content: '',
displayResult: false,
mouseOnResult: false,
searchResult: [],
});
function addWire(wireItem) {
searchManage.searchResult.push({
name: wireItem.name,
width: wireItem.size,
type: wireItem.type,
value: globalLookup.currentSignalValues[wireItem.link]
});
}
function searchByValue() {
const value = searchManage.content.trim();
for (const wireItem of globalLookup.currentWires) {
const currentVal = globalLookup.currentSignalValues[wireItem.link];
if (currentVal.toString().includes(value)) {
addWire(wireItem);
}
}
}
function searchByName() {
const name = searchManage.content.trim();
for (const wireItem of globalLookup.currentWires) {
if (wireItem.name.includes(name)) {
addWire(wireItem);
}
}
}
function search() {
if (globalLookup.currentWires.size === 0 || searchManage.content.trim().length === 0) {
searchManage.searchResult.length = 0;
return;
}
switch (searchMode.value) {
case 0:
searchByValue();
break;
case 1:
searchByName();
break;
}
}
const safeSearch = debounceWrapper(search, 200);
function clickSearchItem() {
}
function makeSignalCaption(signal) {
if (signal === undefined) {
return '';
}
return signal.width === 1 ? '' : `${signal.width - 1}:0`;
}
function makeSignalIconClass(signal) {
return 'iconfont ' + makeIconClass(signal);
}
</script> </script>
@ -41,8 +153,106 @@ const searchMode = ref(0);
} }
.value-input-wrapper { .value-input-wrapper {
position: relative;
margin-left: 5px; margin-left: 5px;
width: 120px; width: 120px;
} }
.toolbar-search-container {
position: absolute;
top: 50px;
left: -10px;
transition: var(--animation-3s);
padding: 10px;
margin: 10px;
background-color: var(--sidebar);
border: 1.5px solid var(--main-color);
color: var(--sidebar-item-text);
border-radius: .5em;
width: 420px;
}
.toolbar-search-nothing {
height: 260px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1.1rem;
}
.toolbar-search-nothing .iconfont {
font-size: 80px;
}
.toolbar-search .signal-name {
width: 100px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 100%;
align-items: center;
padding: 5px;
}
.toolbar-search .iconfont {
font-size: 13px;
color: var(--sidebar);
background-color: #7ca532;
border-radius: 99em;
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 5px;
}
.toolbar-search {
display: flex;
margin: 3px;
align-items: center;
cursor: pointer;
transition: var(--animation-3s);
border-radius: .5em;
padding-left: 5px;
}
.toolbar-search:hover {
transition: var(--animation-3s);
background-color: var(--sidebar-item-selected);
}
.toolbar-search .signal-width {
width: 80px;
height: 100%;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: center;
padding: 5px;
}
.toolbar-search .vec {
color: var(--sidebar);
background-color: #7ca532;
padding: 2px 3px;
border-radius: .5em;
font-size: 0.9rem;
}
.toolbar-search .signal-value {
width: 150px;
height: 100%;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: center;
padding: 5px;
}
</style> </style>

View File

@ -13,7 +13,7 @@
</div> </div>
<transition name="collapse-from-top"> <transition name="collapse-from-top">
<div <div
v-show="searchManage.displayResult | searchManage.mouseOnResult" v-show="searchManage.displayResult || searchManage.mouseOnResult"
:style="searchResultWrapper" :style="searchResultWrapper"
class="search-result-wrapper" class="search-result-wrapper"
id="search-result-wrapper" id="search-result-wrapper"
@ -110,7 +110,7 @@ emitter.on('signal-search', searchResultItem => {
searchManage.searchResult.push(searchResultItem); searchManage.searchResult.push(searchResultItem);
}); });
const safeSearch = debounceWrapper(search, 500); const safeSearch = debounceWrapper(search, 200);
</script> </script>

View File

@ -86,10 +86,11 @@ export const globalLookup = reactive({
*/ */
chango: {}, chango: {},
// 初始化时会被定义 /**
render: () => {}, * @description 核心接入渲染管线重新渲染该函数必须在 domContainer 初始化完成后再去调用
* @param {RenderConfig} renderConfig 渲染的类型默认为重新渲染所有可视项
*/
render: (renderConfig) => {},
/** /**
* @description 非常核心的用于操控 webgl 进行渲染和动画的核心类 * @description 非常核心的用于操控 webgl 进行渲染和动画的核心类
@ -98,6 +99,10 @@ export const globalLookup = reactive({
waveRender: undefined, waveRender: undefined,
/**
* @description 描述描述当前渲染区的一些基本几何状态
* @type {Pstate | undefined}
*/
pstate: undefined, pstate: undefined,
xScale: 1, xScale: 1,
@ -126,13 +131,18 @@ export const globalLookup = reactive({
* @param {string} link * @param {string} link
* @param {'height' | 'color' | 'valueFormat' | 'renderModal'} option * @param {'height' | 'color' | 'valueFormat' | 'renderModal'} option
* @param {any} value * @param {any} value
* @returns {boolean} true 代表改变了值否则则没有可以用来判断是否需要重复塑造 Vertices
*/ */
setRenderOption(link, option, value) { setRenderOption(link, option, value) {
if (!this.currentSignalRenderOptions.has(link)) { if (!this.currentSignalRenderOptions.has(link)) {
this.currentSignalRenderOptions.set(link, {}); this.currentSignalRenderOptions.set(link, {});
} }
const renderOption = this.currentSignalRenderOptions.get(link); const renderOption = this.currentSignalRenderOptions.get(link);
if (renderOption[option] === value) {
return false;
}
renderOption[option] = value; renderOption[option] = value;
return true;
} }
}); });

View File

@ -65,8 +65,6 @@ function makeWaveView(parentElement) {
console.log('updater'); console.log('updater');
}; };
globalLookup
// 注册基本的响应事件 // 注册基本的响应事件
container.elo.container.addEventListener('wheel', container.elo.container.addEventListener('wheel',
registerWheelEvent(parentElement, container.pstate, globalLookup, eventHandler) registerWheelEvent(parentElement, container.pstate, globalLookup, eventHandler)

View File

@ -21,14 +21,20 @@ const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
// 这是上面展示当前 time 的圆角矩形内的字体大小 // 这是上面展示当前 time 的圆角矩形内的字体大小
const fontHeight = 20; const fontHeight = 20;
const fontWidth = fontHeight / 2; const fontWidth = fontHeight / 2;
const sidebarWidth = pstate.sidebarWidth;
const handler = event => { const handler = event => {
const x = pstate.xCursor = event.clientX; const x = pstate.xCursor = event.clientX;
cursor.style.left = (x - xmargin) + 'px'; const left = x - xmargin;
cursor.innerHTML = renderCursor({ xmargin, fontWidth, fontHeight }, pstate); // 不能进入左侧,也不能进入右侧
if (left > sidebarWidth - 195) {
cursor.style.left = (x - xmargin) + 'px';
cursor.innerHTML = renderCursor({ xmargin, fontWidth, fontHeight }, pstate);
}
}; };
// 添加初始鼠标位置 // 添加初始鼠标位置
handler({ clientX: pstate.width / 2 }); handler({ clientX: pstate.width / 2 });
content.addEventListener('mousemove', handler); document.addEventListener('mousemove', handler);
}; };
@ -171,7 +177,6 @@ const domContainer = (obj) => {
setTime(pstate, deso.timeOpt.value); setTime(pstate, deso.timeOpt.value);
} }
const waveRender = new WebGL2WaveRender(elo, deso, pstate, obj.renderPlugins); const waveRender = new WebGL2WaveRender(elo, deso, pstate, obj.renderPlugins);
deso.render = waveRender.render.bind(waveRender); deso.render = waveRender.render.bind(waveRender);
deso.waveRender = waveRender; deso.waveRender = waveRender;

View File

@ -81,7 +81,7 @@ function addVecRenderItem(link) {
/** /**
* *
* @param {GlobalLookup} desc * @param {GlobalLookup} desc
* @param {*} pstate * @param {Pstate} pstate
* @returns * @returns
*/ */
function* renderValues(desc, pstate) { function* renderValues(desc, pstate) {
@ -89,9 +89,9 @@ function* renderValues(desc, pstate) {
// 根据 currentWiresRenderView 视图渲染 // 根据 currentWiresRenderView 视图渲染
// 此处应该和 render-wave 的相同注释的地方保持逻辑上的一致render-wave.js 约 646 行) // 此处应该和 render-wave 的相同注释的地方保持逻辑上的一致render-wave.js 约 646 行)
const currentWires = desc.currentWires; const currentWires = desc.currentWires;
const renderSignals = []; const renderSignals = [];
for (const view of globalLookup.currentWiresRenderView) { for (const view of globalLookup.currentWiresRenderView) {
if (view.renderType === 0) { if (view.renderType === 0) {
const realSignal = addVecRenderItem(view.signalInfo.link); const realSignal = addVecRenderItem(view.signalInfo.link);
@ -115,48 +115,57 @@ function* renderValues(desc, pstate) {
const lineHeightExtra = (globalSetting.displaySignalHeight - 30) / 2; const lineHeightExtra = (globalSetting.displaySignalHeight - 30) / 2;
const ilen = height / yStep; const canvaseHeight = height - topBarHeight - botBarHeight;
const iskip = (yOffset - lineHeightExtra) / yStep;
const ml = genSVG(width, height - topBarHeight - botBarHeight); // 当前一页最多渲染这么多项目
const validRenderNum = Math.ceil(canvaseHeight / yStep);
const ml = genSVG(width, canvaseHeight);
// 需要跳过前面几项
const renderStartNo = (yOffset - lineHeightExtra) / yStep;
let ifirst = 0; let ifirst = 0;
for (let i = 0; i < ilen; ++ i) { for (let i = 0; i < validRenderNum; ++ i) {
const lane = renderSignals[i]; const lane = renderSignals[i];
if (lane && (lane.name || lane.kind)) { if (lane && (lane.name || lane.kind)) {
if (i > iskip) { if (i > renderStartNo) {
break; break;
} }
ifirst = i; ifirst = i;
} }
} }
ml.push(defs); ml.push(defs);
yield; yield;
const markers = ['g']; const markers = ['g'];
ml.push(markers); ml.push(markers);
for (let i = 0; i < (iskip + ilen); i++) { for (let i = 0; i < (renderStartNo + validRenderNum); i++) {
const lane = renderSignals[i + (ifirst | 0)]; const lane = renderSignals[i + (ifirst | 0)];
const link = (lane || {}).ref; const link = (lane || {}).ref;
if (link === '') {
continue;
}
if (lane && lane.kind === 'DIZ') { if (lane && lane.kind === 'DIZ') {
markers.push(['g', tt(0, Math.round((i - (iskip - ifirst) + 1.18) * yStep))].concat(water(lane, desc, pstate))); markers.push(['g', tt(0, Math.round((i - (renderStartNo - ifirst) + 1.18) * yStep))].concat(water(lane, desc, pstate)));
} else if (lane && lane.kind === 'brace') { } else if (lane && lane.kind === 'brace') {
markers.push(['g', tt(0, Math.round((i - (iskip - ifirst) + 1.18) * yStep))].concat(bracer(lane, desc, pstate))); markers.push(['g', tt(0, Math.round((i - (renderStartNo - ifirst) + 1.18) * yStep))].concat(bracer(lane, desc, pstate)));
} else if (lane && link) { } else if (lane && link) {
const chango = desc.chango[link]; const chango = desc.chango[link];
if (chango && chango.kind === 'vec') { if (chango && chango.kind === 'vec') {
// tt: 计算出当前这一行的所有 值 svg 在 Y 方向的偏移 // tt: 计算出当前这一行的所有 值 svg 在 Y 方向的偏移
const mLane = ['g', tt(0, Math.round((i - (iskip - ifirst) + 0.15) * yStep))]; const mLane = ['g', tt(0, Math.round((i - (renderStartNo - ifirst) + 0.15) * yStep))];
const { wave } = chango; const { wave } = chango;
const jlen = wave.length;
perLane: { perLane: {
let [tPre, vPre, mPre] = wave[0]; let [tPre, vPre, mPre] = wave[0];
let xPre = getX(pstate, tPre); let xPre = getX(pstate, tPre);
const labeler = getLabel(lane); const labeler = getLabel(lane);
for (let j = 1; j <= jlen; j++) { for (let j = 1; j <= wave.length; j++) {
const mark = wave[j]; const mark = wave[j];
const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]); const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]);
@ -191,7 +200,6 @@ function* renderValues(desc, pstate) {
} }
} }
// console.log(view);
for (let i = 0; i < renderSignals.length; i++) { for (let i = 0; i < renderSignals.length; i++) {
const lane = renderSignals[i]; const lane = renderSignals[i];
if (lane && lane.vlines) { if (lane && lane.vlines) {

View File

@ -3,6 +3,7 @@ import { 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 { 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 { vertexShader, fragmentShader } from './render-shader.js';
import { renderAsBit, renderAsCommonDigital, renderAsLadderAnalog, renderAsLineAnalog } from './toolbar/renderModal'; import { renderAsBit, renderAsCommonDigital, renderAsLadderAnalog, renderAsLineAnalog } from './toolbar/renderModal';
import { StaticCursor } from '@/components/render/cursor';
/** /**
* @description * @description
@ -392,6 +393,17 @@ class WebGL2WaveRender {
const _this = this; const _this = this;
if (renderConfig.type === 'value') {
const renderValue = plugins.filter(plugin => plugin.name === 'pluginRenderValues')[0];
if (renderValue) {
renderValue(globalLookup, pstate, elements);
}
return;
}
// 更新静态 cursor
StaticCursor.updateLeft();
function linearAnimation(delta, oldVal, newVal) { function linearAnimation(delta, oldVal, newVal) {
return (1 - delta) * oldVal + delta * newVal; return (1 - delta) * oldVal + delta * newVal;
} }
@ -537,10 +549,8 @@ class WebGL2WaveRender {
pstate.oldYStep = pstate.yStep; pstate.oldYStep = pstate.yStep;
pstate.oldYDuty = pstate.yDuty; pstate.oldYDuty = pstate.yDuty;
if (needHiddenAnimation) { _this.elements.grid.classList.remove('vcd-hidden');
_this.elements.grid.classList.remove('vcd-hidden'); _this.elements.values.classList.remove('vcd-hidden');
_this.elements.values.classList.remove('vcd-hidden');
}
return; return;
} }
} }

View File

@ -124,7 +124,7 @@ export class FormatValueRender {
if (valueString.length <= pos) { if (valueString.length <= pos) {
return valueString; return valueString;
} }
const valSign = (value < 0) ? '-' : '+'; const valSign = (value < 0) ? '-' : '';
if (pos === 1) { if (pos === 1) {
return valSign; return valSign;
} }
@ -155,6 +155,8 @@ export class FormatValueRender {
* @param {number} pos 位置 * @param {number} pos 位置
*/ */
floatTransform(fWidth, value, pos) { floatTransform(fWidth, value, pos) {
const replacer = this.replacer;
if (fWidth === 16) { if (fWidth === 16) {
value = this.calcIEEEFloat(value, 5, 10); value = this.calcIEEEFloat(value, 5, 10);
} else if (fWidth === 32) { } else if (fWidth === 32) {
@ -167,7 +169,7 @@ export class FormatValueRender {
if (valueString.length <= pos) { if (valueString.length <= pos) {
return valueString; return valueString;
} }
const valSign = (value < 0) ? '-' : '+'; const valSign = (value < 0) ? '-' : '';
if (pos === 1) { if (pos === 1) {
return valSign; return valSign;
} }
@ -221,3 +223,141 @@ export class FormatValueRender {
return sign * efficentPow2(e - offset) * (1 + m / mFrac); return sign * efficentPow2(e - offset) * (1 + m / mFrac);
} }
} }
export class JSValueRender {
/**
*
* @param {string} link 信号的ID
* @param {number} width 信号的位置宽度
* @param {string} replacer 位置不足的地方会用 replacer 补足比如 ...
*/
constructor(link, width) {
this.formatCode = getValueFormatCode(link);
this.width = BigInt(width);
}
/**
* @description 根据当前的设置进行数值的渲染
* @param {number} value 波形当前的数值
* @returns {string} 转换后需要渲染的字符串
*/
explainAsNumber(value) {
const formatCode = this.formatCode;
switch (formatCode) {
// 二进制
case 0: return this.radixTransform(2, value);
// 八进制
case 1: return this.radixTransform(8, value);
// 十六进制
case 2: return this.radixTransform(16, value);
// 有符号整型
case 3: return this.radixTransform(10, value, true);
// 无符号整型
case 4: return this.radixTransform(10, value);
// 半精度浮点数
case 5: return this.floatTransform(16, value);
// 单精度浮点数
case 6: return this.floatTransform(32, value);
// 双精度浮点数
case 7: return this.floatTransform(64, value);
// 未知
default: return '?';
}
}
/**
* @description 整数的进制转换
* @param {number} radix 进制
* @param {number} value
* @param {number} pos 位置宽度
* @param {boolean} sign 是否是有符号数默认为 false
*/
radixTransform(radix, value, sign = false) {
const width = this.width;
const replacer = this.replacer;
if (value === 'x') {
return -1;
}
value = BigInt(value);
// 如果是有符号数
if (sign) {
if ((value >> (width - 1n)) & 1n) {
value = value - (2n ** width);
}
return parseInt(value);
}
// 无符号的各类进制数字
return parseInt(value);
}
/**
* @description IEEE 浮点数的转换
* 为什么没有 sign 参数因为 IEEE 定义下的 float 第一个位置就是符号
* @param {number} fWidth 16 32 或者 64
* @param {number} value
* @param {number} pos 位置
*/
floatTransform(fWidth, value) {
const replacer = this.replacer;
if (fWidth === 16) {
value = this.calcIEEEFloat(value, 5, 10);
} else if (fWidth === 32) {
value = this.calcIEEEFloat(value, 8, 23);
} else if (fWidth === 64) {
value = this.calcIEEEFloat(value, 11, 52);
}
return value;
}
/**
* @description 根据 e m 得到计算 IEEE 浮点数的函数默认第一个位置代表符号
* @param {number} value
* @param {number} eWidth 代表指数部分的位数
* @param {number} mWidth 代表有效尾数的位数
* @returns {(value: number) => number}
*/
calcIEEEFloat(value, eWidth, mWidth) {
const offset = (1 << (eWidth - 1)) - 1;
const mFrac = 1 << mWidth;
// 计算参考博客https://blog.csdn.net/leo0308/article/details/117398166
let bits = value.toString(2);
const width = 1 + eWidth + mWidth;
// 应对 bits 长度和 预定长度不一致的情况
// 不足的地方补上 0否则进行截断
if (bits.length < width) {
bits = '0'.repeat(width - bits.length) + bits;
}
if (bits.length > width) {
bits = bits.substring(bits.length - width);
}
const s = parseInt(bits[0], 2);
const e = parseInt(bits.substring(1, 1 + eWidth), 2);
const m = parseInt(bits.substring(2 + eWidth), 2);
const sign = (s === 1) ? -1 : 1;
// 全 0
if (e === 0) {
return sign * efficentPow2(-offset + 1 - mWidth) * m;
}
// 全 1
if (e === ((1 << eWidth) - 1)) {
if (m === 0) {
return sign * Infinity;
}
return NaN;
}
return sign * efficentPow2(e - offset) * (1 + m / mFrac);
}
}

View File

@ -30,7 +30,7 @@
import { globalLookup } from "@/hook/global"; import { globalLookup } from "@/hook/global";
import { lineAnalog_WidthShift, lineAnlog_GL_WidthShifts, maskColorIndexOffset, posYFactor, prettyPrint } from "../render-utils"; import { lineAnalog_WidthShift, lineAnlog_GL_WidthShifts, maskColorIndexOffset, posYFactor, prettyPrint } from "../render-utils";
import { hexToSignedInt } from "./renderFormat"; import { FormatValueRender, hexToSignedInt, JSValueRender } from "./renderFormat";
function makeQuadVertices(p1, p2, p3, p4) { function makeQuadVertices(p1, p2, p3, p4) {
return [ return [
@ -413,11 +413,13 @@ function getMaxMinByFormat(link, wave, time, formatCode, width) {
let minVal = undefined; let minVal = undefined;
const length = wave.length; const length = wave.length;
const valueRender = new JSValueRender(link, width);
// TODO : 优化这段代码 // TODO : 优化这段代码
for (let i = 0; i < length; ++ i) { for (let i = 0; i < length; ++ i) {
const [t1, val, mask] = wave[i]; const [t1, val, mask] = wave[i];
const t2 = (i === (length - 1)) ? time : wave[i + 1][0]; const t2 = (i === (length - 1)) ? time : wave[i + 1][0];
const numVal = explainAsJSNumber(formatCode, val, width); const numVal = valueRender.explainAsNumber(val);
if (maxVal === undefined) { if (maxVal === undefined) {
maxVal = numVal; maxVal = numVal;
@ -479,6 +481,7 @@ export function renderAsLadderAnalog(lookup, link, wave, time) {
const { maxVal, minVal } = getMaxMinByFormat(link, wave, time, formatCode, width); const { maxVal, minVal } = getMaxMinByFormat(link, wave, time, formatCode, width);
const coordinateTransform = getMappingFunc(formatCode, maxVal, minVal); const coordinateTransform = getMappingFunc(formatCode, maxVal, minVal);
const valueRender = new JSValueRender(link, width);
function makeLadderAnalogRenderParam(link, wave, time) { function makeLadderAnalogRenderParam(link, wave, time) {
const [t1, val, mask] = wave; const [t1, val, mask] = wave;
@ -489,7 +492,7 @@ export function renderAsLadderAnalog(lookup, link, wave, time) {
} }
// 根据当前格式进行转换 // 根据当前格式进行转换
const numVal = explainAsJSNumber(formatCode, val, width); const numVal = valueRender.explainAsNumber(val);
// 此时的 y 是一个 -1 到 1 的浮点数,因为 VAO 我设置了 Int // 此时的 y 是一个 -1 到 1 的浮点数,因为 VAO 我设置了 Int
const y = coordinateTransform(numVal); const y = coordinateTransform(numVal);
const colorParam = { y, color: 5 }; const colorParam = { y, color: 5 };
@ -648,6 +651,7 @@ export function renderAsLineAnalog(lookup, link, wave, time) {
const length = wave.length; const length = wave.length;
const lineVertices = []; const lineVertices = [];
const maskVertices = []; const maskVertices = [];
const valueRender = new JSValueRender(link, width);
function makeLineAnalogRenderParam(link, wave, time) { function makeLineAnalogRenderParam(link, wave, time) {
const [t1, val, mask] = wave; const [t1, val, mask] = wave;
@ -658,7 +662,7 @@ export function renderAsLineAnalog(lookup, link, wave, time) {
} }
// 根据当前格式进行转换 // 根据当前格式进行转换
const numVal = explainAsJSNumber(formatCode, val, width); const numVal = valueRender.explainAsNumber(val);
// 此时的 y 是一个 -1 到 1 的浮点数,因为 VAO 我设置了 Int // 此时的 y 是一个 -1 到 1 的浮点数,因为 VAO 我设置了 Int
const y = coordinateTransform(numVal); const y = coordinateTransform(numVal);
const colorParam = { y, color: 5 }; const colorParam = { y, color: 5 };

View File

@ -21,6 +21,7 @@ const xOffsetUpdate = (pstate, nextOffsetXFn) => {
pstate.oldXOffset = pstate.xOffset; pstate.oldXOffset = pstate.xOffset;
pstate.xOffset = nextOffsetX; pstate.xOffset = nextOffsetX;
return true; return true;
}; };

View File

@ -6,19 +6,25 @@ const yOffsetUpdate = (pstate, nextOffsetYFn) => {
nextOffsetY = nextOffsetY; nextOffsetY = nextOffsetY;
// 当前所有信号的高度之和
const currentRenderHeight = globalLookup.currentWires.size * pstate.yStep; const currentRenderHeight = globalLookup.currentWires.size * pstate.yStep;
// 当前有效的画布高度
const canvasHeight = pstate.height - pstate.topBarHeight - pstate.botBarHeight; const canvasHeight = pstate.height - pstate.topBarHeight - pstate.botBarHeight;
// console.log(currentRenderHeight, canvasHeight);
const maxOffsetY = Math.max(-20, if (currentRenderHeight < canvasHeight) {
currentRenderHeight - canvasHeight); // maximum offset // 如果当前的信号高度小于画布的高度,则取消本次渲染
return false;
}
const maxOffsetY = Math.max(-20, currentRenderHeight - canvasHeight);
nextOffsetY = Math.min(nextOffsetY, maxOffsetY); nextOffsetY = Math.min(nextOffsetY, maxOffsetY);
const minOffsetY = -20; // minimum offset const minOffsetY = -20;
nextOffsetY = Math.max(nextOffsetY, minOffsetY); nextOffsetY = Math.max(nextOffsetY, minOffsetY);
// if (nextOffsetY === xOffset) { console.log(nextOffsetY);
// return false; // exit without scroll
// }
pstate.oldYOffset = pstate.yOffset; pstate.oldYOffset = pstate.yOffset;
pstate.yOffset = nextOffsetY; pstate.yOffset = nextOffsetY;

View File

@ -87,6 +87,12 @@
"toolbar.format.float": "Float (32bit)", "toolbar.format.float": "Float (32bit)",
"toolbar.format.double": "Double (64bit)", "toolbar.format.double": "Double (64bit)",
"toolbar.location.to-begin": "Move to Beginning",
"toolbar.location.to-end": "Move to End",
"toolbar.location.to-next-change": "Go to Next Change Edge",
"toolbar.location.to-prev-change": "Go to Previous Change Edge",
"toolbar.location.make-location": "Create New Pivot",
"current-version": "current version", "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>." "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>."
} }

View File

@ -85,7 +85,11 @@
"toolbar.format.float": "单精度32bit", "toolbar.format.float": "单精度32bit",
"toolbar.format.double": "双精度64bit", "toolbar.format.double": "双精度64bit",
"toolbar.location.to-begin": "移动至开头",
"toolbar.location.to-end": "移动至结尾",
"toolbar.location.to-next-change": "前往下一个变化的边沿",
"toolbar.location.to-prev-change": "前往上一个变化的边沿",
"toolbar.location.make-location": "创建新的信标",
"current-version": "当前版本", "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>。" "copyright": "本软件版权归 <a href=\"https://github.com/Digital-EDA\" target=\"_blank\">Digital-IDE</a> 项目组所有,欢迎 <a href=\"https://github.com/Digital-EDA/Digital-IDE\">Star</a>。"

View File

@ -96,13 +96,18 @@
/** /**
* @description * @description
* @typedef {Object} Pstate * @typedef {Object} Pstate
* @property {number} tgcd
* @property {number} width * @property {number} width
* @property {number} height * @property {number} height
* @property {number} xScale * @property {number} xScale
* @property {number} xCursor
* @property {number} xOffset * @property {number} xOffset
* @property {number} yOffset * @property {number} yOffset
* @property {number} yStep * @property {number} yStep
* @property {number} yDuty * @property {number} yDuty
* @property {number} sidebarWidth
* @property {number} topBarHeight
* @property {number} botBarHeight
*/ */
/** /**
@ -124,7 +129,7 @@
/** /**
* @description * @description
* @typedef {Object} RenderConfig * @typedef {Object} RenderConfig
* @property {'common' | 'action' | undefined} type * @property {'common' | 'action' | 'value' | undefined} type
*/ */
/** /**