waveform-analysis 0.1.41 → 0.1.42
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 +6 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +27 -22
- package/dist/style.css +1 -1
- package/dist/types/components/core/grid.d.ts +3 -0
- package/dist/types/components/core/useWaveformChartController.d.ts +1 -0
- package/dist/types/components/core/useWaveformChartLifecycle.d.ts +2 -4
- package/dist/types/components/core/useWaveformLayout.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/annotation/WaveformAnnotationEditor.css +30 -0
- package/src/components/annotation/WaveformAnnotationEditor.vue +1 -0
- package/src/components/annotation/components.test.ts +14 -1
- package/src/components/core/fixedYDomainLayout.test.ts +21 -3
- package/src/components/core/grid.test.ts +48 -0
- package/src/components/core/grid.ts +20 -7
- package/src/components/core/layout.test.ts +21 -3
- package/src/components/core/trackLayoutBuilder.ts +1 -1
- package/src/components/core/useWaveformChartLifecycle.ts +25 -15
- package/src/components/waveformChartCases/gridFill.test.ts +95 -0
package/dist/index.js
CHANGED
|
@@ -1032,6 +1032,7 @@ function tn(e) {
|
|
|
1032
1032
|
rowCount: en(e?.rowCount, 2),
|
|
1033
1033
|
columnCount: en(e?.columnCount, 1),
|
|
1034
1034
|
showPagination: e?.showPagination ?? !0,
|
|
1035
|
+
fillIncompleteLastRow: e?.fillIncompleteLastRow ?? !1,
|
|
1035
1036
|
trackLines: t
|
|
1036
1037
|
};
|
|
1037
1038
|
}
|
|
@@ -1049,32 +1050,33 @@ function on(e) {
|
|
|
1049
1050
|
return e === "compact" ? 0 : e === "separated" ? 16 : 14;
|
|
1050
1051
|
}
|
|
1051
1052
|
function sn(e, t, n, r, i = [], a, o = !0) {
|
|
1052
|
-
let s =
|
|
1053
|
+
let s = nn(n), c = i.filter(Boolean).length, l = n.fillIncompleteLastRow && c > 0 && c < s, u = l ? Math.ceil(c / n.columnCount) : n.rowCount, d = on(r), f = Number.isFinite(a) ? Math.max(0, a) : d, p = /* @__PURE__ */ new Set();
|
|
1053
1054
|
if (o) {
|
|
1054
|
-
if (r === "independent") for (let e = 0; e <
|
|
1055
|
-
else if (r === "compact")
|
|
1055
|
+
if (r === "independent") for (let e = 0; e < u; e += 1) p.add(e);
|
|
1056
|
+
else if (r === "compact") p.add(u - 1);
|
|
1056
1057
|
else for (let e = 0; e < n.columnCount; e += 1) for (let t = nn(n) - 1; t >= 0; --t) if (t % n.columnCount === e && i[t]) {
|
|
1057
|
-
|
|
1058
|
+
p.add(Math.floor(t / n.columnCount));
|
|
1058
1059
|
break;
|
|
1059
1060
|
}
|
|
1060
1061
|
}
|
|
1061
|
-
let
|
|
1062
|
-
return Array.from({ length:
|
|
1063
|
-
let
|
|
1064
|
-
let n =
|
|
1065
|
-
return
|
|
1062
|
+
let m = Math.max(0, u - 1) * d, h = p.size * 30, g = Math.max(1, (t - m - h) / u);
|
|
1063
|
+
return Array.from({ length: l ? c : s }, (t, r) => {
|
|
1064
|
+
let i = Math.floor(r / n.columnCount), a = r % n.columnCount, o = l && i === u - 1 ? c - i * n.columnCount : n.columnCount, s = Math.max(0, o - 1) * f, m = Math.max(1, (e - s) / o), h = p.has(i) ? 30 : 0, _ = g + h, v = Array.from({ length: i }, (e, t) => {
|
|
1065
|
+
let n = p.has(t) ? 30 : 0;
|
|
1066
|
+
return g + n + d;
|
|
1066
1067
|
}).reduce((e, t) => e + t, 0);
|
|
1067
1068
|
return {
|
|
1068
|
-
slotIndex:
|
|
1069
|
-
row:
|
|
1070
|
-
column:
|
|
1071
|
-
left:
|
|
1072
|
-
top:
|
|
1073
|
-
width:
|
|
1074
|
-
height:
|
|
1075
|
-
plotHeight:
|
|
1076
|
-
cellHeight:
|
|
1077
|
-
xAxisBand:
|
|
1069
|
+
slotIndex: r,
|
|
1070
|
+
row: i,
|
|
1071
|
+
column: a,
|
|
1072
|
+
left: a * (m + f),
|
|
1073
|
+
top: v,
|
|
1074
|
+
width: m,
|
|
1075
|
+
height: g,
|
|
1076
|
+
plotHeight: g,
|
|
1077
|
+
cellHeight: _,
|
|
1078
|
+
xAxisBand: h,
|
|
1079
|
+
isLastRow: i === u - 1
|
|
1078
1080
|
};
|
|
1079
1081
|
});
|
|
1080
1082
|
}
|
|
@@ -1210,7 +1212,7 @@ function pn(e) {
|
|
|
1210
1212
|
horizontal: !0,
|
|
1211
1213
|
vertical: !0
|
|
1212
1214
|
},
|
|
1213
|
-
showXAxis: (i || s) && (e.displayMode === "independent" || (e.displayMode === "compact" ? t.row === e.grid.rowCount - 1 : n.has(t.slotIndex)))
|
|
1215
|
+
showXAxis: (i || s) && (e.displayMode === "independent" || (e.displayMode === "compact" ? t.isLastRow ?? t.row === e.grid.rowCount - 1 : n.has(t.slotIndex)))
|
|
1214
1216
|
};
|
|
1215
1217
|
});
|
|
1216
1218
|
}
|
|
@@ -2152,6 +2154,7 @@ function Qn(e) {
|
|
|
2152
2154
|
v,
|
|
2153
2155
|
() => x.value.rowCount,
|
|
2154
2156
|
() => x.value.columnCount,
|
|
2157
|
+
() => x.value.fillIncompleteLastRow,
|
|
2155
2158
|
j
|
|
2156
2159
|
], async () => {
|
|
2157
2160
|
await d(), H();
|
|
@@ -2161,7 +2164,8 @@ function Qn(e) {
|
|
|
2161
2164
|
}), E([
|
|
2162
2165
|
y,
|
|
2163
2166
|
() => t.grid?.rowCount,
|
|
2164
|
-
() => t.grid?.columnCount
|
|
2167
|
+
() => t.grid?.columnCount,
|
|
2168
|
+
() => t.grid?.fillIncompleteLastRow
|
|
2165
2169
|
], () => {
|
|
2166
2170
|
let e = v.value;
|
|
2167
2171
|
v.value = v.value > y.value ? y.value : v.value === 1 ? v.value : 1, e !== v.value && n("page-change", v.value, y.value), B(), d(H);
|
|
@@ -2768,6 +2772,7 @@ var lr = ["id"], ur = { class: "waveform-annotation-editor__content" }, dr = {
|
|
|
2768
2772
|
"cancel-text": "取消",
|
|
2769
2773
|
"ok-text": "保存标注",
|
|
2770
2774
|
"ok-button-props": { disabled: !M.value },
|
|
2775
|
+
"root-class-name": "waveform-annotation-editor-root",
|
|
2771
2776
|
"wrap-class-name": "waveform-annotation-editor",
|
|
2772
2777
|
onCancel: o[4] ||= (e) => u("cancel"),
|
|
2773
2778
|
onOk: R
|
|
@@ -2874,7 +2879,7 @@ var lr = ["id"], ur = { class: "waveform-annotation-editor__content" }, dr = {
|
|
|
2874
2879
|
_: 1
|
|
2875
2880
|
}, 8, ["ok-button-props"]));
|
|
2876
2881
|
}
|
|
2877
|
-
}), [["__scopeId", "data-v-
|
|
2882
|
+
}), [["__scopeId", "data-v-42466cf9"]]), Or = { class: "waveform-tooltip__series-content" }, kr = { class: "waveform-tooltip__series-label" }, Ar = { class: "waveform-tooltip__value" }, jr = 12, Mr = 8, Nr = 238, Pr = 560, Fr = 20, Ir = 20, Lr = /*#__PURE__*/ Fe(/* @__PURE__ */ c({
|
|
2878
2883
|
__name: "WaveformTooltip",
|
|
2879
2884
|
props: {
|
|
2880
2885
|
visible: { type: Boolean },
|
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__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}
|
|
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-root,.waveform-annotation-editor-root *{box-sizing:border-box}.waveform-annotation-editor-root{color:#344054;text-align:left;text-transform:none;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif;line-height:1.5715}.waveform-annotation-editor-root button,.waveform-annotation-editor-root input,.waveform-annotation-editor-root select,.waveform-annotation-editor-root textarea{letter-spacing:normal;text-transform:none;font-family:inherit}.waveform-annotation-editor-root button{appearance:auto}.waveform-annotation-editor__content[data-v-42466cf9]{color:#344054;gap:20px;font-size:13px;display:grid}.waveform-annotation-editor__coordinates[data-v-42466cf9]{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;display:grid}.waveform-annotation-editor__coordinates span[data-v-42466cf9],.waveform-annotation-editor__series[data-v-42466cf9]{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-42466cf9]{color:#667085}.waveform-annotation-editor__coordinate-input[data-v-42466cf9]{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-42466cf9] .ant-input-number{color:#344054;width:auto;min-width:96px;font-family:SFMono-Regular,Consolas,monospace}.waveform-annotation-editor__coordinate-value[data-v-42466cf9]{display:none}.waveform-annotation-editor__coordinate-error[data-v-42466cf9]{color:#d92d20;grid-column:1/-1;margin:-12px 0 0;font-size:11px;line-height:1.4}.waveform-annotation-editor__coordinate-hint[data-v-42466cf9]{color:#98a2b3;margin:-12px 0 0;font-size:11px;line-height:1.4}.waveform-annotation-editor__coordinates b[data-v-42466cf9]{color:#1677ff;font-size:11px}.waveform-annotation-editor__coordinates code[data-v-42466cf9]{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-42466cf9]{gap:10px}.waveform-annotation-editor__series i[data-v-42466cf9]{border:1px solid #0000001f;border-radius:2px;flex:0 0 12px;width:12px;height:12px}.waveform-annotation-editor__series-label[data-v-42466cf9]{gap:1px;min-width:0;display:grid}.waveform-annotation-editor__series select[data-v-42466cf9]{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-42466cf9]{color:#667085;font-size:10px}.waveform-annotation-editor__series b[data-v-42466cf9]{color:#344054;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.waveform-annotation-editor__series code[data-v-42466cf9]{color:#667085;margin-left:auto;font-size:11px}.waveform-annotation-editor__field[data-v-42466cf9],.waveform-annotation-editor__color-field[data-v-42466cf9]{gap:4px;display:grid}.waveform-annotation-editor__label-row[data-v-42466cf9]{justify-content:space-between;align-items:center;gap:8px;display:flex}.waveform-annotation-editor__label-row b[data-v-42466cf9],.waveform-annotation-editor__colors legend[data-v-42466cf9]{color:#344054;font-size:12px;font-weight:600}.waveform-annotation-editor__label-row small[data-v-42466cf9]{color:#98a2b3;font-size:11px}.waveform-annotation-editor textarea[data-v-42466cf9]{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-42466cf9]:focus{border-color:#1677ff;outline:3px solid #1677ff24}.waveform-annotation-editor__colors[data-v-42466cf9]{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-42466cf9]{grid-column:1/-1;padding:0}.waveform-annotation-editor__color-field[data-v-42466cf9]{color:#667085;text-align:left;place-items:stretch stretch;min-width:0;font-size:11px}.waveform-annotation-editor__color-field[data-v-42466cf9] .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-42466cf9] .vc-color-wrap:hover{border-color:#98a2b3;box-shadow:0 0 0 3px #1677ff1f}@media (width<=420px){.waveform-annotation-editor__content[data-v-42466cf9]{gap:16px}.waveform-annotation-editor__coordinates[data-v-42466cf9]{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*/
|
|
@@ -6,6 +6,7 @@ export interface WaveformGridOptions {
|
|
|
6
6
|
rowCount?: number;
|
|
7
7
|
columnCount?: number;
|
|
8
8
|
showPagination?: boolean;
|
|
9
|
+
fillIncompleteLastRow?: boolean;
|
|
9
10
|
trackLines?: WaveformGridTrackLines;
|
|
10
11
|
}
|
|
11
12
|
export interface WaveformGridLineOptions {
|
|
@@ -27,6 +28,7 @@ export interface NormalizedWaveformGridOptions {
|
|
|
27
28
|
rowCount: number;
|
|
28
29
|
columnCount: number;
|
|
29
30
|
showPagination: boolean;
|
|
31
|
+
fillIncompleteLastRow: boolean;
|
|
30
32
|
trackLines: Record<string, NormalizedWaveformGridLineOptions>;
|
|
31
33
|
}
|
|
32
34
|
export interface GridCellGeometry {
|
|
@@ -41,6 +43,7 @@ export interface GridCellGeometry {
|
|
|
41
43
|
plotHeight: number;
|
|
42
44
|
cellHeight: number;
|
|
43
45
|
xAxisBand: number;
|
|
46
|
+
isLastRow?: boolean;
|
|
44
47
|
}
|
|
45
48
|
export declare function normalizeGridOptions(options?: WaveformGridOptions): NormalizedWaveformGridOptions;
|
|
46
49
|
export declare function getPageSize(options: NormalizedWaveformGridOptions): number;
|
|
@@ -272,6 +272,7 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
|
|
|
272
272
|
plotHeight: number;
|
|
273
273
|
cellHeight: number;
|
|
274
274
|
xAxisBand: number;
|
|
275
|
+
isLastRow?: boolean;
|
|
275
276
|
}[];
|
|
276
277
|
trackLayouts: import("./types").TrackLayout[];
|
|
277
278
|
annotationLayoutsForTrack: (track: import("./types").TrackLayout) => import("../annotation").AnnotationTrackLayout[];
|
|
@@ -2,6 +2,7 @@ import { type ZoomTransform } from 'd3';
|
|
|
2
2
|
import { type ComputedRef, type Ref, type ShallowRef } from 'vue';
|
|
3
3
|
import type { AnnotationSeriesCandidate } from '../annotation';
|
|
4
4
|
import type { useWaveformAnnotationInteraction } from '../annotation';
|
|
5
|
+
import type { NormalizedWaveformGridOptions } from './grid';
|
|
5
6
|
import type { DisplaySeries, DisplayTrack, TrackLayout } from './types';
|
|
6
7
|
import type { ResolvedWaveformChartProps, WaveformChartEmit } from './waveformChartTypes';
|
|
7
8
|
interface LifecycleContext {
|
|
@@ -22,10 +23,7 @@ interface LifecycleContext {
|
|
|
22
23
|
currentPage: Ref<number>;
|
|
23
24
|
pageCount: ComputedRef<number>;
|
|
24
25
|
pagedTracks: ComputedRef<Array<DisplayTrack | undefined>>;
|
|
25
|
-
gridOptions: ComputedRef<
|
|
26
|
-
rowCount: number;
|
|
27
|
-
columnCount: number;
|
|
28
|
-
}>;
|
|
26
|
+
gridOptions: ComputedRef<NormalizedWaveformGridOptions>;
|
|
29
27
|
chartSeries: ComputedRef<DisplaySeries[]>;
|
|
30
28
|
chartTracks: ComputedRef<DisplayTrack[]>;
|
|
31
29
|
trackLayouts: ComputedRef<TrackLayout[]>;
|
|
@@ -48,6 +48,7 @@ export declare function useWaveformLayout(context: LayoutContext): {
|
|
|
48
48
|
plotHeight: number;
|
|
49
49
|
cellHeight: number;
|
|
50
50
|
xAxisBand: number;
|
|
51
|
+
isLastRow?: boolean;
|
|
51
52
|
}[]>;
|
|
52
53
|
trackLayouts: ComputedRef<TrackLayout[]>;
|
|
53
54
|
annotationLayoutsForTrack: (track: TrackLayout) => AnnotationTrackLayout[];
|
package/package.json
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
/* The modal is teleported to body. Keep its entire subtree namespaced so host
|
|
2
|
+
application resets (for example `button { ... }`) cannot change the editor. */
|
|
3
|
+
:global(.waveform-annotation-editor-root),
|
|
4
|
+
:global(.waveform-annotation-editor-root *) {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:global(.waveform-annotation-editor-root) {
|
|
9
|
+
color: #344054;
|
|
10
|
+
font-family:
|
|
11
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
|
12
|
+
'Noto Sans', sans-serif;
|
|
13
|
+
line-height: 1.5715;
|
|
14
|
+
text-align: left;
|
|
15
|
+
text-transform: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:global(.waveform-annotation-editor-root button),
|
|
19
|
+
:global(.waveform-annotation-editor-root input),
|
|
20
|
+
:global(.waveform-annotation-editor-root select),
|
|
21
|
+
:global(.waveform-annotation-editor-root textarea) {
|
|
22
|
+
font-family: inherit;
|
|
23
|
+
letter-spacing: normal;
|
|
24
|
+
text-transform: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:global(.waveform-annotation-editor-root button) {
|
|
28
|
+
appearance: auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
1
31
|
.waveform-annotation-editor__content {
|
|
2
32
|
display: grid;
|
|
3
33
|
gap: 20px;
|
|
@@ -126,6 +126,7 @@ function handleSeriesChange(event: Event) {
|
|
|
126
126
|
cancel-text="取消"
|
|
127
127
|
ok-text="保存标注"
|
|
128
128
|
:ok-button-props="{ disabled: !canConfirm }"
|
|
129
|
+
root-class-name="waveform-annotation-editor-root"
|
|
129
130
|
wrap-class-name="waveform-annotation-editor"
|
|
130
131
|
@cancel="emit('cancel')"
|
|
131
132
|
@ok="confirm"
|
|
@@ -18,13 +18,14 @@ const modalStub = defineComponent({
|
|
|
18
18
|
'cancelText',
|
|
19
19
|
'okText',
|
|
20
20
|
'okButtonProps',
|
|
21
|
+
'rootClassName',
|
|
21
22
|
],
|
|
22
23
|
emits: ['cancel', 'ok'],
|
|
23
24
|
setup(props, { emit, slots }) {
|
|
24
25
|
return () => {
|
|
25
26
|
const title = slots.title?.() ?? []
|
|
26
27
|
const titleId = (title[0]?.props as { id?: string } | undefined)?.id
|
|
27
|
-
return h('div', { class: 'ant-modal-root' }, [
|
|
28
|
+
return h('div', { class: ['ant-modal-root', props.rootClassName] }, [
|
|
28
29
|
h(
|
|
29
30
|
'div',
|
|
30
31
|
{
|
|
@@ -96,6 +97,18 @@ describe('waveform annotation controls', () => {
|
|
|
96
97
|
expect(second.get('[role="dialog"]').attributes('aria-labelledby')).toBe(secondTitleId)
|
|
97
98
|
})
|
|
98
99
|
|
|
100
|
+
it('uses a dedicated root class to isolate teleported modal styles', () => {
|
|
101
|
+
const wrapper = mountEditor({
|
|
102
|
+
props: {
|
|
103
|
+
annotation: { id: 'isolated', seriesId: 'a', x: 1, y: 2, text: '说明' },
|
|
104
|
+
mode: 'add',
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
expect(wrapper.get('.ant-modal-root').classes()).toContain('waveform-annotation-editor-root')
|
|
109
|
+
expect(wrapper.get('.ant-modal-wrap').classes()).toContain('waveform-annotation-editor')
|
|
110
|
+
})
|
|
111
|
+
|
|
99
112
|
it.each(['add', 'edit'] as const)('shows the X-axis snapping hint in %s mode', (mode) => {
|
|
100
113
|
const wrapper = mountEditor({
|
|
101
114
|
props: {
|
|
@@ -53,7 +53,13 @@ describe('fixed Y-domain layout', () => {
|
|
|
53
53
|
series: sourceTrack,
|
|
54
54
|
},
|
|
55
55
|
],
|
|
56
|
-
grid: {
|
|
56
|
+
grid: {
|
|
57
|
+
rowCount: 1,
|
|
58
|
+
columnCount: 1,
|
|
59
|
+
showPagination: false,
|
|
60
|
+
fillIncompleteLastRow: false,
|
|
61
|
+
trackLines: {},
|
|
62
|
+
},
|
|
57
63
|
displayMode: 'independent',
|
|
58
64
|
overlayMode: 'single-axis',
|
|
59
65
|
independentTransforms: [zoomIdentity],
|
|
@@ -89,7 +95,13 @@ describe('fixed Y-domain layout', () => {
|
|
|
89
95
|
series: track([series('a', 0, 100)]),
|
|
90
96
|
},
|
|
91
97
|
],
|
|
92
|
-
grid: {
|
|
98
|
+
grid: {
|
|
99
|
+
rowCount: 1,
|
|
100
|
+
columnCount: 1,
|
|
101
|
+
showPagination: false,
|
|
102
|
+
fillIncompleteLastRow: false,
|
|
103
|
+
trackLines: {},
|
|
104
|
+
},
|
|
93
105
|
displayMode: 'independent',
|
|
94
106
|
overlayMode: 'single-axis',
|
|
95
107
|
independentTransforms: [zoomIdentity],
|
|
@@ -124,7 +136,13 @@ describe('fixed Y-domain layout', () => {
|
|
|
124
136
|
series: track([series('a', 3, 97)]),
|
|
125
137
|
},
|
|
126
138
|
],
|
|
127
|
-
grid: {
|
|
139
|
+
grid: {
|
|
140
|
+
rowCount: 1,
|
|
141
|
+
columnCount: 1,
|
|
142
|
+
showPagination: false,
|
|
143
|
+
fillIncompleteLastRow: false,
|
|
144
|
+
trackLines: {},
|
|
145
|
+
},
|
|
128
146
|
displayMode: 'independent',
|
|
129
147
|
overlayMode: 'single-axis',
|
|
130
148
|
independentTransforms: [zoomIdentity],
|
|
@@ -15,12 +15,14 @@ describe('waveform grid helpers', () => {
|
|
|
15
15
|
rowCount: 2,
|
|
16
16
|
columnCount: 1,
|
|
17
17
|
showPagination: true,
|
|
18
|
+
fillIncompleteLastRow: false,
|
|
18
19
|
trackLines: {},
|
|
19
20
|
})
|
|
20
21
|
expect(normalizeGridOptions({ rowCount: 0, columnCount: 99 })).toEqual({
|
|
21
22
|
rowCount: 1,
|
|
22
23
|
columnCount: 10,
|
|
23
24
|
showPagination: true,
|
|
25
|
+
fillIncompleteLastRow: false,
|
|
24
26
|
trackLines: {},
|
|
25
27
|
})
|
|
26
28
|
})
|
|
@@ -131,4 +133,50 @@ describe('waveform grid helpers', () => {
|
|
|
131
133
|
expect(cells[1].left).toBe(232)
|
|
132
134
|
expect(cells[2].top).toBe(cells[0].plotHeight + X_AXIS_BAND + 14)
|
|
133
135
|
})
|
|
136
|
+
|
|
137
|
+
it('fills incomplete final rows without changing page capacity', () => {
|
|
138
|
+
const oneColumn = resolveGridCellGeometry(
|
|
139
|
+
400,
|
|
140
|
+
400,
|
|
141
|
+
normalizeGridOptions({ rowCount: 4, columnCount: 1, fillIncompleteLastRow: true }),
|
|
142
|
+
'separated',
|
|
143
|
+
[true, true, true],
|
|
144
|
+
)
|
|
145
|
+
expect(oneColumn).toHaveLength(3)
|
|
146
|
+
expect(oneColumn.map((cell) => cell.width)).toEqual([400, 400, 400])
|
|
147
|
+
expect(oneColumn.at(-1)?.isLastRow).toBe(true)
|
|
148
|
+
|
|
149
|
+
const twoColumns = resolveGridCellGeometry(
|
|
150
|
+
400,
|
|
151
|
+
300,
|
|
152
|
+
normalizeGridOptions({ rowCount: 2, columnCount: 2, fillIncompleteLastRow: true }),
|
|
153
|
+
'separated',
|
|
154
|
+
[true, true, true],
|
|
155
|
+
)
|
|
156
|
+
expect(twoColumns).toHaveLength(3)
|
|
157
|
+
expect(twoColumns[2]).toMatchObject({ row: 1, column: 0, left: 0, width: 400 })
|
|
158
|
+
|
|
159
|
+
const threeColumns = resolveGridCellGeometry(
|
|
160
|
+
400,
|
|
161
|
+
300,
|
|
162
|
+
normalizeGridOptions({ rowCount: 2, columnCount: 3, fillIncompleteLastRow: true }),
|
|
163
|
+
'separated',
|
|
164
|
+
[true, true, true, true, true],
|
|
165
|
+
)
|
|
166
|
+
expect(threeColumns).toHaveLength(5)
|
|
167
|
+
expect(threeColumns.slice(3).map((cell) => cell.width)).toEqual([192, 192])
|
|
168
|
+
expect(threeColumns.slice(3).map((cell) => cell.left)).toEqual([0, 208])
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('keeps full pages and the disabled option byte-for-byte compatible', () => {
|
|
172
|
+
const base = normalizeGridOptions({ rowCount: 2, columnCount: 2 })
|
|
173
|
+
const filled = normalizeGridOptions({ rowCount: 2, columnCount: 2, fillIncompleteLastRow: true })
|
|
174
|
+
const fullSlots = [true, true, true, true]
|
|
175
|
+
expect(resolveGridCellGeometry(400, 300, filled, 'independent', fullSlots)).toEqual(
|
|
176
|
+
resolveGridCellGeometry(400, 300, base, 'independent', fullSlots),
|
|
177
|
+
)
|
|
178
|
+
expect(resolveGridCellGeometry(400, 300, base, 'independent', [true, true, true])).toHaveLength(
|
|
179
|
+
4,
|
|
180
|
+
)
|
|
181
|
+
})
|
|
134
182
|
})
|
|
@@ -8,6 +8,7 @@ export interface WaveformGridOptions {
|
|
|
8
8
|
rowCount?: number
|
|
9
9
|
columnCount?: number
|
|
10
10
|
showPagination?: boolean
|
|
11
|
+
fillIncompleteLastRow?: boolean
|
|
11
12
|
trackLines?: WaveformGridTrackLines
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -33,6 +34,7 @@ export interface NormalizedWaveformGridOptions {
|
|
|
33
34
|
rowCount: number
|
|
34
35
|
columnCount: number
|
|
35
36
|
showPagination: boolean
|
|
37
|
+
fillIncompleteLastRow: boolean
|
|
36
38
|
trackLines: Record<string, NormalizedWaveformGridLineOptions>
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -48,6 +50,7 @@ export interface GridCellGeometry {
|
|
|
48
50
|
plotHeight: number
|
|
49
51
|
cellHeight: number
|
|
50
52
|
xAxisBand: number
|
|
53
|
+
isLastRow?: boolean
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
const normalizeCount = (value: unknown, fallback: number) => {
|
|
@@ -78,6 +81,7 @@ export function normalizeGridOptions(options?: WaveformGridOptions): NormalizedW
|
|
|
78
81
|
rowCount: normalizeCount(options?.rowCount, 2),
|
|
79
82
|
columnCount: normalizeCount(options?.columnCount, 1),
|
|
80
83
|
showPagination: options?.showPagination ?? true,
|
|
84
|
+
fillIncompleteLastRow: options?.fillIncompleteLastRow ?? false,
|
|
81
85
|
trackLines,
|
|
82
86
|
}
|
|
83
87
|
}
|
|
@@ -114,20 +118,23 @@ export function resolveGridCellGeometry(
|
|
|
114
118
|
horizontalGap?: number,
|
|
115
119
|
showXAxis = true,
|
|
116
120
|
): GridCellGeometry[] {
|
|
121
|
+
const pageSize = getPageSize(options)
|
|
122
|
+
const seriesCount = slotHasSeries.filter(Boolean).length
|
|
123
|
+
const filledLastRow = options.fillIncompleteLastRow && seriesCount > 0 && seriesCount < pageSize
|
|
124
|
+
const rowCount = filledLastRow ? Math.ceil(seriesCount / options.columnCount) : options.rowCount
|
|
117
125
|
const defaultGap = getGridGap(displayMode)
|
|
118
126
|
const columnGap = Number.isFinite(horizontalGap)
|
|
119
127
|
? Math.max(0, horizontalGap as number)
|
|
120
128
|
: defaultGap
|
|
121
|
-
const totalHorizontalGap = Math.max(0, options.columnCount - 1) * columnGap
|
|
122
129
|
const axisRows = new Set<number>()
|
|
123
130
|
if (!showXAxis) {
|
|
124
131
|
// Net view uses the full drawing area for waveform pixels.
|
|
125
132
|
} else if (displayMode === 'independent') {
|
|
126
|
-
for (let row = 0; row <
|
|
133
|
+
for (let row = 0; row < rowCount; row += 1) axisRows.add(row)
|
|
127
134
|
} else if (displayMode === 'compact') {
|
|
128
135
|
// Compact tracks share one continuous plot stack. Reserve the X-axis band
|
|
129
136
|
// only beneath the final grid row, including when that row is empty.
|
|
130
|
-
axisRows.add(
|
|
137
|
+
axisRows.add(rowCount - 1)
|
|
131
138
|
} else {
|
|
132
139
|
for (let column = 0; column < options.columnCount; column += 1) {
|
|
133
140
|
for (let slotIndex = getPageSize(options) - 1; slotIndex >= 0; slotIndex -= 1) {
|
|
@@ -139,17 +146,22 @@ export function resolveGridCellGeometry(
|
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
|
-
const totalVerticalGap = Math.max(0,
|
|
149
|
+
const totalVerticalGap = Math.max(0, rowCount - 1) * defaultGap
|
|
143
150
|
const totalAxisBand = axisRows.size * X_AXIS_BAND
|
|
144
|
-
const width = Math.max(1, (innerWidth - totalHorizontalGap) / options.columnCount)
|
|
145
151
|
const plotHeight = Math.max(
|
|
146
152
|
1,
|
|
147
|
-
(innerHeight - totalVerticalGap - totalAxisBand) /
|
|
153
|
+
(innerHeight - totalVerticalGap - totalAxisBand) / rowCount,
|
|
148
154
|
)
|
|
149
155
|
|
|
150
|
-
return Array.from({ length:
|
|
156
|
+
return Array.from({ length: filledLastRow ? seriesCount : pageSize }, (_, slotIndex) => {
|
|
151
157
|
const row = Math.floor(slotIndex / options.columnCount)
|
|
152
158
|
const column = slotIndex % options.columnCount
|
|
159
|
+
const rowSeriesCount =
|
|
160
|
+
filledLastRow && row === rowCount - 1
|
|
161
|
+
? seriesCount - row * options.columnCount
|
|
162
|
+
: options.columnCount
|
|
163
|
+
const rowGap = Math.max(0, rowSeriesCount - 1) * columnGap
|
|
164
|
+
const width = Math.max(1, (innerWidth - rowGap) / rowSeriesCount)
|
|
153
165
|
const xAxisBand = axisRows.has(row) ? X_AXIS_BAND : 0
|
|
154
166
|
const cellHeight = plotHeight + xAxisBand
|
|
155
167
|
const top = Array.from({ length: row }, (_, previousRow) => {
|
|
@@ -167,6 +179,7 @@ export function resolveGridCellGeometry(
|
|
|
167
179
|
plotHeight,
|
|
168
180
|
cellHeight,
|
|
169
181
|
xAxisBand,
|
|
182
|
+
isLastRow: row === rowCount - 1,
|
|
170
183
|
}
|
|
171
184
|
})
|
|
172
185
|
}
|
|
@@ -65,7 +65,13 @@ function layoutForSeries(
|
|
|
65
65
|
series: sourceTrack,
|
|
66
66
|
},
|
|
67
67
|
],
|
|
68
|
-
grid: {
|
|
68
|
+
grid: {
|
|
69
|
+
rowCount: 1,
|
|
70
|
+
columnCount: 1,
|
|
71
|
+
showPagination: false,
|
|
72
|
+
fillIncompleteLastRow: false,
|
|
73
|
+
trackLines: {},
|
|
74
|
+
},
|
|
69
75
|
displayMode: 'independent',
|
|
70
76
|
overlayMode: 'single-axis',
|
|
71
77
|
independentTransforms: [transform],
|
|
@@ -107,7 +113,13 @@ describe('multi-value Y-axis grouping', () => {
|
|
|
107
113
|
series: sourceTrack,
|
|
108
114
|
},
|
|
109
115
|
],
|
|
110
|
-
grid: {
|
|
116
|
+
grid: {
|
|
117
|
+
rowCount: 1,
|
|
118
|
+
columnCount: 1,
|
|
119
|
+
showPagination: false,
|
|
120
|
+
fillIncompleteLastRow: false,
|
|
121
|
+
trackLines: {},
|
|
122
|
+
},
|
|
111
123
|
displayMode: 'independent',
|
|
112
124
|
overlayMode: 'single-axis',
|
|
113
125
|
independentTransforms: [zoomIdentity],
|
|
@@ -217,7 +229,13 @@ describe('multi-value Y-axis grouping', () => {
|
|
|
217
229
|
series: track([series('left', 1000, 3000), series('right', 1000, 3000)]),
|
|
218
230
|
},
|
|
219
231
|
],
|
|
220
|
-
grid: {
|
|
232
|
+
grid: {
|
|
233
|
+
rowCount: 1,
|
|
234
|
+
columnCount: 1,
|
|
235
|
+
showPagination: false,
|
|
236
|
+
fillIncompleteLastRow: false,
|
|
237
|
+
trackLines: {},
|
|
238
|
+
},
|
|
221
239
|
displayMode: 'independent',
|
|
222
240
|
overlayMode: 'multi-axis',
|
|
223
241
|
independentTransforms: [zoomIdentity],
|
|
@@ -266,7 +266,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
266
266
|
(isEmpty || hasVisibleSeries) &&
|
|
267
267
|
(options.displayMode === 'independent' ||
|
|
268
268
|
(options.displayMode === 'compact'
|
|
269
|
-
? cell.row === options.grid.rowCount - 1
|
|
269
|
+
? (cell.isLastRow ?? cell.row === options.grid.rowCount - 1)
|
|
270
270
|
: bottomCells.has(cell.slotIndex))),
|
|
271
271
|
}
|
|
272
272
|
})
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
import type { AnnotationSeriesCandidate } from '../annotation'
|
|
13
13
|
import type { useWaveformAnnotationInteraction } from '../annotation'
|
|
14
|
+
import type { NormalizedWaveformGridOptions } from './grid'
|
|
14
15
|
import type { DisplaySeries, DisplayTrack, TrackLayout } from './types'
|
|
15
16
|
import type { ResolvedWaveformChartProps, WaveformChartEmit } from './waveformChartTypes'
|
|
16
17
|
import { constrainZoomDomain, transformForDomain } from '../interaction/zoomConstraints'
|
|
@@ -33,7 +34,7 @@ interface LifecycleContext {
|
|
|
33
34
|
currentPage: Ref<number>
|
|
34
35
|
pageCount: ComputedRef<number>
|
|
35
36
|
pagedTracks: ComputedRef<Array<DisplayTrack | undefined>>
|
|
36
|
-
gridOptions: ComputedRef<
|
|
37
|
+
gridOptions: ComputedRef<NormalizedWaveformGridOptions>
|
|
37
38
|
chartSeries: ComputedRef<DisplaySeries[]>
|
|
38
39
|
chartTracks: ComputedRef<DisplayTrack[]>
|
|
39
40
|
trackLayouts: ComputedRef<TrackLayout[]>
|
|
@@ -220,6 +221,7 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
220
221
|
currentPage,
|
|
221
222
|
() => gridOptions.value.rowCount,
|
|
222
223
|
() => gridOptions.value.columnCount,
|
|
224
|
+
() => gridOptions.value.fillIncompleteLastRow,
|
|
223
225
|
activeInteractionMode,
|
|
224
226
|
],
|
|
225
227
|
async () => {
|
|
@@ -239,20 +241,28 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
239
241
|
},
|
|
240
242
|
)
|
|
241
243
|
|
|
242
|
-
watch(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
244
|
+
watch(
|
|
245
|
+
[
|
|
246
|
+
pageCount,
|
|
247
|
+
() => props.grid?.rowCount,
|
|
248
|
+
() => props.grid?.columnCount,
|
|
249
|
+
() => props.grid?.fillIncompleteLastRow,
|
|
250
|
+
],
|
|
251
|
+
() => {
|
|
252
|
+
const previousPage = currentPage.value
|
|
253
|
+
currentPage.value =
|
|
254
|
+
currentPage.value > pageCount.value
|
|
255
|
+
? pageCount.value
|
|
256
|
+
: currentPage.value !== 1
|
|
257
|
+
? 1
|
|
258
|
+
: currentPage.value
|
|
259
|
+
if (previousPage !== currentPage.value) {
|
|
260
|
+
emit('page-change', currentPage.value, pageCount.value)
|
|
261
|
+
}
|
|
262
|
+
clearHover()
|
|
263
|
+
void nextTick(configureZoom)
|
|
264
|
+
},
|
|
265
|
+
)
|
|
256
266
|
|
|
257
267
|
watch(activeInteractionMode, () => {
|
|
258
268
|
editorSeriesOptions.value = []
|