waveform-analysis 0.1.36 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.js +902 -806
- package/dist/style.css +1 -1
- package/dist/types/components/annotation/WaveformAnnotationEditor.vue.d.ts +4 -0
- package/dist/types/components/annotation/useWaveformChartAnnotations.d.ts +3 -1
- package/dist/types/components/core/constants.d.ts +3 -1
- package/dist/types/components/core/useWaveformChartController.d.ts +2 -0
- package/package.json +1 -1
- package/src/App.test.ts +3 -2
- package/src/App.vue +1 -1
- package/src/components/WaveformChartView.vue +10 -1
- package/src/components/annotation/WaveformAnnotationEditor.css +35 -104
- package/src/components/annotation/WaveformAnnotationEditor.vue +87 -37
- package/src/components/annotation/components.test.ts +134 -20
- package/src/components/annotation/markup.test.ts +18 -2
- package/src/components/annotation/markup.ts +33 -0
- package/src/components/annotation/useWaveformChartAnnotations.ts +53 -12
- package/src/components/core/constants.test.ts +29 -0
- package/src/components/core/constants.ts +31 -9
- package/src/components/waveformChartCases/annotationEditingAndReprojection.test.ts +13 -3
- package/src/components/waveformChartCases/dataAndHoverPerformance.test.ts +40 -0
- package/src/components/waveformChartCases/interactionAndAnnotationCreation.test.ts +24 -14
- package/src/components/waveformChartCases/legendVisibility.test.ts +10 -2
- package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +1 -1
- package/src/components/waveformChartCases/presentationMode.test.ts +10 -2
- package/src/components/waveformChartCases/renderingStyles.test.ts +1 -1
- package/src/components/waveformChartCases/xDomainStrategy.test.ts +60 -0
package/dist/style.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.waveform-annotation-layer[data-v-7254383e]{pointer-events:none}.waveform-annotation-layer--interactive .waveform-annotation[data-v-7254383e]{pointer-events:auto;cursor:grab;touch-action:none}.waveform-annotation-layer--interactive .waveform-annotation[data-v-7254383e]:active{cursor:grabbing}.waveform-annotation__arrow[data-v-7254383e]{stroke-width:2px;stroke-linecap:round;pointer-events:none}.waveform-annotation__box[data-v-7254383e]{stroke-width:1px;rx:3}.waveform-annotation-layer--interactive .waveform-annotation__box[data-v-7254383e]{pointer-events:auto}.waveform-annotation__text[data-v-7254383e]{pointer-events:none;-webkit-user-select:none;user-select:none}.waveform-annotation-context-menu[data-v-c70c98a1]{z-index:30;background:#fff;border:1px solid #dfe5ef;border-radius:4px;min-width:112px;padding:4px;display:grid;position:absolute;box-shadow:0 4px 14px #10182829}.waveform-annotation-context-menu button[data-v-c70c98a1]{color:#344054;text-align:left;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-radius:3px;padding:7px 10px;font-size:12px}.waveform-annotation-context-menu button[data-v-c70c98a1]:hover{background:#f2f4f7}.waveform-annotation-editor[data-v-52818b45]{z-index:40;background:#10182852;place-items:center;padding:20px;animation:.16s ease-out waveform-annotation-editor-fade-in-52818b45;display:grid;position:absolute;inset:0}.waveform-annotation-editor__panel[data-v-52818b45]{color:#344054;background:#fff;border:1px solid #e4e7ec;border-radius:12px;gap:20px;width:min(440px,100%);max-height:100%;padding:22px;font-size:13px;animation:.18s ease-out waveform-annotation-editor-rise-in-52818b45;display:grid;overflow-y:auto;box-shadow:0 20px 50px #10182838}.waveform-annotation-editor__header[data-v-52818b45]{justify-content:space-between;align-items:flex-start;gap:16px;display:flex}.waveform-annotation-editor__header h2[data-v-52818b45]{color:#101828;margin:0;font-size:18px;line-height:1.3}.waveform-annotation-editor__header p[data-v-52818b45]{color:#667085;margin:5px 0 0;font-size:12px}.waveform-annotation-editor__close[data-v-52818b45]{color:#667085;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:0 0 30px;place-items:center;width:30px;height:30px;padding:0;font-size:22px;line-height:1;display:inline-grid}.waveform-annotation-editor__close[data-v-52818b45]:hover{color:#101828;background:#f2f4f7}.waveform-annotation-editor__coordinates[data-v-52818b45]{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;display:grid}.waveform-annotation-editor__coordinates span[data-v-52818b45],.waveform-annotation-editor__series[data-v-52818b45]{background:#f8fafc;border:1px solid #eaecf0;border-radius:7px;align-items:center;gap:8px;min-width:0;padding:9px 10px;display:flex}.waveform-annotation-editor__coordinates span[data-v-52818b45]{color:#667085}.waveform-annotation-editor__coordinates b[data-v-52818b45]{color:#1677ff;font-size:11px}.waveform-annotation-editor__coordinates code[data-v-52818b45]{color:#344054;text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:SFMono-Regular,Consolas,monospace;font-size:11px;overflow:hidden}.waveform-annotation-editor__series[data-v-52818b45]{gap:10px}.waveform-annotation-editor__series i[data-v-52818b45]{border:1px solid #0000001f;border-radius:2px;flex:0 0 12px;width:12px;height:12px}.waveform-annotation-editor__series-label[data-v-52818b45]{gap:1px;min-width:0;display:grid}.waveform-annotation-editor__series select[data-v-52818b45]{color:#344054;min-width:0;max-width:190px;font:inherit;background:#fff;border:1px solid #d0d5dd;border-radius:5px;margin-left:auto;padding:5px 7px}.waveform-annotation-editor__series small[data-v-52818b45]{color:#667085;font-size:10px}.waveform-annotation-editor__series b[data-v-52818b45]{color:#344054;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.waveform-annotation-editor__series code[data-v-52818b45]{color:#667085;margin-left:auto;font-size:11px}.waveform-annotation-editor__field[data-v-52818b45],.waveform-annotation-editor__color-field[data-v-52818b45]{gap:4px;display:grid}.waveform-annotation-editor__label-row[data-v-52818b45]{justify-content:space-between;align-items:center;gap:8px;display:flex}.waveform-annotation-editor__label-row b[data-v-52818b45],.waveform-annotation-editor__colors legend[data-v-52818b45]{color:#344054;font-size:12px;font-weight:600}.waveform-annotation-editor__label-row small[data-v-52818b45]{color:#98a2b3;font-size:11px}.waveform-annotation-editor textarea[data-v-52818b45]{box-sizing:border-box;color:#1d2939;width:100%;min-height:92px;font:inherit;resize:vertical;background:#fff;border:1px solid #d0d5dd;border-radius:7px;padding:10px 11px;line-height:1.5}.waveform-annotation-editor textarea[data-v-52818b45]:focus{border-color:#1677ff;outline:3px solid #1677ff24}.waveform-annotation-editor__colors[data-v-52818b45]{border:0;border-top:1px solid #eaecf0;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;min-width:0;margin:0;padding:14px 0 0;display:grid}.waveform-annotation-editor__colors legend[data-v-52818b45]{grid-column:1/-1;padding:0}.waveform-annotation-editor__color-field[data-v-52818b45]{color:#667085;text-align:left;place-items:stretch stretch;min-width:0;font-size:11px}.waveform-annotation-editor__color-field[data-v-52818b45] .vc-color-wrap{border:1px solid #cfd5df;border-radius:6px;width:100%;height:34px;margin-right:0;box-shadow:inset 0 0 0 1px #ffffff61}.waveform-annotation-editor__color-field[data-v-52818b45] .vc-color-wrap:hover{border-color:#98a2b3;box-shadow:0 0 0 3px #1677ff1f}.waveform-annotation-editor__actions[data-v-52818b45]{border-top:1px solid #eaecf0;justify-content:flex-end;gap:8px;padding-top:8px;display:flex}.waveform-annotation-editor__actions button[data-v-52818b45]{color:#475467;cursor:pointer;background:#fff;border:1px solid #d0d5dd;border-radius:6px;height:34px;padding:0 12px}.waveform-annotation-editor__actions button.is-primary[data-v-52818b45]{color:#fff;background:#1677ff;border-color:#1677ff}.waveform-annotation-editor__actions button[data-v-52818b45]:disabled{opacity:.45;cursor:not-allowed}@keyframes waveform-annotation-editor-fade-in-52818b45{0%{opacity:0}to{opacity:1}}@keyframes waveform-annotation-editor-rise-in-52818b45{0%{opacity:0;transform:translateY(8px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}@media (width<=420px){.waveform-annotation-editor[data-v-52818b45]{padding:12px}.waveform-annotation-editor__panel[data-v-52818b45]{gap:16px;padding:18px}.waveform-annotation-editor__coordinates[data-v-52818b45]{grid-template-columns:1fr}}.waveform-tooltip[data-v-1f55d6c8]{box-sizing:border-box;z-index:2;color:#505050;pointer-events:none;background:#fff;border:1px solid #e3e7eb;border-radius:4px;gap:2px;width:max-content;max-width:min(560px,100% - 16px);padding:9px 12px;font:14px/1.35 Arial,sans-serif;display:grid;position:absolute;box-shadow:0 3px 10px #10182826}.waveform-tooltip__series[data-v-1f55d6c8]{grid-template-columns:8px minmax(0,1fr);align-items:start;gap:6px;display:grid}.waveform-tooltip__series i[data-v-1f55d6c8]{border-radius:50%;flex:none;width:8px;height:8px;margin-top:4px}.waveform-tooltip__series-content[data-v-1f55d6c8]{flex-wrap:nowrap;align-items:baseline;gap:12px;min-width:0;display:flex}.waveform-tooltip__series-label[data-v-1f55d6c8]{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.waveform-tooltip__value[data-v-1f55d6c8]{white-space:nowrap;flex:none}.waveform-tooltip__series strong[data-v-1f55d6c8]{font-weight:600}.waveform-tooltip__value[data-v-1f55d6c8]{color:#555}.waveform-tooltip__series small[data-v-1f55d6c8]{color:#667085}.waveform-track__line[data-v-42a3fd47]{fill:none;stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round}.waveform-track__error-bar[data-v-42a3fd47]{fill:none}.waveform-track__point[data-v-42a3fd47],.waveform-track__error-bar[data-v-42a3fd47]{pointer-events:none}.waveform-track{isolation:isolate;pointer-events:none}.waveform-track__y-axis-label-bg{fill:#fff;opacity:.9;pointer-events:none}.waveform-track__y-axis-label{pointer-events:none;font-size:12px;font-weight:500}.waveform-track__grid{pointer-events:none}.waveform-track__grid--major line{stroke:#dfe5ef;stroke-width:1px}.waveform-track__grid--minor line{stroke:#f2f5fa;stroke-width:1px}.waveform-track__plot-frame,.waveform-track__plot-background{pointer-events:none}.waveform-track__watermark{fill:#1677ff1a;pointer-events:none;-webkit-user-select:none;user-select:none;font-family:Consolas,Monaco,Courier New,monospace}.waveform-track__overlay{fill:#0000;cursor:crosshair;pointer-events:all;touch-action:none}.waveform-track__no-visible-series{fill:#8c8c8c;pointer-events:none;font:13px sans-serif}.waveform-track__overlay.is-zoomable{cursor:grab}.waveform-track__overlay.is-zoomable:active{cursor:grabbing}.waveform-track__overlay.is-annotating{cursor:crosshair}.waveform-track__overlay.is-presentation{cursor:default;pointer-events:none}.waveform-track__zero-line{fill:none;pointer-events:none}.waveform-track__axis-endpoint{fill:#667085;pointer-events:none;font-size:11px}.waveform-track__axis-exponent{fill:#666;font-family:sans-serif;font-size:10px}.waveform-track__axis path,.waveform-track__axis line{stroke:#1f2937}.waveform-track__axis text{fill:#667085;font-size:11px}.waveform-legend[data-v-2ae12e71]{pointer-events:none;overflow:hidden}.waveform-legend__viewport[data-v-2ae12e71]{box-sizing:border-box;width:100%;height:100%;padding:8px;display:flex;overflow:hidden}.waveform-legend__viewport--top-left[data-v-2ae12e71]{justify-content:flex-start;align-items:flex-start}.waveform-legend__viewport--top[data-v-2ae12e71]{justify-content:center;align-items:flex-start}.waveform-legend__viewport--top-right[data-v-2ae12e71]{justify-content:flex-end;align-items:flex-start}.waveform-legend__viewport--right[data-v-2ae12e71]{justify-content:flex-end;align-items:center}.waveform-legend__viewport--bottom-right[data-v-2ae12e71]{justify-content:flex-end;align-items:flex-end}.waveform-legend__viewport--bottom[data-v-2ae12e71]{justify-content:center;align-items:flex-end}.waveform-legend__viewport--bottom-left[data-v-2ae12e71]{justify-content:flex-start;align-items:flex-end}.waveform-legend__viewport--left[data-v-2ae12e71]{justify-content:flex-start;align-items:center}.waveform-legend__panel[data-v-2ae12e71]{color:#344054;border:1px solid #d0d5dde6;border-radius:4px;flex:0 auto;gap:5px 12px;max-width:100%;max-height:100%;padding:5px 7px;font:12px/1.35 sans-serif;display:flex;overflow:hidden}.waveform-legend__panel--interactive[data-v-2ae12e71]{pointer-events:auto}.waveform-legend__panel--horizontal[data-v-2ae12e71]{flex-flow:wrap;align-items:center}.waveform-legend__panel--vertical[data-v-2ae12e71]{flex-flow:column;align-items:stretch}.waveform-legend__item[data-v-2ae12e71]{min-width:0;max-width:160px;color:inherit;font:inherit;text-align:left;white-space:nowrap;appearance:none;background:0 0;border:0;align-items:center;gap:6px;padding:0;display:flex}.waveform-legend__item[data-v-2ae12e71]:disabled{opacity:1}.waveform-legend__panel--interactive .waveform-legend__item[data-v-2ae12e71]{cursor:pointer}.waveform-legend__panel--interactive .waveform-legend__item[data-v-2ae12e71]:focus-visible{outline-offset:2px;outline:2px solid #1677ff}.waveform-legend__item.is-hidden[data-v-2ae12e71]{opacity:.45}.waveform-legend__item.is-hidden .waveform-legend__label[data-v-2ae12e71]{text-decoration:line-through}.waveform-legend__swatch[data-v-2ae12e71]{stroke-linecap:round;stroke-linejoin:round;flex:0 0 26px;width:26px;height:16px;overflow:visible}.waveform-legend__label[data-v-2ae12e71]{text-overflow:ellipsis;min-width:0;overflow:hidden}.waveform-track__crosshair[data-v-a6f82099]{pointer-events:none}.waveform-track__crosshair line[data-v-a6f82099]{stroke:#57617b;stroke-width:1px;stroke-dasharray:4 3}.waveform-chart{box-sizing:border-box;color:#475467;background:#fff;border:1px solid #00000014;border-radius:6px;min-width:0;min-height:180px;position:relative;overflow:hidden}.waveform-chart--clean{border-color:#0000}.waveform-chart__pagination{z-index:2;position:absolute;bottom:6px;right:10px}.waveform-chart__title-area{background:#fff;align-items:center;width:100%;min-width:0;padding:0 24px;display:flex;position:relative;overflow:hidden}.waveform-chart__title-measure{visibility:hidden;pointer-events:none;display:block;position:absolute}.waveform-chart__title-visual{flex:none;min-width:0;position:relative;overflow:visible}.waveform-chart__title-text{transform-origin:50%;line-height:1.2;display:block;position:absolute;top:50%;left:50%;overflow:visible}.waveform-chart__pagination .ant-pagination-item,.waveform-chart__pagination .ant-pagination-prev .ant-pagination-item-link,.waveform-chart__pagination .ant-pagination-next .ant-pagination-item-link{background:#fff;border-color:#d9d9d9}.waveform-chart__pagination .ant-pagination-item-active{border-color:#1677ff}.waveform-chart__grid-slot-placeholder{fill:#fafbfc;stroke:#e4e7ec;stroke-dasharray:4 4;pointer-events:none}.waveform-chart__svg{max-width:100%;display:block}.waveform-chart__overlay{fill:#0000;cursor:crosshair;touch-action:none}.waveform-chart__overlay.is-zoomable{cursor:crosshair}.waveform-chart--panning .waveform-chart__overlay.is-zoomable{cursor:grabbing}.waveform-chart__zoom-selection{fill:#1677ff24;stroke:#1677ff;stroke-width:1px;pointer-events:none}.waveform-chart__overlay.is-annotating{cursor:crosshair}.waveform-chart--presentation .waveform-chart__overlay{cursor:default;pointer-events:none}.waveform-chart__label,.waveform-chart__empty{fill:#595959;font-size:12px}
|
|
1
|
+
.waveform-annotation-layer[data-v-7254383e]{pointer-events:none}.waveform-annotation-layer--interactive .waveform-annotation[data-v-7254383e]{pointer-events:auto;cursor:grab;touch-action:none}.waveform-annotation-layer--interactive .waveform-annotation[data-v-7254383e]:active{cursor:grabbing}.waveform-annotation__arrow[data-v-7254383e]{stroke-width:2px;stroke-linecap:round;pointer-events:none}.waveform-annotation__box[data-v-7254383e]{stroke-width:1px;rx:3}.waveform-annotation-layer--interactive .waveform-annotation__box[data-v-7254383e]{pointer-events:auto}.waveform-annotation__text[data-v-7254383e]{pointer-events:none;-webkit-user-select:none;user-select:none}.waveform-annotation-context-menu[data-v-c70c98a1]{z-index:30;background:#fff;border:1px solid #dfe5ef;border-radius:4px;min-width:112px;padding:4px;display:grid;position:absolute;box-shadow:0 4px 14px #10182829}.waveform-annotation-context-menu button[data-v-c70c98a1]{color:#344054;text-align:left;white-space:nowrap;cursor:pointer;background:0 0;border:0;border-radius:3px;padding:7px 10px;font-size:12px}.waveform-annotation-context-menu button[data-v-c70c98a1]:hover{background:#f2f4f7}.waveform-annotation-editor__content[data-v-8ce79dc8]{color:#344054;gap:20px;font-size:13px;display:grid}.waveform-annotation-editor__coordinates[data-v-8ce79dc8]{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;display:grid}.waveform-annotation-editor__coordinates span[data-v-8ce79dc8],.waveform-annotation-editor__series[data-v-8ce79dc8]{background:#f8fafc;border:1px solid #eaecf0;border-radius:7px;align-items:center;gap:8px;min-width:0;padding:9px 10px;display:flex}.waveform-annotation-editor__coordinates span[data-v-8ce79dc8]{color:#667085}.waveform-annotation-editor__coordinate-input[data-v-8ce79dc8]{color:#667085;background:#f8fafc;border:1px solid #eaecf0;border-radius:7px;align-items:center;gap:8px;min-width:0;padding:9px 10px;display:flex}.waveform-annotation-editor__coordinate-input[data-v-8ce79dc8] .ant-input-number{color:#344054;width:auto;min-width:96px;font-family:SFMono-Regular,Consolas,monospace}.waveform-annotation-editor__coordinate-value[data-v-8ce79dc8]{display:none}.waveform-annotation-editor__coordinate-error[data-v-8ce79dc8]{color:#d92d20;grid-column:1/-1;margin:-12px 0 0;font-size:11px;line-height:1.4}.waveform-annotation-editor__coordinate-hint[data-v-8ce79dc8]{color:#98a2b3;margin:-12px 0 0;font-size:11px;line-height:1.4}.waveform-annotation-editor__coordinates b[data-v-8ce79dc8]{color:#1677ff;font-size:11px}.waveform-annotation-editor__coordinates code[data-v-8ce79dc8]{color:#344054;text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:SFMono-Regular,Consolas,monospace;font-size:11px;overflow:hidden}.waveform-annotation-editor__series[data-v-8ce79dc8]{gap:10px}.waveform-annotation-editor__series i[data-v-8ce79dc8]{border:1px solid #0000001f;border-radius:2px;flex:0 0 12px;width:12px;height:12px}.waveform-annotation-editor__series-label[data-v-8ce79dc8]{gap:1px;min-width:0;display:grid}.waveform-annotation-editor__series select[data-v-8ce79dc8]{color:#344054;min-width:0;max-width:190px;font:inherit;background:#fff;border:1px solid #d0d5dd;border-radius:5px;margin-left:auto;padding:5px 7px}.waveform-annotation-editor__series small[data-v-8ce79dc8]{color:#667085;font-size:10px}.waveform-annotation-editor__series b[data-v-8ce79dc8]{color:#344054;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.waveform-annotation-editor__series code[data-v-8ce79dc8]{color:#667085;margin-left:auto;font-size:11px}.waveform-annotation-editor__field[data-v-8ce79dc8],.waveform-annotation-editor__color-field[data-v-8ce79dc8]{gap:4px;display:grid}.waveform-annotation-editor__label-row[data-v-8ce79dc8]{justify-content:space-between;align-items:center;gap:8px;display:flex}.waveform-annotation-editor__label-row b[data-v-8ce79dc8],.waveform-annotation-editor__colors legend[data-v-8ce79dc8]{color:#344054;font-size:12px;font-weight:600}.waveform-annotation-editor__label-row small[data-v-8ce79dc8]{color:#98a2b3;font-size:11px}.waveform-annotation-editor textarea[data-v-8ce79dc8]{box-sizing:border-box;color:#1d2939;width:100%;min-height:92px;font:inherit;resize:vertical;background:#fff;border:1px solid #d0d5dd;border-radius:7px;padding:10px 11px;line-height:1.5}.waveform-annotation-editor textarea[data-v-8ce79dc8]:focus{border-color:#1677ff;outline:3px solid #1677ff24}.waveform-annotation-editor__colors[data-v-8ce79dc8]{border:0;border-top:1px solid #eaecf0;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;min-width:0;margin:0;padding:14px 0 0;display:grid}.waveform-annotation-editor__colors legend[data-v-8ce79dc8]{grid-column:1/-1;padding:0}.waveform-annotation-editor__color-field[data-v-8ce79dc8]{color:#667085;text-align:left;place-items:stretch stretch;min-width:0;font-size:11px}.waveform-annotation-editor__color-field[data-v-8ce79dc8] .vc-color-wrap{border:1px solid #cfd5df;border-radius:6px;width:100%;height:34px;margin-right:0;box-shadow:inset 0 0 0 1px #ffffff61}.waveform-annotation-editor__color-field[data-v-8ce79dc8] .vc-color-wrap:hover{border-color:#98a2b3;box-shadow:0 0 0 3px #1677ff1f}@media (width<=420px){.waveform-annotation-editor__content[data-v-8ce79dc8]{gap:16px}.waveform-annotation-editor__coordinates[data-v-8ce79dc8]{grid-template-columns:1fr}}.waveform-tooltip[data-v-1f55d6c8]{box-sizing:border-box;z-index:2;color:#505050;pointer-events:none;background:#fff;border:1px solid #e3e7eb;border-radius:4px;gap:2px;width:max-content;max-width:min(560px,100% - 16px);padding:9px 12px;font:14px/1.35 Arial,sans-serif;display:grid;position:absolute;box-shadow:0 3px 10px #10182826}.waveform-tooltip__series[data-v-1f55d6c8]{grid-template-columns:8px minmax(0,1fr);align-items:start;gap:6px;display:grid}.waveform-tooltip__series i[data-v-1f55d6c8]{border-radius:50%;flex:none;width:8px;height:8px;margin-top:4px}.waveform-tooltip__series-content[data-v-1f55d6c8]{flex-wrap:nowrap;align-items:baseline;gap:12px;min-width:0;display:flex}.waveform-tooltip__series-label[data-v-1f55d6c8]{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.waveform-tooltip__value[data-v-1f55d6c8]{white-space:nowrap;flex:none}.waveform-tooltip__series strong[data-v-1f55d6c8]{font-weight:600}.waveform-tooltip__value[data-v-1f55d6c8]{color:#555}.waveform-tooltip__series small[data-v-1f55d6c8]{color:#667085}.waveform-track__line[data-v-42a3fd47]{fill:none;stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round}.waveform-track__error-bar[data-v-42a3fd47]{fill:none}.waveform-track__point[data-v-42a3fd47],.waveform-track__error-bar[data-v-42a3fd47]{pointer-events:none}.waveform-track{isolation:isolate;pointer-events:none}.waveform-track__y-axis-label-bg{fill:#fff;opacity:.9;pointer-events:none}.waveform-track__y-axis-label{pointer-events:none;font-size:12px;font-weight:500}.waveform-track__grid{pointer-events:none}.waveform-track__grid--major line{stroke:#dfe5ef;stroke-width:1px}.waveform-track__grid--minor line{stroke:#f2f5fa;stroke-width:1px}.waveform-track__plot-frame,.waveform-track__plot-background{pointer-events:none}.waveform-track__watermark{fill:#1677ff1a;pointer-events:none;-webkit-user-select:none;user-select:none;font-family:Consolas,Monaco,Courier New,monospace}.waveform-track__overlay{fill:#0000;cursor:crosshair;pointer-events:all;touch-action:none}.waveform-track__no-visible-series{fill:#8c8c8c;pointer-events:none;font:13px sans-serif}.waveform-track__overlay.is-zoomable{cursor:grab}.waveform-track__overlay.is-zoomable:active{cursor:grabbing}.waveform-track__overlay.is-annotating{cursor:crosshair}.waveform-track__overlay.is-presentation{cursor:default;pointer-events:none}.waveform-track__zero-line{fill:none;pointer-events:none}.waveform-track__axis-endpoint{fill:#667085;pointer-events:none;font-size:11px}.waveform-track__axis-exponent{fill:#666;font-family:sans-serif;font-size:10px}.waveform-track__axis path,.waveform-track__axis line{stroke:#1f2937}.waveform-track__axis text{fill:#667085;font-size:11px}.waveform-legend[data-v-2ae12e71]{pointer-events:none;overflow:hidden}.waveform-legend__viewport[data-v-2ae12e71]{box-sizing:border-box;width:100%;height:100%;padding:8px;display:flex;overflow:hidden}.waveform-legend__viewport--top-left[data-v-2ae12e71]{justify-content:flex-start;align-items:flex-start}.waveform-legend__viewport--top[data-v-2ae12e71]{justify-content:center;align-items:flex-start}.waveform-legend__viewport--top-right[data-v-2ae12e71]{justify-content:flex-end;align-items:flex-start}.waveform-legend__viewport--right[data-v-2ae12e71]{justify-content:flex-end;align-items:center}.waveform-legend__viewport--bottom-right[data-v-2ae12e71]{justify-content:flex-end;align-items:flex-end}.waveform-legend__viewport--bottom[data-v-2ae12e71]{justify-content:center;align-items:flex-end}.waveform-legend__viewport--bottom-left[data-v-2ae12e71]{justify-content:flex-start;align-items:flex-end}.waveform-legend__viewport--left[data-v-2ae12e71]{justify-content:flex-start;align-items:center}.waveform-legend__panel[data-v-2ae12e71]{color:#344054;border:1px solid #d0d5dde6;border-radius:4px;flex:0 auto;gap:5px 12px;max-width:100%;max-height:100%;padding:5px 7px;font:12px/1.35 sans-serif;display:flex;overflow:hidden}.waveform-legend__panel--interactive[data-v-2ae12e71]{pointer-events:auto}.waveform-legend__panel--horizontal[data-v-2ae12e71]{flex-flow:wrap;align-items:center}.waveform-legend__panel--vertical[data-v-2ae12e71]{flex-flow:column;align-items:stretch}.waveform-legend__item[data-v-2ae12e71]{min-width:0;max-width:160px;color:inherit;font:inherit;text-align:left;white-space:nowrap;appearance:none;background:0 0;border:0;align-items:center;gap:6px;padding:0;display:flex}.waveform-legend__item[data-v-2ae12e71]:disabled{opacity:1}.waveform-legend__panel--interactive .waveform-legend__item[data-v-2ae12e71]{cursor:pointer}.waveform-legend__panel--interactive .waveform-legend__item[data-v-2ae12e71]:focus-visible{outline-offset:2px;outline:2px solid #1677ff}.waveform-legend__item.is-hidden[data-v-2ae12e71]{opacity:.45}.waveform-legend__item.is-hidden .waveform-legend__label[data-v-2ae12e71]{text-decoration:line-through}.waveform-legend__swatch[data-v-2ae12e71]{stroke-linecap:round;stroke-linejoin:round;flex:0 0 26px;width:26px;height:16px;overflow:visible}.waveform-legend__label[data-v-2ae12e71]{text-overflow:ellipsis;min-width:0;overflow:hidden}.waveform-track__crosshair[data-v-a6f82099]{pointer-events:none}.waveform-track__crosshair line[data-v-a6f82099]{stroke:#57617b;stroke-width:1px;stroke-dasharray:4 3}.waveform-chart{box-sizing:border-box;color:#475467;background:#fff;border:1px solid #00000014;border-radius:6px;min-width:0;min-height:180px;position:relative;overflow:hidden}.waveform-chart--clean{border-color:#0000}.waveform-chart__pagination{z-index:2;position:absolute;bottom:6px;right:10px}.waveform-chart__title-area{background:#fff;align-items:center;width:100%;min-width:0;padding:0 24px;display:flex;position:relative;overflow:hidden}.waveform-chart__title-measure{visibility:hidden;pointer-events:none;display:block;position:absolute}.waveform-chart__title-visual{flex:none;min-width:0;position:relative;overflow:visible}.waveform-chart__title-text{transform-origin:50%;line-height:1.2;display:block;position:absolute;top:50%;left:50%;overflow:visible}.waveform-chart__pagination .ant-pagination-item,.waveform-chart__pagination .ant-pagination-prev .ant-pagination-item-link,.waveform-chart__pagination .ant-pagination-next .ant-pagination-item-link{background:#fff;border-color:#d9d9d9}.waveform-chart__pagination .ant-pagination-item-active{border-color:#1677ff}.waveform-chart__grid-slot-placeholder{fill:#fafbfc;stroke:#e4e7ec;stroke-dasharray:4 4;pointer-events:none}.waveform-chart__svg{max-width:100%;display:block}.waveform-chart__overlay{fill:#0000;cursor:crosshair;touch-action:none}.waveform-chart__overlay.is-zoomable{cursor:crosshair}.waveform-chart--panning .waveform-chart__overlay.is-zoomable{cursor:grabbing}.waveform-chart__zoom-selection{fill:#1677ff24;stroke:#1677ff;stroke-width:1px;pointer-events:none}.waveform-chart__overlay.is-annotating{cursor:crosshair}.waveform-chart--presentation .waveform-chart__overlay{cursor:default;pointer-events:none}.waveform-chart__label,.waveform-chart__empty{fill:#595959;font-size:12px}
|
|
2
2
|
/*$vite$:1*/
|
|
@@ -8,17 +8,21 @@ interface Props {
|
|
|
8
8
|
series?: AnnotationSeriesInfo;
|
|
9
9
|
seriesOptions?: AnnotationSeriesCandidate[];
|
|
10
10
|
timeUnit?: TimeUnit;
|
|
11
|
+
timeError?: string;
|
|
11
12
|
}
|
|
12
13
|
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
13
14
|
cancel: () => any;
|
|
14
15
|
confirm: (annotation: WaveformAnnotation) => any;
|
|
15
16
|
"series-change": (seriesId: string) => any;
|
|
17
|
+
"time-change": (displayValue: string) => any;
|
|
16
18
|
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
17
19
|
onCancel?: (() => any) | undefined;
|
|
18
20
|
onConfirm?: ((annotation: WaveformAnnotation) => any) | undefined;
|
|
19
21
|
"onSeries-change"?: ((seriesId: string) => any) | undefined;
|
|
22
|
+
"onTime-change"?: ((displayValue: string) => any) | undefined;
|
|
20
23
|
}>, {
|
|
21
24
|
timeUnit: TimeUnit;
|
|
25
|
+
timeError: string;
|
|
22
26
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
27
|
declare const _default: typeof __VLS_export;
|
|
24
28
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ScaleLinear } from 'd3';
|
|
2
|
-
import type
|
|
2
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
3
3
|
import type { WaveformAnnotation, WaveformInteractionMode } from '../data/types';
|
|
4
4
|
import type { DisplaySeries, TrackLayout } from '../core/types';
|
|
5
5
|
import type { ResolvedWaveformChartProps, WaveformChartEmit } from '../core/waveformChartTypes';
|
|
@@ -29,6 +29,8 @@ interface AnnotationContext {
|
|
|
29
29
|
export declare function useWaveformChartAnnotations(context: AnnotationContext): {
|
|
30
30
|
toggleSeriesVisibility: (seriesId: string) => void;
|
|
31
31
|
changeDraftSeries: (seriesId: string) => void;
|
|
32
|
+
changeDraftTime: (displayValue: string) => void;
|
|
33
|
+
timeError: Ref<string, string>;
|
|
32
34
|
cancelAnnotation: () => void;
|
|
33
35
|
resolveTrackAtPointer: (pointerX: number, pointerY: number, trackIndex?: number) => TrackLayout | undefined;
|
|
34
36
|
handleAnnotationClick: (event: MouseEvent, trackIndex?: number) => void;
|
|
@@ -97,7 +97,9 @@ export declare const TITLE_CHAR_WIDTH_RATIO = 0.62;
|
|
|
97
97
|
*/
|
|
98
98
|
export declare const TITLE_LINE_HEIGHT = 1.2;
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
100
|
+
* 多系列波形的默认颜色列表。
|
|
101
|
+
*
|
|
102
|
+
* 颜色保持较深并具备足够辨识度,避免大量系列同时绘制时使用浅色导致线条难以观察。
|
|
101
103
|
*/
|
|
102
104
|
export declare const channelColors: string[];
|
|
103
105
|
/**
|
|
@@ -231,6 +231,8 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
|
|
|
231
231
|
requestViewportReset: (event: MouseEvent) => void;
|
|
232
232
|
toggleSeriesVisibility: (seriesId: string) => void;
|
|
233
233
|
changeDraftSeries: (seriesId: string) => void;
|
|
234
|
+
changeDraftTime: (displayValue: string) => void;
|
|
235
|
+
timeError: string;
|
|
234
236
|
cancelAnnotation: () => void;
|
|
235
237
|
resolveTrackAtPointer: (pointerX: number, pointerY: number, trackIndex?: number) => import("./types").TrackLayout | undefined;
|
|
236
238
|
handleAnnotationClick: (event: MouseEvent, trackIndex?: number) => void;
|
package/package.json
CHANGED
package/src/App.test.ts
CHANGED
|
@@ -321,8 +321,9 @@ describe('App workspace layout', { timeout: 20_000 }, () => {
|
|
|
321
321
|
const styleSelect = frameControls.findAllComponents(Select)[0]
|
|
322
322
|
|
|
323
323
|
expect(colorPickers).toHaveLength(2)
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
|
|
325
|
+
const initialFrames = wrapper.findAll('.waveform-chart__plot-frame')
|
|
326
|
+
expect(initialFrames.length > 1 && initialFrames.every((frame) => frame.attributes('stroke-width') === '2')).toBe(true)
|
|
326
327
|
|
|
327
328
|
colorPickers[0].vm.$emit('update:pureColor', 'rgba(220, 38, 38, 0.8)')
|
|
328
329
|
colorPickers[1].vm.$emit('update:pureColor', 'rgba(14, 165, 233, 0.25)')
|
package/src/App.vue
CHANGED
|
@@ -32,7 +32,7 @@ const overlayMode = ref<WaveformOverlayMode>('single-axis')
|
|
|
32
32
|
const rowCount = ref(4)
|
|
33
33
|
const columnCount = ref(1)
|
|
34
34
|
const frameBorderColor = ref('#1f2937')
|
|
35
|
-
const frameBorderWidth = ref(
|
|
35
|
+
const frameBorderWidth = ref(2)
|
|
36
36
|
const frameBorderStyle = ref<NonNullable<WaveformFrameStyle['borderStyle']>>('solid')
|
|
37
37
|
const frameBackgroundColor = ref('rgba(255, 255, 255, 0)')
|
|
38
38
|
const frameWatermarkVisible = ref(true)
|
|
@@ -87,9 +87,11 @@ const {
|
|
|
87
87
|
contextMenu,
|
|
88
88
|
editorSeries,
|
|
89
89
|
editorSeriesOptions,
|
|
90
|
+
timeError,
|
|
90
91
|
confirmAnnotation,
|
|
91
92
|
cancelAnnotation,
|
|
92
93
|
changeDraftSeries,
|
|
94
|
+
changeDraftTime,
|
|
93
95
|
editContextAnnotation,
|
|
94
96
|
deleteContextAnnotation,
|
|
95
97
|
chartHeight,
|
|
@@ -98,6 +100,11 @@ const {
|
|
|
98
100
|
setTitleMeasureElement,
|
|
99
101
|
setSharedOverlayElement,
|
|
100
102
|
} = toRefs(props.controller)
|
|
103
|
+
|
|
104
|
+
function handleChartPointerLeave() {
|
|
105
|
+
pointerInsideChart.value = false
|
|
106
|
+
handlePointerLeave.value()
|
|
107
|
+
}
|
|
101
108
|
</script>
|
|
102
109
|
|
|
103
110
|
<template>
|
|
@@ -123,7 +130,7 @@ const {
|
|
|
123
130
|
:data-plot-margin-bottom="resolvedPlotMargin.bottom"
|
|
124
131
|
:data-title-area-height="titleAreaHeight"
|
|
125
132
|
@pointerenter="pointerInsideChart = true"
|
|
126
|
-
@pointerleave="
|
|
133
|
+
@pointerleave="handleChartPointerLeave"
|
|
127
134
|
@contextmenu.capture="handleNativeContextMenu"
|
|
128
135
|
>
|
|
129
136
|
<div
|
|
@@ -332,9 +339,11 @@ const {
|
|
|
332
339
|
:series="editorSeries"
|
|
333
340
|
:series-options="editorSeriesOptions"
|
|
334
341
|
:time-unit="timeUnit"
|
|
342
|
+
:time-error="timeError"
|
|
335
343
|
@confirm="confirmAnnotation"
|
|
336
344
|
@cancel="cancelAnnotation"
|
|
337
345
|
@series-change="changeDraftSeries"
|
|
346
|
+
@time-change="changeDraftTime"
|
|
338
347
|
/>
|
|
339
348
|
|
|
340
349
|
<WaveformAnnotationContextMenu
|
|
@@ -1,63 +1,8 @@
|
|
|
1
|
-
.waveform-annotation-
|
|
2
|
-
position: absolute;
|
|
3
|
-
inset: 0;
|
|
4
|
-
z-index: 40;
|
|
5
|
-
display: grid;
|
|
6
|
-
place-items: center;
|
|
7
|
-
padding: 20px;
|
|
8
|
-
background: rgb(16 24 40 / 32%);
|
|
9
|
-
animation: waveform-annotation-editor-fade-in 160ms ease-out;
|
|
10
|
-
}
|
|
11
|
-
.waveform-annotation-editor__panel {
|
|
1
|
+
.waveform-annotation-editor__content {
|
|
12
2
|
display: grid;
|
|
13
3
|
gap: 20px;
|
|
14
|
-
width: min(440px, 100%);
|
|
15
|
-
max-height: 100%;
|
|
16
|
-
overflow-y: auto;
|
|
17
|
-
padding: 22px;
|
|
18
4
|
color: #344054;
|
|
19
5
|
font-size: 13px;
|
|
20
|
-
background: #fff;
|
|
21
|
-
border: 1px solid #e4e7ec;
|
|
22
|
-
border-radius: 12px;
|
|
23
|
-
box-shadow: 0 20px 50px rgb(16 24 40 / 22%);
|
|
24
|
-
animation: waveform-annotation-editor-rise-in 180ms ease-out;
|
|
25
|
-
}
|
|
26
|
-
.waveform-annotation-editor__header {
|
|
27
|
-
display: flex;
|
|
28
|
-
align-items: flex-start;
|
|
29
|
-
justify-content: space-between;
|
|
30
|
-
gap: 16px;
|
|
31
|
-
}
|
|
32
|
-
.waveform-annotation-editor__header h2 {
|
|
33
|
-
margin: 0;
|
|
34
|
-
color: #101828;
|
|
35
|
-
font-size: 18px;
|
|
36
|
-
line-height: 1.3;
|
|
37
|
-
}
|
|
38
|
-
.waveform-annotation-editor__header p {
|
|
39
|
-
margin: 5px 0 0;
|
|
40
|
-
color: #667085;
|
|
41
|
-
font-size: 12px;
|
|
42
|
-
}
|
|
43
|
-
.waveform-annotation-editor__close {
|
|
44
|
-
display: inline-grid;
|
|
45
|
-
flex: 0 0 30px;
|
|
46
|
-
width: 30px;
|
|
47
|
-
height: 30px;
|
|
48
|
-
padding: 0;
|
|
49
|
-
place-items: center;
|
|
50
|
-
color: #667085;
|
|
51
|
-
font-size: 22px;
|
|
52
|
-
line-height: 1;
|
|
53
|
-
background: transparent;
|
|
54
|
-
border: 0;
|
|
55
|
-
border-radius: 6px;
|
|
56
|
-
cursor: pointer;
|
|
57
|
-
}
|
|
58
|
-
.waveform-annotation-editor__close:hover {
|
|
59
|
-
color: #101828;
|
|
60
|
-
background: #f2f4f7;
|
|
61
6
|
}
|
|
62
7
|
.waveform-annotation-editor__coordinates {
|
|
63
8
|
display: grid;
|
|
@@ -78,6 +23,39 @@
|
|
|
78
23
|
.waveform-annotation-editor__coordinates span {
|
|
79
24
|
color: #667085;
|
|
80
25
|
}
|
|
26
|
+
.waveform-annotation-editor__coordinate-input {
|
|
27
|
+
display: flex;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 8px;
|
|
31
|
+
padding: 9px 10px;
|
|
32
|
+
color: #667085;
|
|
33
|
+
background: #f8fafc;
|
|
34
|
+
border: 1px solid #eaecf0;
|
|
35
|
+
border-radius: 7px;
|
|
36
|
+
}
|
|
37
|
+
.waveform-annotation-editor__coordinate-input :deep(.ant-input-number) {
|
|
38
|
+
width: auto;
|
|
39
|
+
min-width: 96px;
|
|
40
|
+
color: #344054;
|
|
41
|
+
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
42
|
+
}
|
|
43
|
+
.waveform-annotation-editor__coordinate-value {
|
|
44
|
+
display: none;
|
|
45
|
+
}
|
|
46
|
+
.waveform-annotation-editor__coordinate-error {
|
|
47
|
+
grid-column: 1 / -1;
|
|
48
|
+
margin: -12px 0 0;
|
|
49
|
+
color: #d92d20;
|
|
50
|
+
font-size: 11px;
|
|
51
|
+
line-height: 1.4;
|
|
52
|
+
}
|
|
53
|
+
.waveform-annotation-editor__coordinate-hint {
|
|
54
|
+
margin: -12px 0 0;
|
|
55
|
+
color: #98a2b3;
|
|
56
|
+
font-size: 11px;
|
|
57
|
+
line-height: 1.4;
|
|
58
|
+
}
|
|
81
59
|
.waveform-annotation-editor__coordinates b {
|
|
82
60
|
color: #1677ff;
|
|
83
61
|
font-size: 11px;
|
|
@@ -205,56 +183,9 @@
|
|
|
205
183
|
border-color: #98a2b3;
|
|
206
184
|
box-shadow: 0 0 0 3px rgb(22 119 255 / 12%);
|
|
207
185
|
}
|
|
208
|
-
.waveform-annotation-editor__actions {
|
|
209
|
-
display: flex;
|
|
210
|
-
justify-content: flex-end;
|
|
211
|
-
gap: 8px;
|
|
212
|
-
padding-top: 8px;
|
|
213
|
-
border-top: 1px solid #eaecf0;
|
|
214
|
-
}
|
|
215
|
-
.waveform-annotation-editor__actions button {
|
|
216
|
-
height: 34px;
|
|
217
|
-
padding: 0 12px;
|
|
218
|
-
color: #475467;
|
|
219
|
-
background: #fff;
|
|
220
|
-
border: 1px solid #d0d5dd;
|
|
221
|
-
border-radius: 6px;
|
|
222
|
-
cursor: pointer;
|
|
223
|
-
}
|
|
224
|
-
.waveform-annotation-editor__actions button.is-primary {
|
|
225
|
-
color: #fff;
|
|
226
|
-
background: #1677ff;
|
|
227
|
-
border-color: #1677ff;
|
|
228
|
-
}
|
|
229
|
-
.waveform-annotation-editor__actions button:disabled {
|
|
230
|
-
opacity: 0.45;
|
|
231
|
-
cursor: not-allowed;
|
|
232
|
-
}
|
|
233
|
-
@keyframes waveform-annotation-editor-fade-in {
|
|
234
|
-
from {
|
|
235
|
-
opacity: 0;
|
|
236
|
-
}
|
|
237
|
-
to {
|
|
238
|
-
opacity: 1;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
@keyframes waveform-annotation-editor-rise-in {
|
|
242
|
-
from {
|
|
243
|
-
opacity: 0;
|
|
244
|
-
transform: translateY(8px) scale(0.98);
|
|
245
|
-
}
|
|
246
|
-
to {
|
|
247
|
-
opacity: 1;
|
|
248
|
-
transform: translateY(0) scale(1);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
186
|
@media (max-width: 420px) {
|
|
252
|
-
.waveform-annotation-
|
|
253
|
-
padding: 12px;
|
|
254
|
-
}
|
|
255
|
-
.waveform-annotation-editor__panel {
|
|
187
|
+
.waveform-annotation-editor__content {
|
|
256
188
|
gap: 16px;
|
|
257
|
-
padding: 18px;
|
|
258
189
|
}
|
|
259
190
|
.waveform-annotation-editor__coordinates {
|
|
260
191
|
grid-template-columns: 1fr;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
3
|
+
import { InputNumber, Modal } from 'ant-design-vue'
|
|
3
4
|
import { ColorPicker } from 'vue3-colorpicker'
|
|
4
5
|
import 'vue3-colorpicker/style.css'
|
|
5
6
|
|
|
@@ -15,24 +16,44 @@ interface Props {
|
|
|
15
16
|
series?: AnnotationSeriesInfo
|
|
16
17
|
seriesOptions?: AnnotationSeriesCandidate[]
|
|
17
18
|
timeUnit?: TimeUnit
|
|
19
|
+
timeError?: string
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
const props = withDefaults(defineProps<Props>(), {
|
|
21
23
|
timeUnit: 'ms',
|
|
24
|
+
timeError: '',
|
|
22
25
|
})
|
|
23
26
|
const emit = defineEmits<{
|
|
24
27
|
(event: 'confirm', annotation: WaveformAnnotation): void
|
|
25
28
|
(event: 'cancel'): void
|
|
26
29
|
(event: 'series-change', seriesId: string): void
|
|
30
|
+
(event: 'time-change', displayValue: string): void
|
|
27
31
|
}>()
|
|
28
32
|
|
|
29
33
|
const textarea = ref<HTMLTextAreaElement>()
|
|
30
34
|
const dialogTitleId = useWaveformInstanceId('waveform-annotation-editor-title')
|
|
31
35
|
const text = ref('')
|
|
36
|
+
const timeInput = ref('')
|
|
37
|
+
const timeValidationRequested = ref(false)
|
|
32
38
|
const borderColor = ref('')
|
|
33
39
|
const textColor = ref('')
|
|
34
40
|
const backgroundColor = ref('')
|
|
35
|
-
const
|
|
41
|
+
const inputTimeError = computed(() => {
|
|
42
|
+
if (!timeValidationRequested.value) return ''
|
|
43
|
+
if (!timeInput.value.trim() || !Number.isFinite(Number(timeInput.value)))
|
|
44
|
+
return '请输入有效的时间'
|
|
45
|
+
return ''
|
|
46
|
+
})
|
|
47
|
+
const timeErrorMessage = computed(() =>
|
|
48
|
+
timeValidationRequested.value ? inputTimeError.value || props.timeError || '' : '',
|
|
49
|
+
)
|
|
50
|
+
const canConfirm = computed(
|
|
51
|
+
() =>
|
|
52
|
+
text.value.trim().length > 0 &&
|
|
53
|
+
timeInput.value.trim().length > 0 &&
|
|
54
|
+
Number.isFinite(Number(timeInput.value)) &&
|
|
55
|
+
!timeErrorMessage.value,
|
|
56
|
+
)
|
|
36
57
|
const characterCount = computed(() => text.value.length)
|
|
37
58
|
const selectedSeries = computed(() => {
|
|
38
59
|
const option = props.seriesOptions?.find(
|
|
@@ -46,15 +67,30 @@ const selectedSeries = computed(() => {
|
|
|
46
67
|
function hydrate() {
|
|
47
68
|
const style = resolveAnnotationStyle(props.annotation.style)
|
|
48
69
|
text.value = props.annotation.text
|
|
70
|
+
timeInput.value = formatAnnotationTime(props.annotation.x, props.timeUnit)
|
|
71
|
+
timeValidationRequested.value = false
|
|
49
72
|
borderColor.value = style.borderColor
|
|
50
73
|
textColor.value = style.textColor
|
|
51
74
|
backgroundColor.value = style.backgroundColor
|
|
52
75
|
void nextTick(() => textarea.value?.focus())
|
|
53
76
|
}
|
|
54
77
|
|
|
55
|
-
watch(() => props.annotation, hydrate, { immediate: true })
|
|
78
|
+
watch(() => props.annotation.id, hydrate, { immediate: true })
|
|
79
|
+
|
|
80
|
+
function handleTimeInput(value: number | string | null) {
|
|
81
|
+
const nextValue = value === null || value === undefined ? '' : String(value)
|
|
82
|
+
timeInput.value = nextValue
|
|
83
|
+
timeValidationRequested.value = false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function commitTimeInput() {
|
|
87
|
+
timeValidationRequested.value = true
|
|
88
|
+
emit('time-change', timeInput.value)
|
|
89
|
+
}
|
|
56
90
|
|
|
57
|
-
function confirm() {
|
|
91
|
+
async function confirm() {
|
|
92
|
+
commitTimeInput()
|
|
93
|
+
await nextTick()
|
|
58
94
|
if (!canConfirm.value) return
|
|
59
95
|
emit('confirm', {
|
|
60
96
|
...props.annotation,
|
|
@@ -82,40 +118,60 @@ function handleSeriesChange(event: Event) {
|
|
|
82
118
|
</script>
|
|
83
119
|
|
|
84
120
|
<template>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
:
|
|
90
|
-
|
|
121
|
+
<Modal
|
|
122
|
+
:visible="true"
|
|
123
|
+
:width="440"
|
|
124
|
+
:mask-closable="true"
|
|
125
|
+
:keyboard="true"
|
|
126
|
+
cancel-text="取消"
|
|
127
|
+
ok-text="保存标注"
|
|
128
|
+
:ok-button-props="{ disabled: !canConfirm }"
|
|
129
|
+
wrap-class-name="waveform-annotation-editor"
|
|
130
|
+
@cancel="emit('cancel')"
|
|
131
|
+
@ok="confirm"
|
|
91
132
|
>
|
|
92
|
-
<
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
<h2 :id="dialogTitleId">
|
|
96
|
-
{{ props.mode === 'add' ? '添加标注' : '编辑标注' }}
|
|
97
|
-
</h2>
|
|
98
|
-
</div>
|
|
99
|
-
<button
|
|
100
|
-
type="button"
|
|
101
|
-
class="waveform-annotation-editor__close"
|
|
102
|
-
aria-label="关闭标注编辑器"
|
|
103
|
-
title="关闭"
|
|
104
|
-
@click="emit('cancel')"
|
|
105
|
-
>
|
|
106
|
-
×
|
|
107
|
-
</button>
|
|
108
|
-
</header>
|
|
133
|
+
<template #title>
|
|
134
|
+
<span :id="dialogTitleId">{{ props.mode === 'add' ? '添加标注' : '编辑标注' }}</span>
|
|
135
|
+
</template>
|
|
109
136
|
|
|
137
|
+
<div class="waveform-annotation-editor__content">
|
|
110
138
|
<div class="waveform-annotation-editor__coordinates" aria-label="标注坐标">
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
<label
|
|
140
|
+
class="waveform-annotation-editor__coordinate-input"
|
|
141
|
+
:aria-invalid="Boolean(timeErrorMessage)"
|
|
142
|
+
>
|
|
143
|
+
<b>X</b>
|
|
144
|
+
<InputNumber
|
|
145
|
+
:value="timeInput === '' ? undefined : Number(timeInput)"
|
|
146
|
+
:controls="true"
|
|
147
|
+
:step="0.001"
|
|
148
|
+
:keyboard="true"
|
|
149
|
+
:status="timeErrorMessage ? 'error' : undefined"
|
|
150
|
+
aria-label="标注横轴时间"
|
|
151
|
+
:aria-invalid="Boolean(timeErrorMessage)"
|
|
152
|
+
:aria-describedby="timeErrorMessage ? `${dialogTitleId}-time-error` : undefined"
|
|
153
|
+
@blur="commitTimeInput"
|
|
154
|
+
@update:value="handleTimeInput"
|
|
155
|
+
/>
|
|
156
|
+
<code class="waveform-annotation-editor__coordinate-value" aria-hidden="true">{{
|
|
157
|
+
timeInput
|
|
158
|
+
}}</code>
|
|
159
|
+
</label>
|
|
160
|
+
<p
|
|
161
|
+
v-if="timeErrorMessage"
|
|
162
|
+
:id="`${dialogTitleId}-time-error`"
|
|
163
|
+
class="waveform-annotation-editor__coordinate-error"
|
|
164
|
+
role="alert"
|
|
114
165
|
>
|
|
166
|
+
{{ timeErrorMessage }}
|
|
167
|
+
</p>
|
|
115
168
|
<span
|
|
116
169
|
><b>Y</b><code>{{ formatPlainNumber(props.annotation.y) }}</code></span
|
|
117
170
|
>
|
|
118
171
|
</div>
|
|
172
|
+
<p class="waveform-annotation-editor__coordinate-hint" role="note">
|
|
173
|
+
修改 X 轴后失焦时会自动吸附最近的采样点
|
|
174
|
+
</p>
|
|
119
175
|
|
|
120
176
|
<label
|
|
121
177
|
v-if="selectedSeries"
|
|
@@ -200,14 +256,8 @@ function handleSeriesChange(event: Event) {
|
|
|
200
256
|
</label>
|
|
201
257
|
</fieldset>
|
|
202
258
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<button type="button" class="is-primary" :disabled="!canConfirm" @click="confirm">
|
|
206
|
-
保存标注
|
|
207
|
-
</button>
|
|
208
|
-
</footer>
|
|
209
|
-
</section>
|
|
210
|
-
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</Modal>
|
|
211
261
|
</template>
|
|
212
262
|
|
|
213
263
|
<style scoped src="./WaveformAnnotationEditor.css"></style>
|