kd-lane-chart-v3 0.1.4 → 0.1.6

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/dist/esm/index.js CHANGED
@@ -342,7 +342,7 @@ const _sfc_main$e = {
342
342
  document.body.addEventListener("keyup", this.onEscKeyRelease);
343
343
  },
344
344
  beforeUnmount() {
345
- document.removeEventListener("keyup", this.onEscKeyRelease);
345
+ document.body.removeEventListener("keyup", this.onEscKeyRelease);
346
346
  }
347
347
  };
348
348
  const _hoisted_1$d = {
@@ -371,7 +371,7 @@ function _sfc_render$e(_ctx, _cache, $props, $setup, $data, $options) {
371
371
  ])
372
372
  ]);
373
373
  }
374
- const VueSimpleContextMenu = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$e], ["__scopeId", "data-v-5e769d89"]]);
374
+ const VueSimpleContextMenu = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$e], ["__scopeId", "data-v-25d746bb"]]);
375
375
  class CustomStrategy {
376
376
  constructor(strategy) {
377
377
  this.strategy = strategy;
@@ -2607,7 +2607,304 @@ const ACTION_TYPE = {
2607
2607
  UPSERT_LINE: "upsertLine",
2608
2608
  DELETE_LINE: "delLine"
2609
2609
  };
2610
+ const LOG_AXIS_MIN_POSITIVE = 0.1;
2611
+ const LOG_AXIS_BASE = 10;
2612
+ function isLogScaleFlag(val) {
2613
+ return val === true || val === "true" || val === 1 || val === "1";
2614
+ }
2615
+ function isLaneLogScale(lane) {
2616
+ return !!(lane && isLogScaleFlag(lane.isLogScale));
2617
+ }
2618
+ function isLogAxisLabelVisible(formCache) {
2619
+ if (!formCache) return true;
2620
+ return formCache.showLogAxis !== false && formCache.showLogAxis !== "false" && formCache.showLogAxis !== 0 && formCache.showLogAxis !== "0";
2621
+ }
2622
+ function normalizeLogRange(min, max) {
2623
+ let lo = Number(min);
2624
+ let hi = Number(max);
2625
+ if (!Number.isFinite(lo) || lo <= 0) lo = LOG_AXIS_MIN_POSITIVE;
2626
+ if (!Number.isFinite(hi) || hi <= 0) hi = lo * LOG_AXIS_BASE;
2627
+ if (hi <= lo) hi = lo * LOG_AXIS_BASE;
2628
+ return { min: lo, max: hi };
2629
+ }
2630
+ function toLogDisplayValue(raw, digits = 3) {
2631
+ const n = Number(raw);
2632
+ if (!Number.isFinite(n) || n <= 0) return null;
2633
+ const logv = Math.log10(n);
2634
+ if (!Number.isFinite(logv)) return null;
2635
+ return Number(logv.toFixed(digits));
2636
+ }
2637
+ function toLogPlotX(raw) {
2638
+ const n = Number(raw);
2639
+ if (!Number.isFinite(n) || n <= 0) return null;
2640
+ const logv = Math.log10(n);
2641
+ return Number.isFinite(logv) ? logv : null;
2642
+ }
2643
+ function toLaneDrawX(plotX, lane, xAx, digits = 3) {
2644
+ if (!isLaneLogScale(lane)) return plotX;
2645
+ const n = Number(plotX);
2646
+ if (!Number.isFinite(n)) return plotX;
2647
+ return Number(n.toFixed(digits));
2648
+ }
2649
+ function axisIndexOf$1(val) {
2650
+ const n = Array.isArray(val) ? val[0] : val;
2651
+ return Number(n ?? 0);
2652
+ }
2653
+ function findLogTrendSeries(chart, paramId) {
2654
+ const option = chart.getOption() || {};
2655
+ return (option.series || []).find((s) => {
2656
+ if (!s || s.type !== "line") return false;
2657
+ const name = Array.isArray(s.name) ? s.name[0] : s.name;
2658
+ if (name === "helper" || name === "log-grid") return false;
2659
+ return String(s.paramId) === String(paramId);
2660
+ }) || null;
2661
+ }
2662
+ function pixelToLogTrendData(chart, paramId, offsetX, offsetY, lane, lineRange, digits = 3) {
2663
+ if (!chart || !isLaneLogScale(lane)) return null;
2664
+ const series = findLogTrendSeries(chart, paramId);
2665
+ const xAxisIndex = series ? axisIndexOf$1(series.xAxisIndex) : 0;
2666
+ const yAxisIndex = series ? axisIndexOf$1(series.yAxisIndex) : 0;
2667
+ const plot = resolveLaneLogPlotRange(lane, lineRange);
2668
+ const extent = toLogAxisExtent(plot.min, plot.max);
2669
+ let x0;
2670
+ let x1;
2671
+ let depth;
2672
+ try {
2673
+ x0 = chart.convertToPixel({ xAxisIndex }, extent.min);
2674
+ x1 = chart.convertToPixel({ xAxisIndex }, extent.max);
2675
+ } catch (e) {
2676
+ return null;
2677
+ }
2678
+ try {
2679
+ depth = chart.convertFromPixel({ yAxisIndex }, offsetY);
2680
+ } catch (e) {
2681
+ depth = null;
2682
+ }
2683
+ if (!Number.isFinite(x0) || !Number.isFinite(x1) || x1 === x0) return null;
2684
+ if (!Number.isFinite(depth)) return null;
2685
+ const lg = extent.min + (offsetX - x0) / (x1 - x0) * (extent.max - extent.min);
2686
+ if (!Number.isFinite(lg)) return null;
2687
+ return {
2688
+ value: Number(lg.toFixed(digits)),
2689
+ depth,
2690
+ xAxisIndex,
2691
+ yAxisIndex
2692
+ };
2693
+ }
2694
+ function seriesLogXAtDepth(chart, paramId, depth, digits = 3) {
2695
+ const series = findLogTrendSeries(chart, paramId);
2696
+ if (!series || !series.data || !Number.isFinite(Number(depth))) return null;
2697
+ let best = null;
2698
+ series.data.forEach((pt) => {
2699
+ const x = Array.isArray(pt) ? Number(pt[0]) : Number(pt && pt.value && pt.value[0]);
2700
+ const y = Array.isArray(pt) ? Number(pt[1]) : Number(pt && pt.value && pt.value[1]);
2701
+ if (!Number.isFinite(x) || !Number.isFinite(y)) return;
2702
+ const dist = Math.abs(y - Number(depth));
2703
+ if (!best || dist < best.dist) best = { x, dist };
2704
+ });
2705
+ if (!best) return null;
2706
+ return Number(best.x.toFixed(digits));
2707
+ }
2708
+ function logTrendDataToPixel(chart, paramId, lg, depth) {
2709
+ if (!chart) return null;
2710
+ const series = findLogTrendSeries(chart, paramId);
2711
+ const xAxisIndex = series ? axisIndexOf$1(series.xAxisIndex) : 0;
2712
+ const yAxisIndex = series ? axisIndexOf$1(series.yAxisIndex) : 0;
2713
+ try {
2714
+ const px = chart.convertToPixel({ xAxisIndex, yAxisIndex }, [lg, depth]);
2715
+ if (px && Number.isFinite(px[0]) && Number.isFinite(px[1])) return px;
2716
+ } catch (e) {
2717
+ }
2718
+ try {
2719
+ const x = chart.convertToPixel({ xAxisIndex }, lg);
2720
+ const y = chart.convertToPixel({ yAxisIndex }, depth);
2721
+ if (Number.isFinite(x) && Number.isFinite(y)) return [x, y];
2722
+ } catch (e) {
2723
+ return null;
2724
+ }
2725
+ return null;
2726
+ }
2727
+ function toLogAxisExtent(min, max) {
2728
+ const range = normalizeLogRange(min, max);
2729
+ return {
2730
+ min: Math.log10(range.min),
2731
+ max: Math.log10(range.max)
2732
+ };
2733
+ }
2734
+ function mapSeriesDataXToLog(data) {
2735
+ return (data || []).map((item) => {
2736
+ if (Array.isArray(item)) {
2737
+ return [toLogPlotX(item[0]), item[1], item[2]];
2738
+ }
2739
+ if (item && Array.isArray(item.value)) {
2740
+ return {
2741
+ ...item,
2742
+ value: [toLogPlotX(item.value[0]), item.value[1]]
2743
+ };
2744
+ }
2745
+ return item;
2746
+ });
2747
+ }
2748
+ function formatLanePointValue(raw, isLog, digits = 3) {
2749
+ if (raw === null || raw === void 0 || raw === "") return null;
2750
+ return toLogDisplayValue(raw, digits);
2751
+ }
2752
+ function niceLogDecadeRange(min, max) {
2753
+ const range = normalizeLogRange(min, max);
2754
+ let niceMin = 10 ** Math.floor(Math.log10(range.min) + 1e-9);
2755
+ let niceMax = 10 ** Math.ceil(Math.log10(range.max) - 1e-9);
2756
+ if (!Number.isFinite(niceMin) || niceMin <= 0) niceMin = LOG_AXIS_MIN_POSITIVE;
2757
+ if (!Number.isFinite(niceMax) || niceMax <= niceMin) {
2758
+ niceMax = niceMin * LOG_AXIS_BASE;
2759
+ }
2760
+ return { min: niceMin, max: niceMax };
2761
+ }
2762
+ function resolveLaneLogPlotRange(lane, lineRange = {}) {
2763
+ let lo = Infinity;
2764
+ let hi = -Infinity;
2765
+ (lane && lane.lines || []).forEach((line) => {
2766
+ if (!line) return;
2767
+ const r = lineRange[line.lineId] || {};
2768
+ const cfgMin = Number(line.min);
2769
+ const cfgMax = Number(line.max);
2770
+ const useMin = Number.isFinite(cfgMin) && cfgMin > 0 ? cfgMin : Number(r.min);
2771
+ const useMax = Number.isFinite(cfgMax) && cfgMax > 0 ? cfgMax : Number(r.max);
2772
+ if (Number.isFinite(useMin) && useMin > 0) lo = Math.min(lo, useMin);
2773
+ if (Number.isFinite(useMax) && useMax > 0) hi = Math.max(hi, useMax);
2774
+ });
2775
+ return niceLogDecadeRange(
2776
+ Number.isFinite(lo) ? lo : LOG_AXIS_MIN_POSITIVE,
2777
+ Number.isFinite(hi) ? hi : LOG_AXIS_MIN_POSITIVE * LOG_AXIS_BASE
2778
+ );
2779
+ }
2780
+ function buildLogLaneTenLineValues(min, max) {
2781
+ const range = niceLogDecadeRange(min, max);
2782
+ const ratio = range.max / range.min;
2783
+ const values = [];
2784
+ for (let m = 1; m <= 10; m++) {
2785
+ values.push(range.min * ratio ** Math.log10(m));
2786
+ }
2787
+ return values;
2788
+ }
2789
+ function buildLogLaneTenLineLgValues(min, max) {
2790
+ return buildLogLaneTenLineValues(min, max).map((v) => Math.log10(v)).filter((v) => Number.isFinite(v));
2791
+ }
2792
+ function buildLogDecadeTickMarks(min, max) {
2793
+ const range = niceLogDecadeRange(min, max);
2794
+ const loExp = Math.round(Math.log10(range.min));
2795
+ const hiExp = Math.round(Math.log10(range.max));
2796
+ const marks = [];
2797
+ for (let e = loExp; e <= hiExp; e++) {
2798
+ const value = 10 ** e;
2799
+ marks.push({
2800
+ value,
2801
+ label: String(e),
2802
+ percent: logValueToPercent(value, range.min, range.max)
2803
+ });
2804
+ }
2805
+ return marks;
2806
+ }
2807
+ function logValueToPercent(value, min, max) {
2808
+ const range = normalizeLogRange(min, max);
2809
+ const v = Number(value);
2810
+ if (!Number.isFinite(v) || v <= 0) return 0;
2811
+ const clamped = Math.max(range.min, Math.min(range.max, v));
2812
+ const span = Math.log(range.max) - Math.log(range.min);
2813
+ if (span <= 0) return 0;
2814
+ return (Math.log(clamped) - Math.log(range.min)) / span * 100;
2815
+ }
2816
+ function buildLogXAxisOption({
2817
+ gridIndex = 0,
2818
+ min,
2819
+ max,
2820
+ showSplitLine = true,
2821
+ splitLineColor
2822
+ } = {}) {
2823
+ const range = niceLogDecadeRange(min, max);
2824
+ const extent = toLogAxisExtent(range.min, range.max);
2825
+ const lineStyle = {
2826
+ color: splitLineColor,
2827
+ type: "dashed",
2828
+ width: 1
2829
+ };
2830
+ return {
2831
+ gridIndex,
2832
+ show: true,
2833
+ type: "value",
2834
+ min: extent.min,
2835
+ max: extent.max,
2836
+ minorTick: { show: false },
2837
+ minorSplitLine: {
2838
+ show: false,
2839
+ lineStyle
2840
+ },
2841
+ splitLine: {
2842
+ show: showSplitLine,
2843
+ showMaxLine: false,
2844
+ showMinLine: false,
2845
+ lineStyle
2846
+ },
2847
+ axisLabel: { show: false },
2848
+ axisLine: { show: false },
2849
+ axisTick: { show: false }
2850
+ };
2851
+ }
2610
2852
  const _sfc_main$9 = {
2853
+ name: "LogAxisRuler",
2854
+ props: {
2855
+ min: {
2856
+ type: [Number, String],
2857
+ default: 0.1
2858
+ },
2859
+ max: {
2860
+ type: [Number, String],
2861
+ default: 100
2862
+ },
2863
+ visible: {
2864
+ type: Boolean,
2865
+ default: true
2866
+ },
2867
+ // top:曲线上方;bottom:表头底沿。8.22对数轴
2868
+ placement: {
2869
+ type: String,
2870
+ default: "top"
2871
+ }
2872
+ },
2873
+ computed: {
2874
+ // 刻度随量程重算,标 lg;边控关显示时整尺隐藏。8.24
2875
+ marks() {
2876
+ return buildLogDecadeTickMarks(this.min, this.max);
2877
+ }
2878
+ },
2879
+ methods: {
2880
+ // 两端刻度贴边,避免 translateX(-50%) 被裁掉。8.22对数轴
2881
+ tickStyle(mark) {
2882
+ if (mark.percent <= 2) {
2883
+ return { left: "2px", transform: "none" };
2884
+ }
2885
+ if (mark.percent >= 98) {
2886
+ return { left: "auto", right: "2px", transform: "none" };
2887
+ }
2888
+ return { left: mark.percent + "%" };
2889
+ }
2890
+ }
2891
+ };
2892
+ function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
2893
+ return $props.visible && $options.marks.length ? (openBlock(), createElementBlock("div", {
2894
+ key: 0,
2895
+ class: normalizeClass(["kd-log-axis-ruler", { "kd-log-axis-ruler--top": $props.placement === "top" }])
2896
+ }, [
2897
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.marks, (mark) => {
2898
+ return openBlock(), createElementBlock("span", {
2899
+ key: String(mark.value),
2900
+ class: "kd-log-axis-ruler__tick",
2901
+ style: normalizeStyle($options.tickStyle(mark))
2902
+ }, toDisplayString(mark.label), 5);
2903
+ }), 128))
2904
+ ], 2)) : createCommentVNode("", true);
2905
+ }
2906
+ const LogAxisRuler = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$9], ["__scopeId", "data-v-17ebb571"]]);
2907
+ const _sfc_main$8 = {
2611
2908
  name: "HeaderItem",
2612
2909
  props: {
2613
2910
  lineRange: {
@@ -2654,6 +2951,11 @@ const _sfc_main$9 = {
2654
2951
  headerData: {
2655
2952
  type: Object,
2656
2953
  default: () => ({})
2954
+ },
2955
+ // 泳道开了对数轴时,表头当前值出 lg。8.24
2956
+ isLogScale: {
2957
+ type: [Boolean, String, Number],
2958
+ default: false
2657
2959
  }
2658
2960
  },
2659
2961
  methods: {
@@ -2692,7 +2994,7 @@ const _sfc_main$9 = {
2692
2994
  if (!Number.isFinite(max)) return false;
2693
2995
  return max > this.line.max || min < this.line.min;
2694
2996
  },
2695
- // 显示当前数据最新值
2997
+ // 显示当前数据最新值;对数道出 lg(x)。8.24
2696
2998
  getCurrentData() {
2697
2999
  if (this.formCache.displayType == "float") {
2698
3000
  return "";
@@ -2703,7 +3005,13 @@ const _sfc_main$9 = {
2703
3005
  )) {
2704
3006
  return "--";
2705
3007
  }
2706
- return this.headerData[this.line.paramId] !== null && this.headerData[this.line.paramId] !== void 0 && this.headerData[this.line.paramId] !== "" ? typeof +this.headerData[this.line.paramId] === "number" ? Number(Number(this.headerData[this.line.paramId]).toFixed(3)) : this.headerData[this.line.paramId] : "--";
3008
+ const raw = this.headerData[this.line.paramId];
3009
+ if (raw === null || raw === void 0 || raw === "") return "--";
3010
+ if (isLogScaleFlag(this.isLogScale)) {
3011
+ const lg = formatLanePointValue(raw);
3012
+ return lg == null ? "--" : lg;
3013
+ }
3014
+ return typeof +raw === "number" ? Number(Number(raw).toFixed(3)) : raw;
2707
3015
  },
2708
3016
  getParamName(line) {
2709
3017
  const nameConfig = this.paramsNameMap[line.paramId];
@@ -2792,7 +3100,7 @@ const _hoisted_1$8 = { class: "kd-lane-chart-container-text-container" };
2792
3100
  const _hoisted_2$7 = { class: "left" };
2793
3101
  const _hoisted_3$6 = { class: "center" };
2794
3102
  const _hoisted_4$6 = { class: "right" };
2795
- function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
3103
+ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
2796
3104
  return openBlock(), createElementBlock("div", {
2797
3105
  class: normalizeClass(["kd-lane-chart-container-header-item", { "kd-lane-chart-container-header-item_warning": $options.isShowWarning() }]),
2798
3106
  style: normalizeStyle($options.headerItemStyle),
@@ -2819,8 +3127,8 @@ function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
2819
3127
  ])
2820
3128
  ], 6);
2821
3129
  }
2822
- const HeaderItem = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$9], ["__scopeId", "data-v-3a2fbd9e"]]);
2823
- const _sfc_main$8 = {
3130
+ const HeaderItem = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$8], ["__scopeId", "data-v-466dec24"]]);
3131
+ const _sfc_main$7 = {
2824
3132
  name: "LegendItem",
2825
3133
  props: {
2826
3134
  lineRange: {
@@ -2867,6 +3175,11 @@ const _sfc_main$8 = {
2867
3175
  headerData: {
2868
3176
  type: Object,
2869
3177
  default: () => ({})
3178
+ },
3179
+ // 泳道开了对数轴时,表头当前值出 lg。8.24
3180
+ isLogScale: {
3181
+ type: [Boolean, String, Number],
3182
+ default: false
2870
3183
  }
2871
3184
  },
2872
3185
  methods: {
@@ -2884,7 +3197,13 @@ const _sfc_main$8 = {
2884
3197
  if (!Object.prototype.hasOwnProperty.call(this.headerData, paramId)) {
2885
3198
  return "--";
2886
3199
  }
2887
- return this.headerData[paramId] !== null && this.headerData[paramId] !== void 0 && this.headerData[paramId] !== "" ? typeof +this.headerData[paramId] === "number" ? Number(Number(this.headerData[paramId]).toFixed(3)) : this.headerData[paramId] : "--";
3200
+ const raw = this.headerData[paramId];
3201
+ if (raw === null || raw === void 0 || raw === "") return "--";
3202
+ if (isLogScaleFlag(this.isLogScale)) {
3203
+ const lg = formatLanePointValue(raw);
3204
+ return lg == null ? "--" : lg;
3205
+ }
3206
+ return typeof +raw === "number" ? Number(Number(raw).toFixed(3)) : raw;
2888
3207
  },
2889
3208
  toggleLegend(label) {
2890
3209
  const temp = { ...this.line };
@@ -2945,7 +3264,7 @@ const _hoisted_7$3 = {
2945
3264
  class: "legend-data"
2946
3265
  };
2947
3266
  const _hoisted_8$2 = { class: "scale-right" };
2948
- function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
3267
+ function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
2949
3268
  return openBlock(), createElementBlock("div", {
2950
3269
  class: "kd-lane-chart-container-legend-item",
2951
3270
  style: normalizeStyle($options.legendItemStyle)
@@ -2979,7 +3298,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
2979
3298
  ])
2980
3299
  ], 4);
2981
3300
  }
2982
- const LegendItem = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$8], ["__scopeId", "data-v-9206b887"]]);
3301
+ const LegendItem = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$7], ["__scopeId", "data-v-41c24d2f"]]);
2983
3302
  const TREND_LINE_STYLE = {
2984
3303
  stroke: "#FF9800",
2985
3304
  lineWidth: 2,
@@ -3341,8 +3660,8 @@ function findSeriesForDepth(chart, paramId, depth) {
3341
3660
  if (String(seriesParamId(s)) !== String(paramId)) continue;
3342
3661
  const info = {
3343
3662
  seriesIndex: i,
3344
- xAxisIndex: axisIndexOf$1(s.xAxisIndex),
3345
- yAxisIndex: axisIndexOf$1(s.yAxisIndex)
3663
+ xAxisIndex: axisIndexOf(s.xAxisIndex),
3664
+ yAxisIndex: axisIndexOf(s.yAxisIndex)
3346
3665
  };
3347
3666
  fallback = info;
3348
3667
  const yAx = yAxes[info.yAxisIndex];
@@ -3382,7 +3701,7 @@ function isPointerInAnyGrid(chart, offsetX, offsetY) {
3382
3701
  }
3383
3702
  return false;
3384
3703
  }
3385
- function axisIndexOf$1(val) {
3704
+ function axisIndexOf(val) {
3386
3705
  const n = Array.isArray(val) ? val[0] : val;
3387
3706
  return Number(n ?? 0);
3388
3707
  }
@@ -3394,12 +3713,12 @@ function pixelToData(chart, paramId, offsetX, offsetY, loose = false) {
3394
3713
  try {
3395
3714
  if (!loose && !chart.containPixel({ gridIndex: g }, [offsetX, offsetY])) continue;
3396
3715
  const seriesList = (option.series || []).filter(matchParam);
3397
- const series = seriesList.find((s) => axisIndexOf$1(s.yAxisIndex) === g) || seriesList[0];
3716
+ const series = seriesList.find((s) => axisIndexOf(s.yAxisIndex) === g) || seriesList[0];
3398
3717
  const finders = [];
3399
3718
  if (series) {
3400
3719
  finders.push({
3401
- xAxisIndex: axisIndexOf$1(series.xAxisIndex),
3402
- yAxisIndex: axisIndexOf$1(series.yAxisIndex)
3720
+ xAxisIndex: axisIndexOf(series.xAxisIndex),
3721
+ yAxisIndex: axisIndexOf(series.yAxisIndex)
3403
3722
  });
3404
3723
  const seriesIndex = (option.series || []).indexOf(series);
3405
3724
  if (seriesIndex >= 0) finders.push({ seriesIndex });
@@ -3427,356 +3746,59 @@ function pixelToData(chart, paramId, offsetX, offsetY, loose = false) {
3427
3746
  value: x,
3428
3747
  depth: y,
3429
3748
  xAxisIndex: finder.xAxisIndex ?? 0,
3430
- yAxisIndex: finder.yAxisIndex ?? g
3431
- };
3432
- }
3433
- } catch (e) {
3434
- }
3435
- }
3436
- } catch (e) {
3437
- }
3438
- }
3439
- return null;
3440
- }
3441
- function dataToPixel(chart, paramId, value, depth) {
3442
- const finder = findSeriesForDepth(chart, paramId, depth);
3443
- const finders = [
3444
- { xAxisIndex: finder.xAxisIndex, yAxisIndex: finder.yAxisIndex },
3445
- { seriesIndex: finder.seriesIndex },
3446
- { gridIndex: finder.yAxisIndex ?? 0 }
3447
- ];
3448
- for (const f of finders) {
3449
- try {
3450
- const px = chart.convertToPixel(f, [value, depth]);
3451
- if (px && Number.isFinite(px[0]) && Number.isFinite(px[1])) return px;
3452
- } catch (e) {
3453
- }
3454
- }
3455
- return null;
3456
- }
3457
- function snapDepthToEdge(depth, depthMin, depthMax, tol) {
3458
- if (!Number.isFinite(depth)) return depth;
3459
- const lo = Number.isFinite(depthMin) && Number.isFinite(depthMax) ? Math.min(depthMin, depthMax) : depthMin;
3460
- const hi = Number.isFinite(depthMin) && Number.isFinite(depthMax) ? Math.max(depthMin, depthMax) : depthMax;
3461
- if (!Number.isFinite(lo) || !Number.isFinite(hi)) return depth;
3462
- let d = depth;
3463
- if (Math.abs(d - lo) <= tol) d = lo;
3464
- if (Math.abs(d - hi) <= tol) d = hi;
3465
- return Math.max(lo, Math.min(hi, d));
3466
- }
3467
- function getAxisRange(chart, paramId, depth) {
3468
- const option = chart.getOption() || {};
3469
- const finder = findSeriesForDepth(chart, paramId, depth);
3470
- const xAx = (option.xAxis || [])[finder.xAxisIndex] || {};
3471
- const yAx = (option.yAxis || [])[finder.yAxisIndex] || {};
3472
- const xMin = Number(xAx.min);
3473
- const xMax = Number(xAx.max);
3474
- const yMin = Number(yAx.min);
3475
- const yMax = Number(yAx.max);
3476
- return {
3477
- valueMin: Number.isFinite(xMin) ? xMin : 0,
3478
- valueMax: Number.isFinite(xMax) ? xMax : 100,
3479
- depthMin: Number.isFinite(yMin) ? Math.min(yMin, yMax) : 0,
3480
- depthMax: Number.isFinite(yMax) ? Math.max(yMin, yMax) : 100
3481
- };
3482
- }
3483
- const LOG_AXIS_MIN_POSITIVE = 0.1;
3484
- const LOG_AXIS_BASE = 10;
3485
- function isLogScaleFlag(val) {
3486
- return val === true || val === "true" || val === 1 || val === "1";
3487
- }
3488
- function isLaneLogScale(lane) {
3489
- return !!(lane && isLogScaleFlag(lane.isLogScale));
3490
- }
3491
- function isLogAxisLabelVisible(formCache) {
3492
- if (!formCache) return true;
3493
- return formCache.showLogAxis !== false && formCache.showLogAxis !== "false" && formCache.showLogAxis !== 0 && formCache.showLogAxis !== "0";
3494
- }
3495
- function normalizeLogRange(min, max) {
3496
- let lo = Number(min);
3497
- let hi = Number(max);
3498
- if (!Number.isFinite(lo) || lo <= 0) lo = LOG_AXIS_MIN_POSITIVE;
3499
- if (!Number.isFinite(hi) || hi <= 0) hi = lo * LOG_AXIS_BASE;
3500
- if (hi <= lo) hi = lo * LOG_AXIS_BASE;
3501
- return { min: lo, max: hi };
3502
- }
3503
- function toLogPlotX(raw) {
3504
- const n = Number(raw);
3505
- if (!Number.isFinite(n) || n <= 0) return null;
3506
- const logv = Math.log10(n);
3507
- return Number.isFinite(logv) ? logv : null;
3508
- }
3509
- function toLaneDrawX(plotX, lane, xAx, digits = 3) {
3510
- if (!isLaneLogScale(lane)) return plotX;
3511
- const n = Number(plotX);
3512
- if (!Number.isFinite(n)) return plotX;
3513
- return Number(n.toFixed(digits));
3514
- }
3515
- function axisIndexOf(val) {
3516
- const n = Array.isArray(val) ? val[0] : val;
3517
- return Number(n ?? 0);
3518
- }
3519
- function findLogTrendSeries(chart, paramId) {
3520
- const option = chart.getOption() || {};
3521
- return (option.series || []).find((s) => {
3522
- if (!s || s.type !== "line") return false;
3523
- const name = Array.isArray(s.name) ? s.name[0] : s.name;
3524
- if (name === "helper" || name === "log-grid") return false;
3525
- return String(s.paramId) === String(paramId);
3526
- }) || null;
3527
- }
3528
- function pixelToLogTrendData(chart, paramId, offsetX, offsetY, lane, lineRange, digits = 3) {
3529
- if (!chart || !isLaneLogScale(lane)) return null;
3530
- const series = findLogTrendSeries(chart, paramId);
3531
- const xAxisIndex = series ? axisIndexOf(series.xAxisIndex) : 0;
3532
- const yAxisIndex = series ? axisIndexOf(series.yAxisIndex) : 0;
3533
- const plot = resolveLaneLogPlotRange(lane, lineRange);
3534
- const extent = toLogAxisExtent(plot.min, plot.max);
3535
- let x0;
3536
- let x1;
3537
- let depth;
3538
- try {
3539
- x0 = chart.convertToPixel({ xAxisIndex }, extent.min);
3540
- x1 = chart.convertToPixel({ xAxisIndex }, extent.max);
3541
- } catch (e) {
3542
- return null;
3543
- }
3544
- try {
3545
- depth = chart.convertFromPixel({ yAxisIndex }, offsetY);
3546
- } catch (e) {
3547
- depth = null;
3548
- }
3549
- if (!Number.isFinite(x0) || !Number.isFinite(x1) || x1 === x0) return null;
3550
- if (!Number.isFinite(depth)) return null;
3551
- const lg = extent.min + (offsetX - x0) / (x1 - x0) * (extent.max - extent.min);
3552
- if (!Number.isFinite(lg)) return null;
3553
- return {
3554
- value: Number(lg.toFixed(digits)),
3555
- depth,
3556
- xAxisIndex,
3557
- yAxisIndex
3558
- };
3559
- }
3560
- function seriesLogXAtDepth(chart, paramId, depth, digits = 3) {
3561
- const series = findLogTrendSeries(chart, paramId);
3562
- if (!series || !series.data || !Number.isFinite(Number(depth))) return null;
3563
- let best = null;
3564
- series.data.forEach((pt) => {
3565
- const x = Array.isArray(pt) ? Number(pt[0]) : Number(pt && pt.value && pt.value[0]);
3566
- const y = Array.isArray(pt) ? Number(pt[1]) : Number(pt && pt.value && pt.value[1]);
3567
- if (!Number.isFinite(x) || !Number.isFinite(y)) return;
3568
- const dist = Math.abs(y - Number(depth));
3569
- if (!best || dist < best.dist) best = { x, dist };
3570
- });
3571
- if (!best) return null;
3572
- return Number(best.x.toFixed(digits));
3573
- }
3574
- function logTrendDataToPixel(chart, paramId, lg, depth) {
3575
- if (!chart) return null;
3576
- const series = findLogTrendSeries(chart, paramId);
3577
- const xAxisIndex = series ? axisIndexOf(series.xAxisIndex) : 0;
3578
- const yAxisIndex = series ? axisIndexOf(series.yAxisIndex) : 0;
3579
- try {
3580
- const px = chart.convertToPixel({ xAxisIndex, yAxisIndex }, [lg, depth]);
3581
- if (px && Number.isFinite(px[0]) && Number.isFinite(px[1])) return px;
3582
- } catch (e) {
3583
- }
3584
- try {
3585
- const x = chart.convertToPixel({ xAxisIndex }, lg);
3586
- const y = chart.convertToPixel({ yAxisIndex }, depth);
3587
- if (Number.isFinite(x) && Number.isFinite(y)) return [x, y];
3588
- } catch (e) {
3589
- return null;
3590
- }
3591
- return null;
3592
- }
3593
- function toLogAxisExtent(min, max) {
3594
- const range = normalizeLogRange(min, max);
3595
- return {
3596
- min: Math.log10(range.min),
3597
- max: Math.log10(range.max)
3598
- };
3599
- }
3600
- function mapSeriesDataXToLog(data) {
3601
- return (data || []).map((item) => {
3602
- if (Array.isArray(item)) {
3603
- return [toLogPlotX(item[0]), item[1], item[2]];
3604
- }
3605
- if (item && Array.isArray(item.value)) {
3606
- return {
3607
- ...item,
3608
- value: [toLogPlotX(item.value[0]), item.value[1]]
3609
- };
3610
- }
3611
- return item;
3612
- });
3613
- }
3614
- function formatLogTick(value) {
3615
- const n = Number(value);
3616
- if (n === 0) return "0";
3617
- if (!Number.isFinite(n) || n <= 0) return "";
3618
- const exp = Math.log10(n);
3619
- if (Math.abs(exp - Math.round(exp)) < 1e-6 && (n >= 1e3 || n < 0.01)) {
3620
- return `1e${Math.round(exp)}`;
3621
- }
3622
- if (n >= 1) return String(Number(n.toPrecision(4)));
3623
- return String(Number(n.toPrecision(3)));
3624
- }
3625
- function niceLogDecadeRange(min, max) {
3626
- const range = normalizeLogRange(min, max);
3627
- let niceMin = 10 ** Math.floor(Math.log10(range.min) + 1e-9);
3628
- let niceMax = 10 ** Math.ceil(Math.log10(range.max) - 1e-9);
3629
- if (!Number.isFinite(niceMin) || niceMin <= 0) niceMin = LOG_AXIS_MIN_POSITIVE;
3630
- if (!Number.isFinite(niceMax) || niceMax <= niceMin) {
3631
- niceMax = niceMin * LOG_AXIS_BASE;
3632
- }
3633
- return { min: niceMin, max: niceMax };
3634
- }
3635
- function resolveLaneLogPlotRange(lane, lineRange = {}) {
3636
- let lo = Infinity;
3637
- let hi = -Infinity;
3638
- (lane && lane.lines || []).forEach((line) => {
3639
- if (!line) return;
3640
- const r = lineRange[line.lineId] || {};
3641
- const cfgMin = Number(line.min);
3642
- const cfgMax = Number(line.max);
3643
- const useMin = Number.isFinite(cfgMin) && cfgMin > 0 ? cfgMin : Number(r.min);
3644
- const useMax = Number.isFinite(cfgMax) && cfgMax > 0 ? cfgMax : Number(r.max);
3645
- if (Number.isFinite(useMin) && useMin > 0) lo = Math.min(lo, useMin);
3646
- if (Number.isFinite(useMax) && useMax > 0) hi = Math.max(hi, useMax);
3647
- });
3648
- return niceLogDecadeRange(
3649
- Number.isFinite(lo) ? lo : LOG_AXIS_MIN_POSITIVE,
3650
- Number.isFinite(hi) ? hi : LOG_AXIS_MIN_POSITIVE * LOG_AXIS_BASE
3651
- );
3652
- }
3653
- function buildLogLaneTenLineValues(min, max) {
3654
- const range = niceLogDecadeRange(min, max);
3655
- const ratio = range.max / range.min;
3656
- const values = [];
3657
- for (let m = 1; m <= 10; m++) {
3658
- values.push(range.min * ratio ** Math.log10(m));
3749
+ yAxisIndex: finder.yAxisIndex ?? g
3750
+ };
3751
+ }
3752
+ } catch (e) {
3753
+ }
3754
+ }
3755
+ } catch (e) {
3756
+ }
3659
3757
  }
3660
- return values;
3661
- }
3662
- function buildLogLaneTenLineLgValues(min, max) {
3663
- return buildLogLaneTenLineValues(min, max).map((v) => Math.log10(v)).filter((v) => Number.isFinite(v));
3758
+ return null;
3664
3759
  }
3665
- function buildLogDecadeTickMarks(min, max) {
3666
- const range = niceLogDecadeRange(min, max);
3667
- const loExp = Math.round(Math.log10(range.min));
3668
- const hiExp = Math.round(Math.log10(range.max));
3669
- const marks = [];
3670
- for (let e = loExp; e <= hiExp; e++) {
3671
- const value = 10 ** e;
3672
- marks.push({
3673
- value,
3674
- label: formatLogTick(value),
3675
- percent: logValueToPercent(value, range.min, range.max)
3676
- });
3760
+ function dataToPixel(chart, paramId, value, depth) {
3761
+ const finder = findSeriesForDepth(chart, paramId, depth);
3762
+ const finders = [
3763
+ { xAxisIndex: finder.xAxisIndex, yAxisIndex: finder.yAxisIndex },
3764
+ { seriesIndex: finder.seriesIndex },
3765
+ { gridIndex: finder.yAxisIndex ?? 0 }
3766
+ ];
3767
+ for (const f of finders) {
3768
+ try {
3769
+ const px = chart.convertToPixel(f, [value, depth]);
3770
+ if (px && Number.isFinite(px[0]) && Number.isFinite(px[1])) return px;
3771
+ } catch (e) {
3772
+ }
3677
3773
  }
3678
- return marks;
3774
+ return null;
3679
3775
  }
3680
- function logValueToPercent(value, min, max) {
3681
- const range = normalizeLogRange(min, max);
3682
- const v = Number(value);
3683
- if (!Number.isFinite(v) || v <= 0) return 0;
3684
- const clamped = Math.max(range.min, Math.min(range.max, v));
3685
- const span = Math.log(range.max) - Math.log(range.min);
3686
- if (span <= 0) return 0;
3687
- return (Math.log(clamped) - Math.log(range.min)) / span * 100;
3776
+ function snapDepthToEdge(depth, depthMin, depthMax, tol) {
3777
+ if (!Number.isFinite(depth)) return depth;
3778
+ const lo = Number.isFinite(depthMin) && Number.isFinite(depthMax) ? Math.min(depthMin, depthMax) : depthMin;
3779
+ const hi = Number.isFinite(depthMin) && Number.isFinite(depthMax) ? Math.max(depthMin, depthMax) : depthMax;
3780
+ if (!Number.isFinite(lo) || !Number.isFinite(hi)) return depth;
3781
+ let d = depth;
3782
+ if (Math.abs(d - lo) <= tol) d = lo;
3783
+ if (Math.abs(d - hi) <= tol) d = hi;
3784
+ return Math.max(lo, Math.min(hi, d));
3688
3785
  }
3689
- function buildLogXAxisOption({
3690
- gridIndex = 0,
3691
- min,
3692
- max,
3693
- showSplitLine = true,
3694
- splitLineColor
3695
- } = {}) {
3696
- const range = niceLogDecadeRange(min, max);
3697
- const extent = toLogAxisExtent(range.min, range.max);
3698
- const lineStyle = {
3699
- color: splitLineColor,
3700
- type: "dashed",
3701
- width: 1
3702
- };
3786
+ function getAxisRange(chart, paramId, depth) {
3787
+ const option = chart.getOption() || {};
3788
+ const finder = findSeriesForDepth(chart, paramId, depth);
3789
+ const xAx = (option.xAxis || [])[finder.xAxisIndex] || {};
3790
+ const yAx = (option.yAxis || [])[finder.yAxisIndex] || {};
3791
+ const xMin = Number(xAx.min);
3792
+ const xMax = Number(xAx.max);
3793
+ const yMin = Number(yAx.min);
3794
+ const yMax = Number(yAx.max);
3703
3795
  return {
3704
- gridIndex,
3705
- show: true,
3706
- type: "value",
3707
- min: extent.min,
3708
- max: extent.max,
3709
- minorTick: { show: false },
3710
- minorSplitLine: {
3711
- show: false,
3712
- lineStyle
3713
- },
3714
- splitLine: {
3715
- show: showSplitLine,
3716
- showMaxLine: false,
3717
- showMinLine: false,
3718
- lineStyle
3719
- },
3720
- axisLabel: { show: false },
3721
- axisLine: { show: false },
3722
- axisTick: { show: false }
3796
+ valueMin: Number.isFinite(xMin) ? xMin : 0,
3797
+ valueMax: Number.isFinite(xMax) ? xMax : 100,
3798
+ depthMin: Number.isFinite(yMin) ? Math.min(yMin, yMax) : 0,
3799
+ depthMax: Number.isFinite(yMax) ? Math.max(yMin, yMax) : 100
3723
3800
  };
3724
3801
  }
3725
- const _sfc_main$7 = {
3726
- name: "LogAxisRuler",
3727
- props: {
3728
- min: {
3729
- type: [Number, String],
3730
- default: 0.1
3731
- },
3732
- max: {
3733
- type: [Number, String],
3734
- default: 100
3735
- },
3736
- visible: {
3737
- type: Boolean,
3738
- default: true
3739
- },
3740
- // top:曲线上方;bottom:表头底沿。8.22对数轴
3741
- placement: {
3742
- type: String,
3743
- default: "top"
3744
- }
3745
- },
3746
- computed: {
3747
- // 刻度随量程重算,边控关显示时整尺隐藏。8.22对数轴
3748
- marks() {
3749
- return buildLogDecadeTickMarks(this.min, this.max);
3750
- }
3751
- },
3752
- methods: {
3753
- // 两端刻度贴边,避免 translateX(-50%) 被裁掉。8.22对数轴
3754
- tickStyle(mark) {
3755
- if (mark.percent <= 2) {
3756
- return { left: "2px", transform: "none" };
3757
- }
3758
- if (mark.percent >= 98) {
3759
- return { left: "auto", right: "2px", transform: "none" };
3760
- }
3761
- return { left: mark.percent + "%" };
3762
- }
3763
- }
3764
- };
3765
- function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
3766
- return $props.visible && $options.marks.length ? (openBlock(), createElementBlock("div", {
3767
- key: 0,
3768
- class: normalizeClass(["kd-log-axis-ruler", { "kd-log-axis-ruler--top": $props.placement === "top" }])
3769
- }, [
3770
- (openBlock(true), createElementBlock(Fragment, null, renderList($options.marks, (mark) => {
3771
- return openBlock(), createElementBlock("span", {
3772
- key: String(mark.value),
3773
- class: "kd-log-axis-ruler__tick",
3774
- style: normalizeStyle($options.tickStyle(mark))
3775
- }, toDisplayString(mark.label), 5);
3776
- }), 128))
3777
- ], 2)) : createCommentVNode("", true);
3778
- }
3779
- const LogAxisRuler = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$7], ["__scopeId", "data-v-d5ed1748"]]);
3780
3802
  class TrendLineManager {
3781
3803
  constructor(host) {
3782
3804
  this.host = host;
@@ -3790,15 +3812,27 @@ class TrendLineManager {
3790
3812
  this._zoomRaf = null;
3791
3813
  this._zoomPending = false;
3792
3814
  this._zoomEndTimer = null;
3815
+ this._graphicIds = /* @__PURE__ */ Object.create(null);
3793
3816
  this._ignoreClickUntil = 0;
3794
3817
  }
3795
3818
  destroy() {
3796
3819
  this._clearClickTimer();
3797
3820
  this._endDrag();
3798
3821
  Array.from(this.binds.keys()).forEach((laneId) => this.unbindChart(laneId));
3799
- if (this._raf) cancelAnimationFrame(this._raf);
3800
- if (this._zoomRaf) cancelAnimationFrame(this._zoomRaf);
3801
- if (this._zoomEndTimer) clearTimeout(this._zoomEndTimer);
3822
+ if (this._raf) {
3823
+ cancelAnimationFrame(this._raf);
3824
+ this._raf = null;
3825
+ }
3826
+ if (this._zoomRaf) {
3827
+ cancelAnimationFrame(this._zoomRaf);
3828
+ this._zoomRaf = null;
3829
+ }
3830
+ if (this._zoomEndTimer) {
3831
+ clearTimeout(this._zoomEndTimer);
3832
+ this._zoomEndTimer = null;
3833
+ }
3834
+ this.store = /* @__PURE__ */ Object.create(null);
3835
+ this._graphicIds = /* @__PURE__ */ Object.create(null);
3802
3836
  }
3803
3837
  /** 从模板 line.trendSegments 回显;已有 store 的曲线不覆盖,避免编辑中被模板刷新冲掉。8.21 */
3804
3838
  hydrateFromTemplate(template) {
@@ -3939,15 +3973,13 @@ class TrendLineManager {
3939
3973
  }
3940
3974
  }
3941
3975
  /** 图表重绘后对齐叠加层;拖拽中跳过,避免和 _onDragMove 抢 setOption。8.21 */
3976
+ // 只排一帧,不再连刷两次 renderAll(会闪)。8.24
3942
3977
  scheduleRender() {
3943
3978
  if (this.dragSession) return;
3944
3979
  if (this._raf) return;
3945
3980
  this._raf = requestAnimationFrame(() => {
3946
3981
  this._raf = null;
3947
3982
  this.renderAll();
3948
- requestAnimationFrame(() => {
3949
- if (!this.dragSession) this.renderAll();
3950
- });
3951
3983
  });
3952
3984
  }
3953
3985
  /** 缩放过程用 ZR 就地改像素,结束后再整层重画,避免 replaceMerge 把线冲掉。8.22 */
@@ -3994,7 +4026,7 @@ class TrendLineManager {
3994
4026
  patches.push(...this._buildPatches(chart, target));
3995
4027
  });
3996
4028
  if (!patches.length) return;
3997
- if (!this._applyPatchesViaZr(chart, patches)) {
4029
+ if (!this._applyPatchesViaZr(chart, patches) && !this._zoomPending) {
3998
4030
  this.renderLane(laneId);
3999
4031
  }
4000
4032
  }
@@ -4145,8 +4177,7 @@ class TrendLineManager {
4145
4177
  this.dragSession = null;
4146
4178
  this._setPanLocked(false, true);
4147
4179
  this._ignoreClickUntil = Date.now() + 300;
4148
- this.renderLane(sessionTarget.laneId);
4149
- this._emitChange(sessionTarget);
4180
+ this._emitChange(sessionTarget, { redraw: false });
4150
4181
  };
4151
4182
  el.__trendOnDown = onDown;
4152
4183
  el.__trendOnDrag = onDrag;
@@ -4170,12 +4201,32 @@ class TrendLineManager {
4170
4201
  }
4171
4202
  return applied > 0;
4172
4203
  }
4173
- renderAll() {
4204
+ // 只 merge 新图形,不动已有线。8.24
4205
+ _addGraphicElements(chart, elements) {
4206
+ if (!elements.length) return;
4207
+ chart.setOption(
4208
+ {
4209
+ graphic: elements.map((el) => ({ ...el, $action: "merge" }))
4210
+ },
4211
+ { silent: true, lazyUpdate: false }
4212
+ );
4213
+ }
4214
+ // 按 id 删除,不 replaceMerge 整层 graphic。8.24
4215
+ _removeGraphicIds(chart, ids) {
4216
+ if (!ids.length) return;
4217
+ chart.setOption(
4218
+ {
4219
+ graphic: ids.map((id) => ({ id, $action: "remove" }))
4220
+ },
4221
+ { silent: true, lazyUpdate: false }
4222
+ );
4223
+ }
4224
+ renderAll(forceReplace = false) {
4174
4225
  const lanes = this.host.currentTemplate && this.host.currentTemplate.lanes || [];
4175
- lanes.forEach((lane) => this.renderLane(lane.laneId));
4226
+ lanes.forEach((lane) => this.renderLane(lane.laneId, forceReplace));
4176
4227
  }
4177
- /** 用 graphic replaceMerge 整层替换,避免和图表其它 graphic 混在一起。8.21 */
4178
- renderLane(laneId) {
4228
+ /** 已有线只改 ZR 形状;新点/新线段单独 merge 进去,绝不整层 graphic 替换。8.24 */
4229
+ renderLane(laneId, forceReplace = false) {
4179
4230
  const chart = this.getChart(laneId);
4180
4231
  if (!chart) return;
4181
4232
  const targets = this.listDrawableTargets().filter((t) => t.laneId === laneId);
@@ -4185,12 +4236,28 @@ class TrendLineManager {
4185
4236
  });
4186
4237
  const hasKnots = targets.some((t) => (t.segments || []).some((s) => (s.knots || []).length));
4187
4238
  if (hasKnots && !elements.length) return;
4188
- chart.setOption(
4189
- { graphic: { elements } },
4190
- { replaceMerge: ["graphic"], lazyUpdate: false, silent: true }
4191
- );
4239
+ const nextIds = elements.map((el) => el.id);
4240
+ const prevIds = this._graphicIds[laneId] || [];
4241
+ const prevSet = new Set(prevIds);
4242
+ const nextSet = new Set(nextIds);
4243
+ const added = elements.filter((el) => !prevSet.has(el.id));
4244
+ const kept = elements.filter((el) => prevSet.has(el.id));
4245
+ const removedIds = prevIds.filter((id) => !nextSet.has(id));
4246
+ if (forceReplace) {
4247
+ this._removeGraphicIds(chart, prevIds);
4248
+ this._addGraphicElements(chart, elements);
4249
+ } else {
4250
+ if (kept.length) {
4251
+ this._applyPatchesViaZr(
4252
+ chart,
4253
+ kept.map((el) => ({ id: el.id, shape: el.shape }))
4254
+ );
4255
+ }
4256
+ if (removedIds.length) this._removeGraphicIds(chart, removedIds);
4257
+ if (added.length) this._addGraphicElements(chart, added);
4258
+ }
4259
+ this._graphicIds[laneId] = nextIds;
4192
4260
  this._bindPointInteractions(chart, laneId);
4193
- requestAnimationFrame(() => this._bindPointInteractions(chart, laneId));
4194
4261
  this.updateCursor(laneId);
4195
4262
  }
4196
4263
  _buildElements(chart, target) {
@@ -4444,7 +4511,7 @@ class TrendLineManager {
4444
4511
  }
4445
4512
  seg.knots = [...rest, knot].sort((a, b) => a.depth - b.depth);
4446
4513
  this.renderLane(target.laneId);
4447
- this._emitChange(target);
4514
+ this._emitChange(target, { redraw: false });
4448
4515
  }
4449
4516
  /** 取未关闭的最后一段;没有或已 _closed 则开新段。8.21 */
4450
4517
  _ensureActiveSegment(key) {
@@ -4488,7 +4555,7 @@ class TrendLineManager {
4488
4555
  const target = this.listDrawableTargets().find((t) => t.key === k);
4489
4556
  if (target) {
4490
4557
  this.renderLane(target.laneId);
4491
- this._emitChange(target);
4558
+ this._emitChange(target, { redraw: false });
4492
4559
  }
4493
4560
  return true;
4494
4561
  }
@@ -4507,15 +4574,15 @@ class TrendLineManager {
4507
4574
  segments: []
4508
4575
  });
4509
4576
  });
4510
- this.renderAll();
4577
+ this.renderAll(true);
4511
4578
  }
4512
4579
  /** 清空指定曲线的控制点;不传 key 则清当前编辑曲线。8.21 */
4513
4580
  resetTrendLine(key) {
4514
4581
  const target = key ? this.listDrawableTargets().find((t) => t.key === key) : this.getActiveTarget() || this.listDrawableTargets().find((t) => t.editable);
4515
4582
  if (!target) return;
4516
4583
  this.store[target.key] = { segments: [] };
4517
- this.renderLane(target.laneId);
4518
- this._emitChange(target);
4584
+ this.renderLane(target.laneId, true);
4585
+ this._emitChange(target, { redraw: false });
4519
4586
  }
4520
4587
  /** 删除一个控制点。段内只剩 0~1 个点时整段丢掉(画不出线)。8.21 */
4521
4588
  deleteKnot(payload) {
@@ -4533,8 +4600,8 @@ class TrendLineManager {
4533
4600
  }).filter((s) => s.knots.length > 0);
4534
4601
  const target = this.listDrawableTargets().find((t) => t.key === payload.key);
4535
4602
  const laneId = target && target.laneId || payload.laneId;
4536
- if (laneId) this.renderLane(laneId);
4537
- if (target) this._emitChange(target);
4603
+ if (laneId) this.renderLane(laneId, true);
4604
+ if (target) this._emitChange(target, { redraw: false });
4538
4605
  }
4539
4606
  /** 返回 geosteering trendLinePoint 格式的线段数组;8137 带上 isDouble / calcType。8.22 */
4540
4607
  getTrendLineData(mainId = "demo") {
@@ -4653,9 +4720,7 @@ class TrendLineManager {
4653
4720
  }
4654
4721
  this._ignoreClickUntil = Date.now() + 300;
4655
4722
  this.updateCursor(session.target.laneId);
4656
- this.renderLane(session.target.laneId);
4657
- if (emit) this._emitChange(session.target);
4658
- else this._scheduleRenderAfterVue();
4723
+ if (emit) this._emitChange(session.target, { redraw: false });
4659
4724
  }
4660
4725
  _clearClickTimer() {
4661
4726
  if (this.clickTimer) {
@@ -4664,25 +4729,23 @@ class TrendLineManager {
4664
4729
  }
4665
4730
  }
4666
4731
  /** 抛 trend-change(拖拽过程中不抛,只在松开时抛);不写回响应式模板。8.22 */
4667
- _emitChange(target) {
4732
+ // redraw=false:本地已画过,避免再 scheduleRender 把线闪掉。8.24
4733
+ _emitChange(target, { redraw = true } = {}) {
4668
4734
  const segments = cloneSegments(this.store[target.key] && this.store[target.key].segments || []);
4669
4735
  this.host.$emit("trend-change", {
4670
4736
  paramId: target.paramId,
4671
4737
  laneId: target.laneId,
4672
4738
  segments
4673
4739
  });
4674
- this._scheduleRenderAfterVue();
4740
+ if (redraw) this._scheduleRenderAfterVue();
4675
4741
  }
4676
4742
  /** 等 Vue / 图表 setOption 完成后再画叠加层。8.22 */
4743
+ // 只 nextTick 一次,不再叠 rAF 连刷。8.24
4677
4744
  _scheduleRenderAfterVue() {
4678
- const run = () => this.scheduleRender();
4679
4745
  if (this.host && typeof this.host.$nextTick === "function") {
4680
- this.host.$nextTick(() => {
4681
- run();
4682
- requestAnimationFrame(run);
4683
- });
4746
+ this.host.$nextTick(() => this.scheduleRender());
4684
4747
  } else {
4685
- requestAnimationFrame(run);
4748
+ this.scheduleRender();
4686
4749
  }
4687
4750
  }
4688
4751
  /** 手动填写不画镜像;模型计算或回显数据里已有 mirrorValue 则画第二条线。8.22 */
@@ -4867,7 +4930,7 @@ class TrendLineManager {
4867
4930
  }).filter((s) => s.knots.length > 0);
4868
4931
  this.renderLane(found.laneId);
4869
4932
  const target = this.listDrawableTargets().find((t) => t.key === key);
4870
- if (target) this._emitChange(target);
4933
+ if (target) this._emitChange(target, { redraw: false });
4871
4934
  }
4872
4935
  /** 模型计算抽屉确定:写入岩性/偏移并生成镜像值。8.22 */
4873
4936
  applyMoxingConfig(paramId, form) {
@@ -4938,7 +5001,7 @@ class TrendLineManager {
4938
5001
  seg.knots = [...rest, knot].sort((a, b) => a.depth - b.depth);
4939
5002
  this.renderLane(found.laneId);
4940
5003
  const target = this.listDrawableTargets().find((t) => t.key === key);
4941
- if (target) this._emitChange(target);
5004
+ if (target) this._emitChange(target, { redraw: false });
4942
5005
  }
4943
5006
  }
4944
5007
  const _sfc_main$6 = {
@@ -5103,12 +5166,16 @@ const _sfc_main$6 = {
5103
5166
  }
5104
5167
  if (this.resizeObserver) {
5105
5168
  this.resizeObserver.disconnect();
5169
+ this.resizeObserver = null;
5106
5170
  }
5107
5171
  if (this.resizeObserverContainer) {
5108
5172
  this.resizeObserverContainer.disconnect();
5173
+ this.resizeObserverContainer = null;
5109
5174
  }
5110
5175
  },
5111
5176
  methods: {
5177
+ isLaneLogScale,
5178
+ // 模板里判断对数道。8.24
5112
5179
  initStrategy() {
5113
5180
  if (!this.config || !this.config.caseId) {
5114
5181
  return;
@@ -5153,6 +5220,10 @@ const _sfc_main$6 = {
5153
5220
  });
5154
5221
  },
5155
5222
  setupResizeObserver() {
5223
+ if (this.resizeObserver) {
5224
+ this.resizeObserver.disconnect();
5225
+ this.resizeObserver = null;
5226
+ }
5156
5227
  const container = this.$refs.targetDom;
5157
5228
  if (container) {
5158
5229
  this.resizeObserver = new ResizeObserver(() => {
@@ -6294,16 +6365,18 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6294
6365
  line,
6295
6366
  paramsNameMap: $options.paramsNameMap
6296
6367
  }, { ref_for: true }, _ctx.$props, {
6368
+ "is-log-scale": $options.isLaneLogScale(lane),
6297
6369
  onContextmenu: withModifiers(($event) => $options.showContextMenu($event, line), ["prevent"]),
6298
6370
  onUpdateLine: $options.upsertLine
6299
- }), null, 16, ["line", "paramsNameMap", "onContextmenu", "onUpdateLine"])) : (openBlock(), createBlock(_component_LegendItem, mergeProps({
6371
+ }), null, 16, ["line", "paramsNameMap", "is-log-scale", "onContextmenu", "onUpdateLine"])) : (openBlock(), createBlock(_component_LegendItem, mergeProps({
6300
6372
  key: 1,
6301
6373
  line,
6302
6374
  paramsNameMap: $options.paramsNameMap
6303
6375
  }, { ref_for: true }, _ctx.$props, {
6376
+ "is-log-scale": $options.isLaneLogScale(lane),
6304
6377
  onContextmenu: withModifiers(($event) => $options.showContextMenu($event, line), ["prevent"]),
6305
6378
  onUpdateLine: $options.upsertLine
6306
- }), null, 16, ["line", "paramsNameMap", "onContextmenu", "onUpdateLine"]))
6379
+ }), null, 16, ["line", "paramsNameMap", "is-log-scale", "onContextmenu", "onUpdateLine"]))
6307
6380
  ], 2);
6308
6381
  }), 128))
6309
6382
  ]),
@@ -6332,6 +6405,8 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6332
6405
  group: { name: "laneGroup", pull: false, put: false },
6333
6406
  "item-key": "laneId",
6334
6407
  filter: $options.laneDragFilter,
6408
+ "prevent-on-filter": false,
6409
+ handle: $props.isGeomechanical ? ".kd-lane-chart-lane-header" : void 0,
6335
6410
  axis: "x"
6336
6411
  }, {
6337
6412
  default: withCtx(() => [
@@ -6408,16 +6483,18 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6408
6483
  line,
6409
6484
  paramsNameMap: $options.paramsNameMap
6410
6485
  }, { ref_for: true }, _ctx.$props, {
6486
+ "is-log-scale": $options.isLaneLogScale(lane),
6411
6487
  onContextmenu: withModifiers(($event) => $options.showContextMenu($event, line), ["prevent"]),
6412
6488
  onUpdateLine: $options.upsertLine
6413
- }), null, 16, ["line", "paramsNameMap", "onContextmenu", "onUpdateLine"])) : (openBlock(), createBlock(_component_LegendItem, mergeProps({
6489
+ }), null, 16, ["line", "paramsNameMap", "is-log-scale", "onContextmenu", "onUpdateLine"])) : (openBlock(), createBlock(_component_LegendItem, mergeProps({
6414
6490
  key: 1,
6415
6491
  line,
6416
6492
  paramsNameMap: $options.paramsNameMap
6417
6493
  }, { ref_for: true }, _ctx.$props, {
6494
+ "is-log-scale": $options.isLaneLogScale(lane),
6418
6495
  onContextmenu: withModifiers(($event) => $options.showContextMenu($event, line), ["prevent"]),
6419
6496
  onUpdateLine: $options.upsertLine
6420
- }), null, 16, ["line", "paramsNameMap", "onContextmenu", "onUpdateLine"]))
6497
+ }), null, 16, ["line", "paramsNameMap", "is-log-scale", "onContextmenu", "onUpdateLine"]))
6421
6498
  ], 2);
6422
6499
  }), 128))
6423
6500
  ]),
@@ -6436,7 +6513,7 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6436
6513
  }), 128))
6437
6514
  ]),
6438
6515
  _: 3
6439
- }, 8, ["onStart", "onEnd", "modelValue", "filter"])
6516
+ }, 8, ["onStart", "onEnd", "modelValue", "filter", "handle"])
6440
6517
  ], 64)) : (openBlock(), createElementBlock("div", _hoisted_13$1, [
6441
6518
  createElementVNode("div", {
6442
6519
  class: normalizeClass(["kd-lane-chart-lane-header", { "kd-lane-chart-lane-header-isKdCurveV2": $props.isKdCurveV2 }]),
@@ -6518,7 +6595,7 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6518
6595
  }, 8, ["modelValue", "onClose"])
6519
6596
  ], 544);
6520
6597
  }
6521
- const KdLaneContainerComponent = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$6], ["__scopeId", "data-v-4f706753"]]);
6598
+ const KdLaneContainerComponent = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$6], ["__scopeId", "data-v-9d96e270"]]);
6522
6599
  const SLIDER_GROUP_ID = "depthSliderGroup";
6523
6600
  function pad2(n) {
6524
6601
  return n < 10 ? "0" + n : "" + n;
@@ -6651,10 +6728,12 @@ const _sfc_main$5 = {
6651
6728
  yName: curveConfig.yName,
6652
6729
  xCode,
6653
6730
  yCode,
6654
- data: this.cachedCurveData.map((item) => ({
6655
- time: item[xCode] || item.timestamp,
6656
- value: item[yCode] || 0
6657
- }))
6731
+ data: markRaw(
6732
+ this.cachedCurveData.map((item) => ({
6733
+ time: item[xCode] || item.timestamp,
6734
+ value: item[yCode] || 0
6735
+ }))
6736
+ )
6658
6737
  };
6659
6738
  })
6660
6739
  };
@@ -6700,24 +6779,28 @@ const _sfc_main$5 = {
6700
6779
  await this.$nextTick();
6701
6780
  if (newVal.type === "replace") {
6702
6781
  this.cachedCurveData = [];
6703
- let processedData = newVal && newVal.data ? Array.isArray(newVal.data) ? [...newVal.data] : [newVal.data] : [];
6782
+ let processedData = newVal && newVal.data ? Array.isArray(newVal.data) ? newVal.data : [newVal.data] : [];
6704
6783
  if (this.formCache.axisType == "time") {
6705
6784
  const axisKey = ((_c = (_b = (_a = this.getCurrentModeConfig()) == null ? void 0 : _a.datas) == null ? void 0 : _b[0]) == null ? void 0 : _c.xCode) || "timestamp";
6706
- processedData = processedData.map((item) => ({
6707
- ...item,
6708
- [axisKey]: this.toMillisecondTimestamp(item[axisKey] || item.timestamp)
6709
- }));
6710
- this.cachedCurveData = processedData;
6785
+ const firstT = processedData[0] && processedData[0][axisKey];
6786
+ if (!(typeof firstT === "number" && firstT > 1e11)) {
6787
+ processedData = processedData.map((item) => ({
6788
+ ...item,
6789
+ [axisKey]: this.toMillisecondTimestamp(item[axisKey] || item.timestamp)
6790
+ }));
6791
+ }
6792
+ this.cachedCurveData = markRaw(processedData);
6711
6793
  } else {
6712
6794
  const axisKey = ((_f = (_e = (_d = this.getCurrentModeConfig()) == null ? void 0 : _d.datas) == null ? void 0 : _e[0]) == null ? void 0 : _f.xCode) || "depth";
6713
- if (processedData[0] && processedData[0].timestamp) {
6795
+ const firstTs = processedData[0] && processedData[0].timestamp;
6796
+ if (firstTs && !(typeof firstTs === "number" && firstTs > 1e11)) {
6714
6797
  processedData = processedData.map((item) => ({
6715
6798
  ...item,
6716
6799
  timestamp: this.toMillisecondTimestamp(item.timestamp)
6717
6800
  }));
6718
- this.cachedCurveData = this.deduplicateByUniqueKey(this.cachedCurveData, processedData, "timestamp");
6801
+ this.cachedCurveData = markRaw(this.deduplicateByUniqueKey([], processedData, "timestamp"));
6719
6802
  } else {
6720
- this.cachedCurveData = this.deduplicateByUniqueKey(this.cachedCurveData, processedData, axisKey);
6803
+ this.cachedCurveData = markRaw(this.deduplicateByUniqueKey([], processedData, axisKey));
6721
6804
  }
6722
6805
  }
6723
6806
  if (this.cachedCurveData.length > 0) {
@@ -6772,11 +6855,11 @@ const _sfc_main$5 = {
6772
6855
  ...item,
6773
6856
  [axisKey]: this.toMillisecondTimestamp(item[axisKey] || item.timestamp)
6774
6857
  }));
6775
- this.cachedCurveData = this.deduplicateByUniqueKey(
6858
+ this.cachedCurveData = markRaw(this.deduplicateByUniqueKey(
6776
6859
  this.cachedCurveData,
6777
6860
  data,
6778
6861
  axisKey
6779
- );
6862
+ ));
6780
6863
  } else {
6781
6864
  data = data.map((item) => ({
6782
6865
  ...item,
@@ -6784,9 +6867,9 @@ const _sfc_main$5 = {
6784
6867
  }));
6785
6868
  if (direction === "top") {
6786
6869
  const tempData = [...data, ...this.cachedCurveData];
6787
- this.cachedCurveData = this.deduplicateByUniqueKey([], tempData, "timestamp");
6870
+ this.cachedCurveData = markRaw(this.deduplicateByUniqueKey([], tempData, "timestamp"));
6788
6871
  } else {
6789
- this.cachedCurveData = this.deduplicateByUniqueKey(this.cachedCurveData, data, "timestamp");
6872
+ this.cachedCurveData = markRaw(this.deduplicateByUniqueKey(this.cachedCurveData, data, "timestamp"));
6790
6873
  }
6791
6874
  }
6792
6875
  if (this.cachedCurveData.length > 0) {
@@ -6797,8 +6880,7 @@ const _sfc_main$5 = {
6797
6880
  this.renderChart();
6798
6881
  }
6799
6882
  },
6800
- immediate: true,
6801
- deep: true
6883
+ immediate: true
6802
6884
  },
6803
6885
  depthTimeChartData: {
6804
6886
  deep: true,
@@ -7831,7 +7913,7 @@ function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
7831
7913
  ], 512)
7832
7914
  ], 512);
7833
7915
  }
7834
- const DepthTimeChart = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$5], ["__scopeId", "data-v-75a3a4e4"]]);
7916
+ const DepthTimeChart = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$5], ["__scopeId", "data-v-9991a24b"]]);
7835
7917
  const curveExportIcon = "data:image/png;base64,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";
7836
7918
  const depthSlotIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAAFnUlEQVRo3u1ZTWxUVRT+zptOp51pZZpOaWlGCgIFFIRgiCsNJi6MbFyyMRqgPygmJhrXNbJgQQQTSf9mGhaEuGkCK/9iMkhAoxAoJCIBTZEWO0Ch03ZsZzpzPxf3venr0JoZ7LzOkJ7Mz3v3vfvuO/ec7zvn3Assy7IUhUihB9h74MBGI8099jblkq/6OjtvFHLcskIrZii1KVFZ3zEW2AEFYc39S1KRiF4BUNqKAUCiciVGVr/BFAWVk0OoSEQLPqbhlM/TYYyVOYVkIUUc1M5w0lxOquaMYiJOEPBSWIyAOAszZzAGcdgRHWNFghDSQasZTllMtH7ylJEHtameOlZ0Ojo7mXmIw4oVhBX3t7YdFYofAKiwJlstUXKwpaX9LZNWpm/dvPFBJBJJlQDdy/SUf/07sYadUIRMe2ppUX501at8UPPi6wrCVdHzqI7/+cViK1UwV2Ta1eWJD6cnA1sQq9+J+Ip10PQhjK1oxr2VL3PUv1W8U8MJqPThksFYOHz8tjEzddI/9CMIzYRCiGYR7ZYN939CWTp5OhQKRUuKPETUIf/dCwKmrcxD/5NiqBSCIz8gnebhQo1fMMV6enr+cM2Mf+OPXhKQYo9hDdFzUp4cP93X1z1QknQvNA7X3vkeAkUb77Mheh5KyZGSjWO9vZ1ny6ceRKpHr4mFrZqH11AxHb0YDnedL+kALcCXtX+fy6QfwTtfCxQOlXzZcvPm72c2bMAtX+zWOkVIZXzoSijUfaYoFGtpbTsHSNCW+k2Gerq25tI3Eomkmps3H2q4892JtOEBRbryymJa2i6L6CwGABQ5FO7tfmWRLCbB4e0H18x4/JR0AmsvHZkguSXXl4vH4wOfHz02CvzDAx9/djHU3Zlz3/b299b98vwn1akyL8uTY9hx/ejiumKqws9UeY1IetqKsp5c+/p8Pqysq+t3u90TgUAA+fQFgOmKWqZclQAphcGYCJ+0Btm9+81T/68ykLwWF3JXjBRrVeZJJBgMThZ1PeZ0XWWbVAhyd8WcFdPJrCxFMZyZTiuhXlTFBBSQsiQWM6dTCkIeIoQImMfDF00tMb1FCmCxDNU6uuw564jMEwRGXhYDl8gTTQgULI7Neryrv7+/2SF0uSxXLGASLKQYmPI1es9cuH4qC9vZh/PAP7tBSBNFgPYIZo2HykYBXHknBnkGaJAuD/566SOCEEUCYpCk0HxJQodxmqGBBGjjaWUeZt2n+ypo7jWXEJR1TT9Y8KSZx7597zcZhlpjnacNNdbXbZbvIpxT4pMZIuFjFtEvlsGlxWqKIqAo61kwUzTqPU+xlnvMiZpdBNIK20fY29a2zaWM2axfGYPh8PHb8yomrvS7SV+yY6YqASPpQsVDbwTAawDgiQ1KmXsUFGtKYR0DJDQIRO+qMONSYk22FV0tyiZpntC0GoUwiDl9xTI4QIo7OT7LekqOxXwPdyVdM/AmfPAmfR0APl3QFR+tH0V02136Rqrw3Lcbreaf6387OYgiEAWMWMfXmgZw75koNw+9gE3DW3LAmJmWiWBXS2u7uVGCohAB0NLavkd7DCkLJEMLkkd81QQH3r4IpikUkiSgIAqk/sz9AgCVdiwqitlGRQWLAax2ivZdKgqhn23vk7kP5lWTPZTKjDPnes4BWgzR9xMCYxa0NFGdsaoZXAQi9nOdfmnwiBV/aO7+yQIxQfuITtnEgl0mOTD/ZJ5uMm/RUTY/sxOVj7xo/PVZ2MBsiz8UW2zK8JW1vWe7D8w6N3/tHKe3BZkV4Gy5r/VS2VH6atNlxLxjecQxQlwJF6pGqq4AxocoSlHH3Kny7cT8rviYYr6RKtSjEe7JchAyFurtPFuMau1vaR9bfb+JgYk6BMbr/lsxoUR80eoOX7TaKhcGUaRCkROrH6yN2N8dy7IsxSf/Avx35qhCwuXeAAAAAElFTkSuQmCC";
7837
7919
  const refreshIcon = "data:image/png;base64,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";
@@ -9104,24 +9186,53 @@ const _sfc_main$3 = {
9104
9186
  }
9105
9187
  return null;
9106
9188
  },
9107
- _restoreDataZoomState(savedState) {
9108
- if (!savedState || !this.chart || this.chart.isDisposed()) return;
9189
+ // notMerge 刷 option 时把当前趋势线 graphic 带回去,避免先消失再画。8.24
9190
+ _preserveGraphic(options) {
9191
+ if (!options || options.graphic || !this.chart || this.chart.isDisposed()) return;
9109
9192
  try {
9110
- const currentOption = this.chart.getOption();
9111
- if (!currentOption.dataZoom || currentOption.dataZoom.length === 0) return;
9112
- savedState.forEach((state, i) => {
9113
- if (i < currentOption.dataZoom.length) {
9114
- const dz = currentOption.dataZoom[i];
9115
- if (state.start !== void 0) dz.start = state.start;
9116
- if (state.end !== void 0) dz.end = state.end;
9117
- if (state.startValue !== void 0) dz.startValue = state.startValue;
9118
- if (state.endValue !== void 0) dz.endValue = state.endValue;
9119
- }
9120
- });
9121
- this.chart.setOption({ dataZoom: currentOption.dataZoom });
9193
+ const current = this.chart.getOption();
9194
+ if (current && current.graphic && current.graphic.length) {
9195
+ options.graphic = current.graphic;
9196
+ }
9122
9197
  } catch (e) {
9123
9198
  }
9124
9199
  },
9200
+ // dataZoom 写进即将下发的 option,不再二次 setOption 打断 Chrome 平移。8.24
9201
+ _applySavedDataZoomToOptions(options, savedState) {
9202
+ if (!savedState || !options) return;
9203
+ const raw = options.dataZoom;
9204
+ if (!raw) return;
9205
+ const list = Array.isArray(raw) ? raw : [raw];
9206
+ savedState.forEach((state, i) => {
9207
+ if (!list[i] || !state) return;
9208
+ if (state.start !== void 0) list[i].start = state.start;
9209
+ if (state.end !== void 0) list[i].end = state.end;
9210
+ if (state.startValue !== void 0) list[i].startValue = state.startValue;
9211
+ if (state.endValue !== void 0) list[i].endValue = state.endValue;
9212
+ });
9213
+ },
9214
+ // 拦截 HTML5 dragstart,Chrome 才能把 mousemove 交给 dataZoom。8.24
9215
+ _preventNativeDrag(e) {
9216
+ e.preventDefault();
9217
+ },
9218
+ _bindNativeDragGuard() {
9219
+ const el = this.$el;
9220
+ if (!el || el.__kdNativeDragBound) return;
9221
+ el.__kdNativeDragBound = true;
9222
+ el.setAttribute("draggable", "false");
9223
+ el.addEventListener("dragstart", this._preventNativeDrag, true);
9224
+ const canvases = el.querySelectorAll("canvas");
9225
+ canvases.forEach((canvas) => {
9226
+ canvas.draggable = false;
9227
+ canvas.setAttribute("draggable", "false");
9228
+ });
9229
+ },
9230
+ _unbindNativeDragGuard() {
9231
+ const el = this.$el;
9232
+ if (!el) return;
9233
+ el.removeEventListener("dragstart", this._preventNativeDrag, true);
9234
+ el.__kdNativeDragBound = false;
9235
+ },
9125
9236
  // provide an explicit merge option method
9126
9237
  mergeOptions(options, notMerge, lazyUpdate, skipClone) {
9127
9238
  if (this.manualUpdate) {
@@ -9132,10 +9243,13 @@ const _sfc_main$3 = {
9132
9243
  } else {
9133
9244
  this._skipWatcher = true;
9134
9245
  const savedDataZoom = this._saveDataZoomState();
9135
- this.delegateMethod("setOption", this.getOptionsWithTheme(options, skipClone), notMerge, lazyUpdate);
9136
- if (savedDataZoom) {
9137
- this._restoreDataZoomState(savedDataZoom);
9138
- }
9246
+ const next = this.getOptionsWithTheme(options, skipClone);
9247
+ this._applySavedDataZoomToOptions(next, savedDataZoom);
9248
+ this._preserveGraphic(next);
9249
+ this.delegateMethod("setOption", next, {
9250
+ notMerge: !!notMerge,
9251
+ lazyUpdate: !!lazyUpdate
9252
+ });
9139
9253
  this.$nextTick(() => {
9140
9254
  this._skipWatcher = false;
9141
9255
  });
@@ -9215,6 +9329,7 @@ const _sfc_main$3 = {
9215
9329
  chart.group = this.group;
9216
9330
  }
9217
9331
  chart.setOption(this.getOptionsWithTheme(options || this.manualOptions || this.options || {}), true);
9332
+ this._bindNativeDragGuard();
9218
9333
  Object.keys(this.$attrs).forEach((key) => {
9219
9334
  if (!key.startsWith("on") || typeof this.$attrs[key] !== "function") {
9220
9335
  return;
@@ -9294,10 +9409,12 @@ const _sfc_main$3 = {
9294
9409
  this.init(val);
9295
9410
  } else {
9296
9411
  const savedDataZoom = this._saveDataZoomState();
9297
- this.chart.setOption(this.getOptionsWithTheme(val), val !== oldVal);
9298
- if (savedDataZoom) {
9299
- this._restoreDataZoomState(savedDataZoom);
9300
- }
9412
+ const next = this.getOptionsWithTheme(val);
9413
+ this._applySavedDataZoomToOptions(next, savedDataZoom);
9414
+ this._preserveGraphic(next);
9415
+ this.chart.setOption(next, {
9416
+ notMerge: this.skipClone || val !== oldVal
9417
+ });
9301
9418
  if (this.group) {
9302
9419
  this.chart.group = this.group;
9303
9420
  }
@@ -9308,8 +9425,16 @@ const _sfc_main$3 = {
9308
9425
  }
9309
9426
  },
9310
9427
  destroy() {
9428
+ this._unbindNativeDragGuard();
9429
+ if (this.__unwatchOptions) {
9430
+ this.__unwatchOptions();
9431
+ this.__unwatchOptions = null;
9432
+ }
9311
9433
  if (this.autoresize) {
9312
9434
  removeListener(this.$el, this.__resizeHandler);
9435
+ if (this.__resizeHandler && this.__resizeHandler.cancel) {
9436
+ this.__resizeHandler.cancel();
9437
+ }
9313
9438
  }
9314
9439
  this.dispose();
9315
9440
  this.chart = null;
@@ -9382,7 +9507,7 @@ const _hoisted_1$3 = { class: "echarts" };
9382
9507
  function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
9383
9508
  return openBlock(), createElementBlock("div", _hoisted_1$3);
9384
9509
  }
9385
- const resizeEcharts = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3], ["__scopeId", "data-v-de2449c9"]]);
9510
+ const resizeEcharts = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3], ["__scopeId", "data-v-8c9f410f"]]);
9386
9511
  const DRAW_POINT_MIN = 600;
9387
9512
  const DRAW_POINT_MAX = 1800;
9388
9513
  function getSeriesDrawThreshold(laneHeightPx) {
@@ -9773,6 +9898,7 @@ const _sfc_main$2 = {
9773
9898
  this.showTooltip = this.formCache.displayType == "float";
9774
9899
  },
9775
9900
  beforeUnmount() {
9901
+ this._isUnmounted = true;
9776
9902
  window.removeEventListener("keydown", this.handleKeyDown);
9777
9903
  window.removeEventListener("keyup", this.handleKeyUp);
9778
9904
  if (this.trendLineManager) this.trendLineManager.destroy();
@@ -9780,15 +9906,29 @@ const _sfc_main$2 = {
9780
9906
  cancelAnimationFrame(this._pointerRaf);
9781
9907
  this._pointerRaf = 0;
9782
9908
  }
9909
+ if (this._connectRaf) {
9910
+ cancelAnimationFrame(this._connectRaf);
9911
+ this._connectRaf = 0;
9912
+ }
9913
+ cancelAnimationFrame(this.animationId);
9914
+ this.animationId = null;
9915
+ if (this.debounceJudgeEdge && this.debounceJudgeEdge.cancel) {
9916
+ this.debounceJudgeEdge.cancel();
9917
+ }
9918
+ if (this.scheduleConnectAllCharts && this.scheduleConnectAllCharts.cancel) {
9919
+ this.scheduleConnectAllCharts.cancel();
9920
+ }
9783
9921
  this._pendingPointer = null;
9784
9922
  this.unbindChartPointerSync();
9785
9923
  echarts.disConnect(this.group);
9786
9924
  this.clearEcharts();
9787
9925
  if (this.resizeObserver) {
9788
9926
  this.resizeObserver.disconnect();
9927
+ this.resizeObserver = null;
9789
9928
  }
9790
9929
  if (this.resizeTimeout) {
9791
9930
  clearTimeout(this.resizeTimeout);
9931
+ this.resizeTimeout = null;
9792
9932
  }
9793
9933
  },
9794
9934
  methods: {
@@ -9809,6 +9949,10 @@ const _sfc_main$2 = {
9809
9949
  getLaneLogPlotRange(lane) {
9810
9950
  return resolveLaneLogPlotRange(lane, this.lineRange);
9811
9951
  },
9952
+ // 对数开关变化时重建该道图表,series 才能换成 lg 数据。8.24
9953
+ chartLaneKey(lane) {
9954
+ return `${lane && lane.laneId}-${isLaneLogScale(lane) ? "log" : "lin"}`;
9955
+ },
9812
9956
  // 整道 10 条竖线,样式跟普通泳道 splitLine 同一套。8.22对数轴
9813
9957
  getLogPaperGridSeries(lane, xAxisIndex, yAxisIndex) {
9814
9958
  const range = this.getLaneLogPlotRange(lane);
@@ -10144,7 +10288,7 @@ const _sfc_main$2 = {
10144
10288
  const item = Array.isArray(tip) ? tip[0] : tip;
10145
10289
  return !!(item && item.show === false);
10146
10290
  },
10147
- // 对数轴曲线 X 用 lg(x);轴是线性 lg 量程,允许负数。8.22对数轴
10291
+ // 对数轴曲线 X 用 lg(x);轴是线性 lg 量程,允许负数。不改原始行。8.24
10148
10292
  plotX(raw, isLogScale) {
10149
10293
  return isLogScale ? toLogPlotX(raw) : raw;
10150
10294
  },
@@ -10433,7 +10577,11 @@ const _sfc_main$2 = {
10433
10577
  // 联动所有泳道图表的十字准线与 tooltip(贯穿整个泳道区域)
10434
10578
  connectAllCharts() {
10435
10579
  this.$nextTick(() => {
10436
- requestAnimationFrame(() => {
10580
+ if (this._isUnmounted) return;
10581
+ if (this._connectRaf) cancelAnimationFrame(this._connectRaf);
10582
+ this._connectRaf = requestAnimationFrame(() => {
10583
+ this._connectRaf = 0;
10584
+ if (this._isUnmounted) return;
10437
10585
  const charts = this.getConnectedCharts();
10438
10586
  if (charts.length === 0) return;
10439
10587
  charts.forEach((chart) => {
@@ -10612,6 +10760,14 @@ const _sfc_main$2 = {
10612
10760
  });
10613
10761
  }
10614
10762
  this._pointerMetaGen++;
10763
+ this.flushLaneChartOption(lineId, cachedOption);
10764
+ },
10765
+ // skip-clone 浅监听可能不刷 series;对数切换时把 lg 数据直接打进图。8.24
10766
+ flushLaneChartOption(lineId, option) {
10767
+ const ref = this.getChartRefByLaneId(lineId);
10768
+ if (!ref || typeof ref.mergeOptions !== "function") return;
10769
+ if (!ref.chart || ref.chart.isDisposed()) return;
10770
+ ref.mergeOptions(option, true, false, true);
10615
10771
  },
10616
10772
  // 判断指定泳道是否应该显示tooltip内容
10617
10773
  // 地应力模式下:如果没有选中泳道,所有泳道正常显示;如果有选中泳道,只有选中的泳道显示
@@ -10645,12 +10801,10 @@ const _sfc_main$2 = {
10645
10801
  this.visibleData = markRaw(this.realTimeData.slice(startIndex, end));
10646
10802
  return this.visibleData;
10647
10803
  },
10648
- /** 地应力:进图用全量行,不按窗口截断。8.24 */
10804
+ /** 进图只吃当前窗口。地应力也不准喂整口井,否则井深轴会拉成全井量程。8.24 */
10649
10805
  getChartDrawRows(transferData) {
10650
10806
  if (transferData && transferData.length > 0) return transferData;
10651
- this.getVisibleData();
10652
- if (this.isGeomechanical) return this.realTimeData || [];
10653
- return this.visibleData;
10807
+ return this.getVisibleData();
10654
10808
  },
10655
10809
  getRowsAxisExtent(rows, key) {
10656
10810
  let min = Infinity;
@@ -10665,6 +10819,14 @@ const _sfc_main$2 = {
10665
10819
  if (!Number.isFinite(min)) return { min: 0, max: 0 };
10666
10820
  return { min, max };
10667
10821
  },
10822
+ /** 井深/时间轴:没有有效轴值时不画 0、1 占位刻度。不改行数据。8.24 */
10823
+ shouldShowDepthAxisLabel(rows, axisKey) {
10824
+ if (!rows || !rows.length) return false;
10825
+ for (let i = 0; i < rows.length; i++) {
10826
+ if (Number.isFinite(Number(rows[i][axisKey]))) return true;
10827
+ }
10828
+ return false;
10829
+ },
10668
10830
  getGroupAxisExtents(groups, axisKey) {
10669
10831
  const extents = [];
10670
10832
  let totalRange = 0;
@@ -10751,12 +10913,15 @@ const _sfc_main$2 = {
10751
10913
  const h = this.$refs.chartContainer && this.$refs.chartContainer.getLaneHeightPx && this.$refs.chartContainer.getLaneHeightPx() || 400;
10752
10914
  return getSeriesDrawThreshold(h);
10753
10915
  },
10754
- /** 地应力全量进图不抽稀;其它模式只抽稀进图点。8.24 */
10916
+ /** 地应力也只画窗口抽稀点;数值仍从原始行取。8.24 */
10755
10917
  plotSeriesForDraw(data, isLogScale) {
10756
10918
  const plotted = this.plotSeries(data, isLogScale);
10757
- if (this.isGeomechanical) return plotted;
10758
10919
  return downsampleSeriesForDraw(plotted, this.getSeriesDrawThreshold());
10759
10920
  },
10921
+ /** 该道进图点:开了对数就用 lg 后的 X。8.24 */
10922
+ toDrawSeriesData(lane, rawPoints) {
10923
+ return this.plotSeriesForDraw(rawPoints, isLaneLogScale(lane));
10924
+ },
10760
10925
  findRowByAxisValue(axisValue) {
10761
10926
  const key = this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType] || (this.formCache.axisType === "time" ? "time" : "depth");
10762
10927
  return findNearestRow(this.visibleData, key, axisValue) || findNearestRow(this.realTimeData, key, axisValue);
@@ -10855,7 +11020,10 @@ const _sfc_main$2 = {
10855
11020
  axisKey,
10856
11021
  paramCodeMap
10857
11022
  );
10858
- data = downsampleSeriesForDraw(this.plotSeries(raw, isLog), threshold);
11023
+ data = downsampleSeriesForDraw(
11024
+ this.plotSeries(raw, isLog),
11025
+ threshold
11026
+ );
10859
11027
  groupSeriesCache.set(cacheKey, data);
10860
11028
  }
10861
11029
  return { data };
@@ -11700,7 +11868,8 @@ const _sfc_main$2 = {
11700
11868
  alignTicks: true,
11701
11869
  boundaryGap: false,
11702
11870
  axisLabel: {
11703
- show: true,
11871
+ show: this.shouldShowDepthAxisLabel(group, axisKey),
11872
+ // 无井深值不显示 0/1。8.24
11704
11873
  width: clientWidth,
11705
11874
  hideOverlap: true,
11706
11875
  height: 14,
@@ -11814,7 +11983,7 @@ const _sfc_main$2 = {
11814
11983
  axisTick: { show: false }
11815
11984
  }
11816
11985
  );
11817
- const seriesSource = lineInfo.isUsed === "1" ? this.plotSeriesForDraw(groupSeriesData, isLogScale) : [];
11986
+ const seriesSource = lineInfo.isUsed === "1" ? this.toDrawSeriesData(lane, groupSeriesData) : [];
11818
11987
  const baseSeries = {
11819
11988
  laneId: lineInfo.paramId,
11820
11989
  paramId: lineInfo.paramId,
@@ -11914,7 +12083,7 @@ const _sfc_main$2 = {
11914
12083
  axisKey,
11915
12084
  paramCodeMap
11916
12085
  );
11917
- const recommendSource = lineInfo.recommendIsUsed === "1" || lineInfo.recommendIsUsed == 1 ? this.plotSeriesForDraw(recommendGroupSeriesData, isLogScale) : [];
12086
+ const recommendSource = lineInfo.recommendIsUsed === "1" || lineInfo.recommendIsUsed == 1 ? this.toDrawSeriesData(lane, recommendGroupSeriesData) : [];
11918
12087
  const recommendSeries = {
11919
12088
  laneId: lineInfo.recommendParamId,
11920
12089
  data: recommendSource,
@@ -13473,6 +13642,12 @@ const _sfc_main$2 = {
13473
13642
  boundaryGap: false,
13474
13643
  interval: unifiedInterval
13475
13644
  };
13645
+ if (isDepthLane) {
13646
+ yAxisItem.axisLabel = {
13647
+ show: this.shouldShowDepthAxisLabel(group, axisKey)
13648
+ // 无井深值不显示 0/1。8.24
13649
+ };
13650
+ }
13476
13651
  const currentYAxis = currentOption.yAxis && currentOption.yAxis[gridIndex];
13477
13652
  if (!currentYAxis || currentYAxis.min !== groupMin || currentYAxis.max !== groupMax || currentYAxis.interval !== unifiedInterval) {
13478
13653
  needUpdate.yAxis = true;
@@ -13530,7 +13705,7 @@ const _sfc_main$2 = {
13530
13705
  lineInfo,
13531
13706
  axisKey
13532
13707
  );
13533
- const finalSeriesData = lineInfo.isUsed === "1" ? this.plotSeriesForDraw(seriesData, isLogScale) : [];
13708
+ const finalSeriesData = lineInfo.isUsed === "1" ? this.toDrawSeriesData(lane, seriesData) : [];
13534
13709
  needUpdate.series = true;
13535
13710
  newSeriesData.push({
13536
13711
  index: seriesIndex,
@@ -14005,7 +14180,7 @@ const _sfc_main$2 = {
14005
14180
  this.realTimeData = [];
14006
14181
  this.visibleData = [];
14007
14182
  if (!this.initialRealTimeData || !this.initialRealTimeData.data) {
14008
- this.initialRealTimeData = newVal || {};
14183
+ this.initialRealTimeData = markRaw(newVal || {});
14009
14184
  }
14010
14185
  let processedData = newVal && newVal.data || [];
14011
14186
  if (this.formCache.axisType == "time") {
@@ -14036,13 +14211,13 @@ const _sfc_main$2 = {
14036
14211
  await this.$nextTick();
14037
14212
  this.updateLanesChartOption();
14038
14213
  } else if (newVal.type === "supplementaryData") {
14039
- let data = cloneDeep(newVal && newVal.data) || [];
14214
+ let data = newVal && newVal.data || [];
14040
14215
  if (!Array.isArray(data)) {
14041
14216
  data = [data];
14042
14217
  }
14043
14218
  this.handleDataLoaded(data);
14044
14219
  } else if (newVal.type === "updateData") {
14045
- let data = cloneDeep(newVal && newVal.data) || [];
14220
+ let data = newVal && newVal.data || [];
14046
14221
  if (!Array.isArray(data)) {
14047
14222
  data = [data];
14048
14223
  }
@@ -14098,7 +14273,7 @@ const _sfc_main$2 = {
14098
14273
  this.updateLanesChartOption();
14099
14274
  } else {
14100
14275
  console.log(newVal, "newVal");
14101
- let data = cloneDeep(newVal && newVal.data) || [];
14276
+ let data = newVal && newVal.data || [];
14102
14277
  if (!Array.isArray(data)) {
14103
14278
  data = [data];
14104
14279
  }
@@ -14109,10 +14284,12 @@ const _sfc_main$2 = {
14109
14284
  ...item,
14110
14285
  [axisKey]: this.toMillisecondTimestamp(item[axisKey])
14111
14286
  }));
14112
- this.realTimeData = this.deduplicateByUniqueKey(
14113
- this.realTimeData,
14114
- data,
14115
- this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType]
14287
+ this.realTimeData = markRaw(
14288
+ this.deduplicateByUniqueKey(
14289
+ this.realTimeData,
14290
+ data,
14291
+ this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType]
14292
+ )
14116
14293
  );
14117
14294
  } else {
14118
14295
  data = data.map((item) => ({
@@ -14120,14 +14297,18 @@ const _sfc_main$2 = {
14120
14297
  timestamp: this.toMillisecondTimestamp(item.timestamp)
14121
14298
  }));
14122
14299
  if (direction === "top") {
14123
- this.realTimeData = this.uniqueByKeys(
14124
- [...data, ...this.realTimeData],
14125
- "timestamp"
14300
+ this.realTimeData = markRaw(
14301
+ this.uniqueByKeys(
14302
+ [...data, ...this.realTimeData],
14303
+ "timestamp"
14304
+ )
14126
14305
  );
14127
14306
  } else {
14128
- this.realTimeData = this.uniqueByKeys(
14129
- [...this.realTimeData, ...data],
14130
- "timestamp"
14307
+ this.realTimeData = markRaw(
14308
+ this.uniqueByKeys(
14309
+ [...this.realTimeData, ...data],
14310
+ "timestamp"
14311
+ )
14131
14312
  );
14132
14313
  }
14133
14314
  }
@@ -14145,8 +14326,7 @@ const _sfc_main$2 = {
14145
14326
  }
14146
14327
  }
14147
14328
  },
14148
- immediate: true,
14149
- deep: true
14329
+ immediate: true
14150
14330
  }
14151
14331
  }
14152
14332
  };
@@ -14222,7 +14402,7 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
14222
14402
  placement: "top"
14223
14403
  }, null, 8, ["min", "max"])) : createCommentVNode("", true),
14224
14404
  (openBlock(), createBlock(_component_resizeEcharts, {
14225
- key: lane.laneId,
14405
+ key: $options.chartLaneKey(lane),
14226
14406
  ref: (el) => $options.setChartRef(lane.laneId, el),
14227
14407
  autoresize: "",
14228
14408
  options: $options.getOptionsByLineId(lane.laneId),
@@ -14267,7 +14447,7 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
14267
14447
  placement: "top"
14268
14448
  }, null, 8, ["min", "max"])) : createCommentVNode("", true),
14269
14449
  (openBlock(), createBlock(_component_resizeEcharts, {
14270
- key: lane.laneId,
14450
+ key: $options.chartLaneKey(lane),
14271
14451
  ref: (el) => $options.setChartRef(lane.laneId, el),
14272
14452
  autoresize: "",
14273
14453
  options: $options.getOptionsByLineId(lane.laneId),
@@ -14336,7 +14516,7 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
14336
14516
  ])
14337
14517
  ], 544);
14338
14518
  }
14339
- const chartContainer = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-f4dde916"]]);
14519
+ const chartContainer = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-aace7d52"]]);
14340
14520
  const _sfc_main$1 = {
14341
14521
  name: "ParameterPanel",
14342
14522
  props: {
@@ -14969,6 +15149,16 @@ const faultParameters = [
14969
15149
  paramId: ["8034"]
14970
15150
  }
14971
15151
  ];
15152
+ function holdCurveDatas(val) {
15153
+ if (!val || typeof val !== "object") {
15154
+ return markRaw({ data: markRaw([]) });
15155
+ }
15156
+ const data = Array.isArray(val.data) ? val.data : [];
15157
+ return markRaw({
15158
+ ...val,
15159
+ data: markRaw(data)
15160
+ });
15161
+ }
14972
15162
  const _sfc_main = {
14973
15163
  name: "frameLayout",
14974
15164
  components: {
@@ -15180,8 +15370,9 @@ const _sfc_main = {
15180
15370
  this.depthTimeChartData = this.WellBitDepthTimePlotConfig && this.WellBitDepthTimePlotConfig.data || [];
15181
15371
  this.initialFormCache = cloneDeep(this.currentToolBarConfig && this.currentToolBarConfig.form || {});
15182
15372
  this.formCache = cloneDeep(this.currentToolBarConfig && this.currentToolBarConfig.form || {});
15183
- this.cachedCurveDatas = cloneDeep(this.curveDatas || {});
15184
- this.initialCurveDatas = cloneDeep(this.curveDatas || {});
15373
+ this.cachedCurveDatas = holdCurveDatas(this.curveDatas);
15374
+ this.initialCurveDatas = holdCurveDatas(this.curveDatas);
15375
+ this._hasInitialCurveDatas = !!(this.curveDatas && this.curveDatas.type);
15185
15376
  let form = cloneDeep(this.currentToolBarConfig && this.currentToolBarConfig.form || {});
15186
15377
  const processedDepthConfig = this.processConfig(this.depthConfig);
15187
15378
  const processedTimeConfig = this.processConfig(this.timeConfig);
@@ -15318,13 +15509,24 @@ const _sfc_main = {
15318
15509
  this.containerWidth = this.$refs.container && this.$refs.container.offsetWidth || 800;
15319
15510
  this.initWidth();
15320
15511
  });
15321
- window.addEventListener("resize", () => {
15512
+ this._onWindowResize = () => {
15322
15513
  this.$nextTick(() => {
15514
+ if (this._isUnmounted) return;
15323
15515
  this.containerWidth = this.$refs.container && this.$refs.container.offsetWidth || 800;
15324
15516
  });
15325
- });
15517
+ };
15518
+ window.addEventListener("resize", this._onWindowResize);
15326
15519
  },
15327
15520
  methods: {
15521
+ // 延后显示图表;销毁时清掉,避免回调打到已卸载实例。8.24
15522
+ deferShowChart(fn) {
15523
+ if (this._showChartTimer) clearTimeout(this._showChartTimer);
15524
+ this._showChartTimer = setTimeout(() => {
15525
+ this._showChartTimer = null;
15526
+ if (this._isUnmounted) return;
15527
+ fn();
15528
+ }, 0);
15529
+ },
15328
15530
  // 处理单个对象,根据paramId匹配faultParameters并补充lineColor、max、min
15329
15531
  processSingleItem(item) {
15330
15532
  if (!item || !item.paramId) return;
@@ -15417,16 +15619,16 @@ const _sfc_main = {
15417
15619
  this.formCache = cloneDeep(this.initialFormCache);
15418
15620
  this.showChartContainer = false;
15419
15621
  this.enableCurveDatasWatch = false;
15420
- setTimeout(() => {
15622
+ this.deferShowChart(() => {
15421
15623
  const processedDepthConfig = this.processConfig(this.depthConfig);
15422
15624
  const processedTimeConfig = this.processConfig(this.timeConfig);
15423
15625
  this.config = this.formCache.axisType === "depth" ? processedDepthConfig : processedTimeConfig;
15424
15626
  if (JSON.stringify(this.config) !== "{}") {
15425
15627
  this.showChartContainer = true;
15426
15628
  }
15427
- this.cachedCurveDatas = cloneDeep(this.initialCurveDatas || {});
15629
+ this.cachedCurveDatas = this.initialCurveDatas;
15428
15630
  this.enableCurveDatasWatch = true;
15429
- }, 0);
15631
+ });
15430
15632
  },
15431
15633
  // 清空图表数据
15432
15634
  clearChartData() {
@@ -15473,14 +15675,14 @@ const _sfc_main = {
15473
15675
  }
15474
15676
  if (key === "axisType") {
15475
15677
  this.showChartContainer = false;
15476
- setTimeout(() => {
15678
+ this.deferShowChart(() => {
15477
15679
  const processedDepthConfig = this.processConfig(this.depthConfig);
15478
15680
  const processedTimeConfig = this.processConfig(this.timeConfig);
15479
15681
  this.config = this.formCache.axisType === "depth" ? processedDepthConfig : processedTimeConfig;
15480
15682
  if (JSON.stringify(this.config) !== "{}") {
15481
15683
  this.showChartContainer = true;
15482
15684
  }
15483
- }, 0);
15685
+ });
15484
15686
  this.$emit("updateSettings", { key, value, settings: cloneDeep(this.formCache) });
15485
15687
  }
15486
15688
  if (key === "dataType") {
@@ -15543,10 +15745,11 @@ const _sfc_main = {
15543
15745
  this.pendingEvent = e;
15544
15746
  if (!this.frameRequested) {
15545
15747
  this.frameRequested = true;
15546
- requestAnimationFrame(this.updateSize);
15748
+ this._panelResizeRaf = requestAnimationFrame(this.updateSize);
15547
15749
  }
15548
15750
  },
15549
15751
  updateSize() {
15752
+ this._panelResizeRaf = 0;
15550
15753
  const e = this.pendingEvent;
15551
15754
  if (!e) return;
15552
15755
  const dx = e.clientX - this.startX;
@@ -15609,10 +15812,19 @@ const _sfc_main = {
15609
15812
  this.isLoading = isLoading;
15610
15813
  }
15611
15814
  },
15612
- // 组件销毁时移除事件监听,防止内存泄漏
15613
15815
  beforeUnmount() {
15816
+ this._isUnmounted = true;
15817
+ window.removeEventListener("resize", this._onWindowResize);
15614
15818
  document.removeEventListener("mousemove", this.handleMove);
15615
15819
  document.removeEventListener("mouseup", this.stopResize);
15820
+ if (this._showChartTimer) {
15821
+ clearTimeout(this._showChartTimer);
15822
+ this._showChartTimer = null;
15823
+ }
15824
+ if (this._panelResizeRaf) {
15825
+ cancelAnimationFrame(this._panelResizeRaf);
15826
+ this._panelResizeRaf = 0;
15827
+ }
15616
15828
  },
15617
15829
  watch: {
15618
15830
  timeConfig: {
@@ -15621,9 +15833,9 @@ const _sfc_main = {
15621
15833
  this.showChartContainer = false;
15622
15834
  const processedConfig = this.processConfig(newVal);
15623
15835
  this.config = processedConfig;
15624
- setTimeout(() => {
15836
+ this.deferShowChart(() => {
15625
15837
  this.showChartContainer = true;
15626
- }, 0);
15838
+ });
15627
15839
  }
15628
15840
  },
15629
15841
  deep: true,
@@ -15638,9 +15850,9 @@ const _sfc_main = {
15638
15850
  this.showChartContainer = false;
15639
15851
  const processedConfig = this.processConfig(newVal);
15640
15852
  this.config = processedConfig;
15641
- setTimeout(() => {
15853
+ this.deferShowChart(() => {
15642
15854
  this.showChartContainer = true;
15643
- }, 0);
15855
+ });
15644
15856
  console.log(this.config, "depthConfig");
15645
15857
  }
15646
15858
  },
@@ -15671,23 +15883,22 @@ const _sfc_main = {
15671
15883
  deep: true,
15672
15884
  immediate: true
15673
15885
  },
15674
- // 监听curveDatas的变化
15886
+ // 只跟对象引用,不 deep 走进 markRaw 行数据。8.24
15675
15887
  curveDatas: {
15676
15888
  handler(newVal) {
15677
- if (this.enableCurveDatasWatch) {
15678
- if (JSON.stringify(this.initialCurveDatas) === "{}") {
15679
- this.initialCurveDatas = cloneDeep(newVal || {});
15680
- }
15681
- if (Object.prototype.hasOwnProperty.call(newVal, "dataType") && newVal.dataType !== this.formCache.dataType && newVal.dataType !== "" && newVal.dataType !== void 0 && newVal.dataType !== null) {
15682
- this.formCache.dataType = newVal.dataType;
15683
- if (this.$refs.functionControlPanel) {
15684
- this.$refs.functionControlPanel.form.dataType = newVal.dataType;
15685
- }
15889
+ if (!this.enableCurveDatasWatch || !newVal) return;
15890
+ if (!this._hasInitialCurveDatas && newVal.type) {
15891
+ this.initialCurveDatas = holdCurveDatas(newVal);
15892
+ this._hasInitialCurveDatas = true;
15893
+ }
15894
+ if (Object.prototype.hasOwnProperty.call(newVal, "dataType") && newVal.dataType !== this.formCache.dataType && newVal.dataType !== "" && newVal.dataType !== void 0 && newVal.dataType !== null) {
15895
+ this.formCache.dataType = newVal.dataType;
15896
+ if (this.$refs.functionControlPanel) {
15897
+ this.$refs.functionControlPanel.form.dataType = newVal.dataType;
15686
15898
  }
15687
- this.cachedCurveDatas = cloneDeep(newVal || {});
15688
15899
  }
15689
- },
15690
- deep: true
15900
+ this.cachedCurveDatas = holdCurveDatas(newVal);
15901
+ }
15691
15902
  },
15692
15903
  themeName: {
15693
15904
  handler(newVal) {
@@ -15820,7 +16031,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
15820
16031
  ])])) : createCommentVNode("", true)
15821
16032
  ]);
15822
16033
  }
15823
- const FrameLayoutComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-bc2030c8"]]);
16034
+ const FrameLayoutComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-76b2334b"]]);
15824
16035
  KdLaneContainerComponent.install = function(app) {
15825
16036
  app.component(KdLaneContainerComponent.name, KdLaneContainerComponent);
15826
16037
  };