kd-lane-chart-v3 0.1.9 → 0.1.11

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
@@ -2723,8 +2723,8 @@ function logTrendDataToPixel(chart, paramId, lg, depth) {
2723
2723
  const xAxis = model.getComponent("xAxis", xAxisIndex) && model.getComponent("xAxis", xAxisIndex).axis;
2724
2724
  const yAxis = model.getComponent("yAxis", yAxisIndex) && model.getComponent("yAxis", yAxisIndex).axis;
2725
2725
  if (xAxis && yAxis) {
2726
- const x = xAxis.toGlobalCoord(xAxis.dataToCoord(lg, true));
2727
- const y = yAxis.toGlobalCoord(yAxis.dataToCoord(depth, true));
2726
+ const x = xAxis.toGlobalCoord(xAxis.dataToCoord(lg, false));
2727
+ const y = yAxis.toGlobalCoord(yAxis.dataToCoord(depth, false));
2728
2728
  if (Number.isFinite(x) && Number.isFinite(y)) return [x, y];
2729
2729
  }
2730
2730
  } catch (e) {
@@ -3152,7 +3152,7 @@ function _sfc_render$8(_ctx, _cache, $props, $setup, $data, $options) {
3152
3152
  ])
3153
3153
  ], 6);
3154
3154
  }
3155
- const HeaderItem = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$8], ["__scopeId", "data-v-c4185947"]]);
3155
+ const HeaderItem = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$8], ["__scopeId", "data-v-7ad7195c"]]);
3156
3156
  const _sfc_main$7 = {
3157
3157
  name: "LegendItem",
3158
3158
  props: {
@@ -3323,7 +3323,7 @@ function _sfc_render$7(_ctx, _cache, $props, $setup, $data, $options) {
3323
3323
  ])
3324
3324
  ], 4);
3325
3325
  }
3326
- const LegendItem = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$7], ["__scopeId", "data-v-9fa6fff3"]]);
3326
+ const LegendItem = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$7], ["__scopeId", "data-v-273d8509"]]);
3327
3327
  const TREND_LINE_STYLE = {
3328
3328
  stroke: "#FF9800",
3329
3329
  lineWidth: 2,
@@ -3355,6 +3355,7 @@ const TREND_MIRROR_POINT_STYLE = {
3355
3355
  lineWidth: 1
3356
3356
  };
3357
3357
  const TREND_LINE_Z = 9999;
3358
+ const TREND_POINT_Z = 99999;
3358
3359
  const DEPTH_EDGE_SNAP = 0.2;
3359
3360
  const TREND_CLICK_DELAY_MS = 240;
3360
3361
  const TREND_HIT_RADIUS = 14;
@@ -3771,16 +3772,17 @@ function findSeriesForDepth(chart, paramId, depth) {
3771
3772
  }
3772
3773
  return fallback || { seriesIndex: 0, xAxisIndex: 0, yAxisIndex: 0 };
3773
3774
  }
3774
- function eventOffsetInChart(chart, evt) {
3775
+ function eventOffsetInChart(chart, evt, opts = {}) {
3775
3776
  var _a, _b;
3776
3777
  const zr = chart.getZr();
3777
- const clamp = (x, y) => ({
3778
- offsetX: Math.max(0, Math.min(x, zr.getWidth())),
3779
- offsetY: Math.max(0, Math.min(y, zr.getHeight()))
3780
- });
3781
- if (evt && evt.event && Number.isFinite(evt.offsetX) && Number.isFinite(evt.offsetY)) {
3782
- return clamp(evt.offsetX, evt.offsetY);
3783
- }
3778
+ const doClamp = opts.clamp !== false;
3779
+ const finish = (x, y) => {
3780
+ if (!doClamp) return { offsetX: x, offsetY: y };
3781
+ return {
3782
+ offsetX: Math.max(0, Math.min(x, zr.getWidth())),
3783
+ offsetY: Math.max(0, Math.min(y, zr.getHeight()))
3784
+ };
3785
+ };
3784
3786
  const native = (evt == null ? void 0 : evt.event) || evt;
3785
3787
  let el = null;
3786
3788
  try {
@@ -3789,12 +3791,50 @@ function eventOffsetInChart(chart, evt) {
3789
3791
  }
3790
3792
  const rect = (_b = (_a = el || chart.getDom()) == null ? void 0 : _a.getBoundingClientRect) == null ? void 0 : _b.call(_a);
3791
3793
  if (rect && Number.isFinite(native == null ? void 0 : native.clientX) && Number.isFinite(native == null ? void 0 : native.clientY)) {
3792
- return clamp(native.clientX - rect.left, native.clientY - rect.top);
3794
+ return finish(native.clientX - rect.left, native.clientY - rect.top);
3795
+ }
3796
+ if (evt && evt.event && Number.isFinite(evt.offsetX) && Number.isFinite(evt.offsetY)) {
3797
+ return finish(evt.offsetX, evt.offsetY);
3793
3798
  }
3794
3799
  if (Number.isFinite(evt == null ? void 0 : evt.offsetX) && Number.isFinite(evt == null ? void 0 : evt.offsetY)) {
3795
- return clamp(evt.offsetX, evt.offsetY);
3800
+ return finish(evt.offsetX, evt.offsetY);
3796
3801
  }
3797
- return clamp(0, 0);
3802
+ return finish(0, 0);
3803
+ }
3804
+ function eventOffsetInChartRaw(chart, evt) {
3805
+ return eventOffsetInChart(chart, evt, { clamp: false });
3806
+ }
3807
+ function getGridPixelRect(chart, yAxisIndex = 0) {
3808
+ try {
3809
+ const model = chartModel(chart);
3810
+ const yComp = model && model.getComponent("yAxis", yAxisIndex || 0);
3811
+ const cs = yComp && yComp.coordinateSystem;
3812
+ const rect = cs && cs.getRect && cs.getRect();
3813
+ if (!rect || !rect.width || !rect.height) return null;
3814
+ return {
3815
+ left: rect.x,
3816
+ top: rect.y,
3817
+ right: rect.x + rect.width,
3818
+ bottom: rect.y + rect.height,
3819
+ width: rect.width,
3820
+ height: rect.height
3821
+ };
3822
+ } catch (e) {
3823
+ return null;
3824
+ }
3825
+ }
3826
+ function isPointerInGrid(chart, offsetX, offsetY, yAxisIndex = 0) {
3827
+ const grid = getGridPixelRect(chart, yAxisIndex);
3828
+ if (!grid) return true;
3829
+ return offsetX >= grid.left && offsetX <= grid.right && offsetY >= grid.top && offsetY <= grid.bottom;
3830
+ }
3831
+ function clampPointerToGrid(chart, offsetX, offsetY, yAxisIndex = 0) {
3832
+ const grid = getGridPixelRect(chart, yAxisIndex);
3833
+ if (!grid) return { offsetX, offsetY };
3834
+ return {
3835
+ offsetX: Math.max(grid.left, Math.min(grid.right, offsetX)),
3836
+ offsetY: Math.max(grid.top, Math.min(grid.bottom, offsetY))
3837
+ };
3798
3838
  }
3799
3839
  function isPointerInAnyGrid(chart, offsetX, offsetY) {
3800
3840
  const gridCount = modelGridCount(chartModel(chart));
@@ -3862,7 +3902,7 @@ function pixelToData(chart, paramId, offsetX, offsetY, loose = false) {
3862
3902
  }
3863
3903
  return null;
3864
3904
  }
3865
- function axisPairToPixel(chart, xAxisIndex, yAxisIndex, value, depth) {
3905
+ function axisPairToPixel(chart, xAxisIndex, yAxisIndex, value, depth, clamp = false) {
3866
3906
  try {
3867
3907
  const model = chartModel(chart);
3868
3908
  if (!model) return null;
@@ -3871,8 +3911,8 @@ function axisPairToPixel(chart, xAxisIndex, yAxisIndex, value, depth) {
3871
3911
  const xAxis = xComp && xComp.axis;
3872
3912
  const yAxis = yComp && yComp.axis;
3873
3913
  if (!xAxis || !yAxis) return null;
3874
- const x = xAxis.toGlobalCoord(xAxis.dataToCoord(value, true));
3875
- const y = yAxis.toGlobalCoord(yAxis.dataToCoord(depth, true));
3914
+ const x = xAxis.toGlobalCoord(xAxis.dataToCoord(value, clamp));
3915
+ const y = yAxis.toGlobalCoord(yAxis.dataToCoord(depth, clamp));
3876
3916
  if (Number.isFinite(x) && Number.isFinite(y)) return [x, y];
3877
3917
  } catch (e) {
3878
3918
  }
@@ -3946,6 +3986,12 @@ function getAxisRange(chart, paramId, depth) {
3946
3986
  }
3947
3987
  class TrendLineManager {
3948
3988
  constructor(host) {
3989
+ /**
3990
+ * 趋势线改走 ECharts graphic 全量绘制(不走笛卡尔 series)。
3991
+ * series + clip 会在泳道边缘裁掉控制点;graphic 圆点可画在 grid 内可见处。
3992
+ * 缩放/平移按真实 knot.depth 重算像素。8.31
3993
+ */
3994
+ __publicField(this, "_KNOT_R", 4);
3949
3995
  this.host = host;
3950
3996
  this.store = /* @__PURE__ */ Object.create(null);
3951
3997
  this.activeKey = null;
@@ -3954,8 +4000,13 @@ class TrendLineManager {
3954
4000
  this.dragSession = null;
3955
4001
  this._panLockedByHover = false;
3956
4002
  this._raf = null;
3957
- this._seriesIds = /* @__PURE__ */ Object.create(null);
3958
- this._graphicCleared = /* @__PURE__ */ new WeakSet();
4003
+ this._graphicIds = /* @__PURE__ */ Object.create(null);
4004
+ this._ensuringDzSkip = false;
4005
+ this._zoomTrendPatchLanes = /* @__PURE__ */ new Set();
4006
+ this._zoomTrendPatchRaf = 0;
4007
+ this._zoomTrendPatchRaf2 = 0;
4008
+ this._zoomTrendNeedFollowUp = false;
4009
+ this._landingLithByParam = /* @__PURE__ */ Object.create(null);
3959
4010
  this._ignoreClickUntil = 0;
3960
4011
  this._destroyed = false;
3961
4012
  }
@@ -3977,8 +4028,19 @@ class TrendLineManager {
3977
4028
  cancelAnimationFrame(this._raf);
3978
4029
  this._raf = null;
3979
4030
  }
4031
+ if (this._zoomTrendPatchRaf) {
4032
+ cancelAnimationFrame(this._zoomTrendPatchRaf);
4033
+ this._zoomTrendPatchRaf = 0;
4034
+ }
4035
+ if (this._zoomTrendPatchRaf2) {
4036
+ cancelAnimationFrame(this._zoomTrendPatchRaf2);
4037
+ this._zoomTrendPatchRaf2 = 0;
4038
+ }
4039
+ this._zoomTrendNeedFollowUp = false;
4040
+ this._zoomTrendPatchLanes = /* @__PURE__ */ new Set();
3980
4041
  this.store = /* @__PURE__ */ Object.create(null);
3981
- this._seriesIds = /* @__PURE__ */ Object.create(null);
4042
+ this._graphicIds = /* @__PURE__ */ Object.create(null);
4043
+ this._landingLithByParam = /* @__PURE__ */ Object.create(null);
3982
4044
  this.binds.clear();
3983
4045
  this.host = null;
3984
4046
  }
@@ -4057,16 +4119,26 @@ class TrendLineManager {
4057
4119
  if (!chart || chart.isDisposed()) return null;
4058
4120
  return chart;
4059
4121
  }
4122
+ /** canClickSelectLane=true 才允许绘制/编辑趋势线;false 时仅回显不可画。8.26 */
4123
+ _isTrendDrawEnabled() {
4124
+ return !!(this.host && this.host.canClickSelectLane);
4125
+ }
4126
+ /** 未选中泳道不可加点、拖点;仅回显。8.31 */
4127
+ _isLaneSelected(laneId) {
4128
+ if (!this.host || typeof this.host.isLaneSelected !== "function") return false;
4129
+ return !!this.host.isLaneSelected(laneId);
4130
+ }
4060
4131
  /** isDraw 可编辑,或已有控制点(只读回显)的曲线。8.21 */
4061
4132
  listDrawableTargets() {
4062
4133
  if (!this._alive()) return [];
4063
4134
  const lanes = this.host.currentTemplate && this.host.currentTemplate.lanes || [];
4064
4135
  const list = [];
4136
+ const drawEnabled = this._isTrendDrawEnabled();
4065
4137
  lanes.forEach((lane) => {
4066
4138
  (lane.lines || []).forEach((line) => {
4067
4139
  const key = makeTrendKey(lane.laneId, line.paramId);
4068
4140
  const segments = this.store[key] && this.store[key].segments || [];
4069
- const editable = isLineDrawable(line);
4141
+ const editable = !!(drawEnabled && isLineDrawable(line) && this._isLaneSelected(lane.laneId));
4070
4142
  if (!editable && !segments.some((s) => (s.knots || []).length)) return;
4071
4143
  list.push({
4072
4144
  key,
@@ -4124,23 +4196,60 @@ class TrendLineManager {
4124
4196
  bindChart(laneId, chart) {
4125
4197
  this.unbindChart(laneId);
4126
4198
  if (!this._alive() || !chart || chart.isDisposed()) return;
4127
- const onZrDown = (e) => this.onZrMouseDown(e, laneId);
4128
4199
  const onZrMove = (e) => this.onZrHover(e, laneId);
4129
4200
  const onDblClick = (e) => this.handleDblClick(e, laneId);
4130
4201
  const zr = chart.getZr();
4131
- zr.on("mousedown", onZrDown);
4132
4202
  zr.on("mousemove", onZrMove);
4133
4203
  zr.on("dblclick", onDblClick);
4204
+ const dom = chart.getDom();
4205
+ const onMouseDown = (nativeEvent) => {
4206
+ if (!this._isPrimaryButton(nativeEvent)) return;
4207
+ this.onZrMouseDown({ event: nativeEvent }, laneId);
4208
+ };
4209
+ if (dom) dom.addEventListener("mousedown", onMouseDown, true);
4134
4210
  const onZoom = () => {
4211
+ this._stripResidualTrendSeries(chart);
4212
+ this._scheduleZoomTrendPatch(laneId);
4213
+ if (this.host && typeof this.host.ensureTrendDataZoomOnAllCharts === "function") {
4214
+ this.host.ensureTrendDataZoomOnAllCharts(chart);
4215
+ }
4135
4216
  if (this.host && this.host._isPanning) return;
4136
4217
  if (this.host && typeof this.host.startChartZoom === "function") {
4137
4218
  this.host.startChartZoom();
4138
4219
  }
4139
4220
  };
4140
4221
  if (typeof chart.on === "function") chart.on("datazoom", onZoom);
4141
- this.binds.set(laneId, { chart, onZrDown, onZrMove, onDblClick, onZoom, dom: chart.getDom() });
4222
+ this.binds.set(laneId, {
4223
+ chart,
4224
+ onZrMove,
4225
+ onDblClick,
4226
+ onZoom,
4227
+ dom,
4228
+ onMouseDown
4229
+ });
4142
4230
  this.updateCursor(laneId);
4143
4231
  }
4232
+ isDraggingKnot() {
4233
+ return !!this.dragSession;
4234
+ }
4235
+ /** 命中趋势线控制点时,地应力 dataZoom 平移不要抢 mousedown。8.26 */
4236
+ shouldBlockChartPan(chart, evt) {
4237
+ if (!this._isTrendDrawEnabled()) return false;
4238
+ if (this.dragSession) return true;
4239
+ if (!this._alive() || !chart || chart.isDisposed()) return false;
4240
+ const laneId = this.host && typeof this.host.findLaneIdByChart === "function" ? this.host.findLaneIdByChart(chart) : null;
4241
+ if (!laneId) return false;
4242
+ const target = this.getTargetByLane(laneId);
4243
+ if (!target || !target.editable) return false;
4244
+ const { offsetX, offsetY } = eventOffsetInChart(chart, evt);
4245
+ return !!this._findKnotAtPointer(chart, target, offsetX, offsetY);
4246
+ }
4247
+ _isPrimaryButton(evt) {
4248
+ const native = evt && evt.event ? evt.event : evt;
4249
+ if (native && native.button != null) return native.button === 0;
4250
+ if (evt && evt.which != null) return evt.which === 1;
4251
+ return true;
4252
+ }
4144
4253
  unbindChart(laneId) {
4145
4254
  const bind = this.binds.get(laneId);
4146
4255
  if (!bind) return;
@@ -4159,7 +4268,6 @@ class TrendLineManager {
4159
4268
  if (chart && typeof chart.getZr === "function") {
4160
4269
  const zr = chart.getZr();
4161
4270
  if (zr) {
4162
- if (bind.onZrDown) zr.off("mousedown", bind.onZrDown);
4163
4271
  if (bind.onZrMove) zr.off("mousemove", bind.onZrMove);
4164
4272
  if (bind.onDblClick) zr.off("dblclick", bind.onDblClick);
4165
4273
  if (bind.onZoom) zr.off("mousewheel", bind.onZoom);
@@ -4170,11 +4278,10 @@ class TrendLineManager {
4170
4278
  }
4171
4279
  } catch (e) {
4172
4280
  }
4173
- delete this._seriesIds[laneId];
4281
+ delete this._graphicIds[laneId];
4174
4282
  if (bind) {
4175
4283
  bind.chart = null;
4176
4284
  bind.dom = null;
4177
- bind.onZrDown = null;
4178
4285
  bind.onZrMove = null;
4179
4286
  bind.onDblClick = null;
4180
4287
  bind.onZoom = null;
@@ -4216,18 +4323,33 @@ class TrendLineManager {
4216
4323
  }
4217
4324
  return false;
4218
4325
  }
4219
- // 趋势线已是笛卡尔 series,dataZoom 带着走;这些入口留给旧调用方,不再像素跟帧。8.25
4326
+ // graphic:缩放/平移按 knot.depth 重算像素。8.31
4220
4327
  scheduleZoomRender() {
4328
+ this._scheduleZoomTrendPatch("*");
4329
+ }
4330
+ /**
4331
+ * 泳道图表 resize 后重算 graphic 像素。
4332
+ * 趋势线是绝对像素,autoresize 只调 chart.resize 不会带动 graphic;
4333
+ * 不补这一步会表现为回显偏左,点选泳道后 scheduleRender 才往右跳。8.31
4334
+ */
4335
+ onChartResized(laneId) {
4336
+ if (!this.hasAnyKnots()) return;
4337
+ this._scheduleZoomTrendPatch(laneId != null ? laneId : "*");
4221
4338
  }
4222
4339
  beginPanFollow() {
4223
4340
  }
4341
+ /** 平移跟帧:只排一帧,不补第二帧(缩放才需要等轴就绪)。8.31 */
4224
4342
  tickPanFollow() {
4343
+ this._scheduleZoomTrendPatch("*", { followUp: false });
4225
4344
  }
4226
4345
  endPanFollow() {
4346
+ this._scheduleZoomTrendPatch("*");
4227
4347
  }
4228
4348
  endFollowView() {
4349
+ this._scheduleZoomTrendPatch("*");
4229
4350
  }
4230
4351
  _patchAllPositions() {
4352
+ this._scheduleZoomTrendPatch("*");
4231
4353
  }
4232
4354
  _isTrendSeriesOpt(series) {
4233
4355
  if (!series) return false;
@@ -4264,262 +4386,208 @@ class TrendLineManager {
4264
4386
  yAxisIndex: info && info.yAxisIndex != null ? info.yAxisIndex : 0
4265
4387
  };
4266
4388
  }
4267
- _buildOneTrendSeries(id, data, lineStyle, pointStyle, xAxisIndex, yAxisIndex) {
4268
- return {
4269
- id,
4270
- name: "trend",
4271
- type: "line",
4272
- data,
4273
- xAxisIndex,
4274
- yAxisIndex,
4275
- clip: true,
4276
- animation: false,
4277
- silent: true,
4278
- large: false,
4279
- z: TREND_LINE_Z,
4280
- zlevel: 0,
4281
- symbol: "circle",
4282
- symbolSize: 8,
4283
- showSymbol: true,
4284
- hoverAnimation: false,
4285
- legendHoverLink: false,
4286
- connectNulls: false,
4287
- tooltip: { show: false },
4288
- emphasis: { disabled: true },
4289
- lineStyle: {
4290
- color: lineStyle.stroke,
4291
- width: lineStyle.lineWidth,
4292
- type: lineStyle.lineDash || "solid"
4293
- },
4294
- itemStyle: {
4295
- color: pointStyle.fill,
4296
- borderColor: pointStyle.stroke,
4297
- borderWidth: pointStyle.lineWidth
4298
- }
4299
- };
4389
+ _lineStyleFor(line, segments, role = "main") {
4390
+ if (role === "mirror") return TREND_MIRROR_LINE_STYLE;
4391
+ return this._useGammaStyle(line, segments) ? TREND_DOUBLE_LINE_STYLE : TREND_LINE_STYLE;
4300
4392
  }
4301
- _knotPoint(x, depth) {
4302
- return { value: [x, depth], symbol: "circle", symbolSize: 8 };
4393
+ _pointStyleFor(line, segments, role = "main") {
4394
+ if (role === "mirror") return TREND_MIRROR_POINT_STYLE;
4395
+ return this._useGammaStyle(line, segments) ? TREND_DOUBLE_POINT_STYLE : TREND_POINT_STYLE;
4303
4396
  }
4304
- _segSeriesData(knots, role) {
4305
- const raw = [];
4306
- for (let i = 0; i < (knots || []).length; i++) {
4307
- const knot = knots[i];
4308
- const x = this._knotDrawX(knot, role);
4309
- const depth = Number(knot && knot.depth);
4310
- if (x == null || !Number.isFinite(depth)) continue;
4311
- raw.push([x, depth]);
4312
- }
4313
- if (raw.length < 2) {
4314
- return raw.map((p) => this._knotPoint(p[0], p[1]));
4315
- }
4316
- const data = [];
4317
- for (let i = 0; i < raw.length - 1; i++) {
4318
- const a = raw[i];
4319
- const b = raw[i + 1];
4320
- data.push(this._knotPoint(a[0], a[1]));
4321
- const span = Math.abs(b[1] - a[1]);
4322
- const n = Math.min(160, Math.max(0, Math.floor(span / 4)));
4323
- for (let k = 1; k < n; k++) {
4324
- const t = k / n;
4325
- data.push({
4326
- value: [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t],
4327
- symbol: "none"
4328
- });
4329
- }
4330
- }
4331
- const last = raw[raw.length - 1];
4332
- data.push(this._knotPoint(last[0], last[1]));
4333
- return data;
4397
+ _safeKey(key) {
4398
+ return String(key || "").replace(/[^a-zA-Z0-9_\-.:]/g, "_");
4334
4399
  }
4335
- /** 曲线仍 weakFilter;趋势线点太稀,滤掉窗外控制点后穿过视窗的线会断。8.25 */
4336
- applyDataZoomSkipTrend(option) {
4337
- if (!option) return;
4338
- const raw = option.dataZoom;
4339
- if (!raw) return;
4340
- const list = Array.isArray(raw) ? raw : [raw];
4341
- const indexes = [];
4342
- const series = option.series || [];
4343
- for (let i = 0; i < series.length; i++) {
4344
- if (!this._isTrendSeriesOpt(series[i])) indexes.push(i);
4400
+ _listNonTrendGraphics(chart) {
4401
+ if (!chart || chart.isDisposed()) return [];
4402
+ try {
4403
+ const list = chart.getModel().queryComponents({ mainType: "graphic" }) || [];
4404
+ return list.map((g) => g && g.option || g).filter((g) => {
4405
+ const id = g && g.id;
4406
+ return id && String(id).indexOf("trend_") !== 0;
4407
+ }).map((g) => ({ ...g }));
4408
+ } catch (e) {
4409
+ return [];
4345
4410
  }
4346
- if (!indexes.length) return;
4347
- list.forEach((dz) => {
4348
- if (dz) dz.seriesIndex = indexes;
4349
- });
4350
4411
  }
4351
- dataZoomSeriesIndex(chart) {
4352
- if (!chart || chart.isDisposed()) return null;
4412
+ _listLiveTrendGraphicIds(chart) {
4413
+ if (!chart || chart.isDisposed()) return [];
4353
4414
  try {
4354
- const list = chart.getModel().getSeries() || [];
4355
- const indexes = [];
4415
+ const list = chart.getModel().queryComponents({ mainType: "graphic" }) || [];
4416
+ const ids = [];
4356
4417
  for (let i = 0; i < list.length; i++) {
4357
- const sm = list[i];
4358
- const opt = sm && sm.option || {};
4359
- const name = Array.isArray(sm.name) ? sm.name[0] : sm.name;
4360
- if (this._isTrendSeriesOpt({ name, id: opt.id })) continue;
4361
- if (sm.seriesIndex != null) indexes.push(sm.seriesIndex);
4418
+ const opt = list[i] && list[i].option || list[i];
4419
+ const id = opt && opt.id;
4420
+ if (id && String(id).indexOf("trend_") === 0) ids.push(id);
4362
4421
  }
4363
- return indexes.length ? indexes : null;
4422
+ return ids;
4364
4423
  } catch (e) {
4365
- return null;
4424
+ return [];
4366
4425
  }
4367
4426
  }
4368
- /** 笛卡尔 [曲线值, 井深];对数道 X 已是 lg。和曲线共用轴,dataZoom 同一帧带走。8.25 */
4369
- _buildTrendSeries(target, xAxisIndex, yAxisIndex) {
4370
- const list = [];
4371
- const { key, segments, line } = target;
4372
- const canMirror = this._canMirror(line, segments);
4373
- const doubleLine = this._useGammaStyle(line, segments);
4374
- const mainLineStyle = doubleLine ? TREND_DOUBLE_LINE_STYLE : TREND_LINE_STYLE;
4375
- const mainPointStyle = doubleLine ? TREND_DOUBLE_POINT_STYLE : TREND_POINT_STYLE;
4376
- (segments || []).forEach((seg) => {
4377
- const knots = seg.knots || [];
4378
- if (!knots.length) return;
4379
- list.push(
4380
- this._buildOneTrendSeries(
4381
- `trend_${key}_${seg.id}`,
4382
- this._segSeriesData(knots, "main"),
4383
- mainLineStyle,
4384
- mainPointStyle,
4385
- xAxisIndex,
4386
- yAxisIndex
4387
- )
4388
- );
4389
- if (!canMirror) return;
4390
- const mirror = this._segSeriesData(knots, "mirror");
4391
- if (!mirror.length) return;
4392
- list.push(
4393
- this._buildOneTrendSeries(
4394
- `trend_mirror_${key}_${seg.id}`,
4395
- mirror,
4396
- TREND_MIRROR_LINE_STYLE,
4397
- TREND_MIRROR_POINT_STYLE,
4398
- xAxisIndex,
4399
- yAxisIndex
4400
- )
4427
+ _stripResidualTrendSeries(chart) {
4428
+ if (!chart || chart.isDisposed()) return;
4429
+ const ids = this._chartTrendSeriesIds(chart);
4430
+ if (!ids.length) return;
4431
+ try {
4432
+ chart.setOption(
4433
+ { series: ids.map((id) => ({ id, $action: "remove" })) },
4434
+ { silent: true, lazyUpdate: false }
4401
4435
  );
4402
- });
4403
- return list;
4436
+ } catch (e) {
4437
+ }
4404
4438
  }
4405
- /** 刷 option 时给该道补上趋势 series,所有有控制点的泳道都会走。8.25 */
4406
- appendSeriesToOption(option, lane) {
4407
- if (!option || !lane) return option;
4408
- if (!Array.isArray(option.series)) option.series = [];
4409
- option.series = option.series.filter((s) => !this._isTrendSeriesOpt(s));
4410
- const targets = this.listDrawableTargets().filter(
4411
- (t) => String(t.laneId) === String(lane.laneId)
4412
- );
4413
- const added = [];
4414
- targets.forEach((target) => {
4415
- const curve = this._findCurveSeriesInOption(option, target.paramId);
4416
- if (!curve) return;
4417
- const xAxisIndex = curve.xAxisIndex == null ? 0 : Number(curve.xAxisIndex);
4418
- const yAxisIndex = curve.yAxisIndex == null ? 0 : Number(curve.yAxisIndex);
4419
- added.push(...this._buildTrendSeries(target, xAxisIndex, yAxisIndex));
4439
+ /**
4440
+ * 控制点显示像素:按真实 depth 换算(不夹紧到视窗)。
4441
+ * 视窗外不画点(线仍用真实像素跟缩放);视窗内贴边仅微内收,避免钉死顶/底。8.31
4442
+ */
4443
+ _knotDisplayPixel(chart, target, knot, role = "main") {
4444
+ const px = this._knotPixel(chart, target, knot, role);
4445
+ if (!px || !Number.isFinite(px[0]) || !Number.isFinite(px[1])) return null;
4446
+ const axis = this._curveAxisOf(chart, target);
4447
+ const rect = getGridPixelRect(chart, axis.yAxisIndex);
4448
+ if (!rect) return px;
4449
+ const r = this._KNOT_R;
4450
+ let cx = px[0];
4451
+ let cy = px[1];
4452
+ if (cy < rect.top - r || cy > rect.bottom + r) return null;
4453
+ if (cx < rect.left - r || cx > rect.right + r) return null;
4454
+ if (cy < rect.top + r) cy = rect.top + r;
4455
+ else if (cy > rect.bottom - r) cy = rect.bottom - r;
4456
+ if (cx < rect.left + r) cx = rect.left + r;
4457
+ else if (cx > rect.right - r) cx = rect.right - r;
4458
+ return [cx, cy];
4459
+ }
4460
+ _buildTrendGraphics(chart, targets, { activeKnot = null } = {}) {
4461
+ const elements = [];
4462
+ (targets || []).forEach((target) => {
4463
+ const canMirror = this._canMirror(target.line, target.segments);
4464
+ const key = this._safeKey(target.key);
4465
+ let flatIdx = 0;
4466
+ (target.segments || []).forEach((seg) => {
4467
+ const knots = seg.knots || [];
4468
+ for (let i = 0; i < knots.length - 1; i++) {
4469
+ const roles = canMirror ? ["main", "mirror"] : ["main"];
4470
+ roles.forEach((role) => {
4471
+ const px1 = this._knotPixel(chart, target, knots[i], role);
4472
+ const px2 = this._knotPixel(chart, target, knots[i + 1], role);
4473
+ if (!px1 || !px2 || !Number.isFinite(px1[0]) || !Number.isFinite(px1[1]) || !Number.isFinite(px2[0]) || !Number.isFinite(px2[1])) {
4474
+ return;
4475
+ }
4476
+ const lineStyle = this._lineStyleFor(target.line, target.segments, role);
4477
+ const id = role === "mirror" ? `trend_mirror_${key}_${seg.id}_${i}` : `trend_line_${key}_${seg.id}_${i}`;
4478
+ elements.push({
4479
+ type: "line",
4480
+ id,
4481
+ shape: { x1: px1[0], y1: px1[1], x2: px2[0], y2: px2[1] },
4482
+ style: {
4483
+ stroke: lineStyle.stroke,
4484
+ lineWidth: lineStyle.lineWidth,
4485
+ lineDash: lineStyle.lineDash || void 0
4486
+ },
4487
+ z: role === "mirror" ? TREND_LINE_Z - 1 : TREND_LINE_Z,
4488
+ silent: true
4489
+ });
4490
+ });
4491
+ }
4492
+ knots.forEach((knot, i) => {
4493
+ const px = this._knotDisplayPixel(chart, target, knot, "main");
4494
+ if (px) {
4495
+ const pointStyle2 = this._pointStyleFor(target.line, target.segments, "main");
4496
+ const active = activeKnot === knot;
4497
+ elements.push({
4498
+ type: "circle",
4499
+ id: `trend_pt_${key}_${flatIdx}`,
4500
+ shape: { cx: px[0], cy: px[1], r: active ? 5 : this._KNOT_R },
4501
+ style: {
4502
+ fill: pointStyle2.fill,
4503
+ stroke: pointStyle2.stroke,
4504
+ lineWidth: pointStyle2.lineWidth
4505
+ },
4506
+ z: TREND_POINT_Z,
4507
+ silent: true,
4508
+ cursor: target.editable ? "pointer" : "default"
4509
+ });
4510
+ }
4511
+ flatIdx++;
4512
+ if (!canMirror) return;
4513
+ const mx = this._knotDisplayPixel(chart, target, knot, "mirror");
4514
+ if (!mx) return;
4515
+ const pointStyle = this._pointStyleFor(target.line, target.segments, "mirror");
4516
+ elements.push({
4517
+ type: "circle",
4518
+ id: `trend_mirror_pt_${key}_${seg.id}_${i}`,
4519
+ shape: { cx: mx[0], cy: mx[1], r: this._KNOT_R },
4520
+ style: {
4521
+ fill: pointStyle.fill,
4522
+ stroke: pointStyle.stroke,
4523
+ lineWidth: pointStyle.lineWidth
4524
+ },
4525
+ z: TREND_POINT_Z,
4526
+ silent: true,
4527
+ cursor: target.editable ? "pointer" : "default"
4528
+ });
4529
+ });
4530
+ });
4420
4531
  });
4421
- option.series.push(...added);
4422
- this._seriesIds[lane.laneId] = added.map((s) => s.id);
4423
- this.applyDataZoomSkipTrend(option);
4424
- return option;
4532
+ return elements;
4425
4533
  }
4426
- _clearLeftoverGraphic(chart) {
4427
- if (!chart || chart.isDisposed() || this._graphicCleared.has(chart)) return;
4428
- this._graphicCleared.add(chart);
4429
- try {
4430
- chart.setOption({ graphic: [] }, { replaceMerge: ["graphic"], silent: true, lazyUpdate: false });
4431
- } catch (e) {
4534
+ /** 刷 option 时去掉残留趋势 series;不把 graphic 像素写入缓存。8.31 */
4535
+ appendSeriesToOption(option) {
4536
+ if (!option) return option;
4537
+ if (Array.isArray(option.series)) {
4538
+ option.series = option.series.filter((s) => !this._isTrendSeriesOpt(s));
4432
4539
  }
4540
+ if (Array.isArray(option.graphic)) {
4541
+ option.graphic = option.graphic.filter((g) => !(g && g.id && String(g.id).indexOf("trend_") === 0));
4542
+ } else if (option.graphic && Array.isArray(option.graphic.elements)) {
4543
+ option.graphic.elements = option.graphic.elements.filter(
4544
+ (g) => !(g && g.id && String(g.id).indexOf("trend_") === 0)
4545
+ );
4546
+ }
4547
+ return option;
4433
4548
  }
4434
4549
  renderAll(forceReplace = false) {
4435
4550
  const lanes = this.host.currentTemplate && this.host.currentTemplate.lanes || [];
4436
4551
  lanes.forEach((lane) => this.renderLane(lane.laneId, forceReplace));
4437
4552
  }
4438
- /** 用笛卡尔 series 画趋势线;平移/缩放交给 dataZoom,不跟像素。8.25 */
4553
+ /** graphic 全量 setOption;缩放/拖拽后按 depth 重算。8.31 */
4439
4554
  renderLane(laneId, forceReplace = false) {
4440
4555
  if (!this._alive()) return;
4441
4556
  const chart = this.getChart(laneId);
4442
4557
  if (!chart) return;
4443
- this._clearLeftoverGraphic(chart);
4558
+ this._stripResidualTrendSeries(chart);
4444
4559
  const targets = this.listDrawableTargets().filter(
4445
4560
  (t) => String(t.laneId) === String(laneId)
4446
4561
  );
4447
- const next = [];
4448
- targets.forEach((target) => {
4449
- const axis = this._curveAxisOf(chart, target);
4450
- next.push(...this._buildTrendSeries(target, axis.xAxisIndex, axis.yAxisIndex));
4562
+ const hasKnots = targets.some((t) => this._hasTrendKnots(t.segments));
4563
+ const trendEls = this._buildTrendGraphics(chart, targets, {
4564
+ activeKnot: this.dragSession && this.dragSession.knot
4451
4565
  });
4452
- const nextIds = next.map((s) => s.id);
4453
- const nextSet = new Set(nextIds);
4454
- const liveIds = this._chartTrendSeriesIds(chart);
4455
- const prevIds = [.../* @__PURE__ */ new Set([...this._seriesIds[laneId] || [], ...liveIds])];
4456
- const replace = !!(forceReplace && !this.dragSession);
4457
- const patch = next.map((s) => ({
4458
- ...s,
4459
- data: s.data || [],
4460
- $action: replace ? "replace" : "merge"
4461
- }));
4462
- prevIds.forEach((id) => {
4463
- if (!nextSet.has(id)) patch.push({ id, $action: "remove" });
4464
- });
4465
- if (patch.length) {
4466
- try {
4467
- chart.setOption({ series: patch }, { silent: true, lazyUpdate: false });
4468
- } catch (e) {
4469
- }
4566
+ if (hasKnots && !trendEls.length && !forceReplace) return;
4567
+ const others = this._listNonTrendGraphics(chart);
4568
+ const elements = [...others, ...trendEls];
4569
+ try {
4570
+ chart.setOption(
4571
+ { graphic: { elements } },
4572
+ { replaceMerge: ["graphic"], silent: true, lazyUpdate: false }
4573
+ );
4574
+ } catch (e) {
4470
4575
  }
4471
- this._seriesIds[laneId] = nextIds;
4576
+ this._graphicIds[laneId] = trendEls.map((el) => el.id).filter(Boolean);
4472
4577
  if (!this.dragSession) this._syncCachedOption(laneId);
4473
- if (this.dragSession) {
4474
- this.updateCursor(laneId);
4475
- return;
4476
- }
4477
- const idsChanged = nextIds.length !== prevIds.length || nextIds.some((id, i) => id !== prevIds[i]);
4478
- if (idsChanged) {
4479
- const skip = this.dataZoomSeriesIndex(chart);
4480
- if (skip && skip.length) {
4481
- try {
4482
- const dz = chart.getModel().getComponent("dataZoom", 0);
4483
- const opt = dz && dz.option;
4484
- const next2 = { seriesIndex: skip };
4485
- if (opt) {
4486
- if (opt.start != null) next2.start = opt.start;
4487
- if (opt.end != null) next2.end = opt.end;
4488
- if (opt.startValue != null) next2.startValue = opt.startValue;
4489
- if (opt.endValue != null) next2.endValue = opt.endValue;
4490
- }
4491
- chart.setOption({ dataZoom: [next2] }, { silent: true, lazyUpdate: true });
4492
- } catch (e) {
4493
- }
4494
- }
4495
- }
4496
4578
  this.updateCursor(laneId);
4497
4579
  }
4498
- /** 把当前 store 写回 allOptions,避免随后 notMerge 用旧趋势 series 把点盖回去。8.25 */
4580
+ /** 缓存只清趋势 series,不写 graphic 像素。8.31 */
4499
4581
  _syncCachedOption(laneId) {
4500
4582
  const host = this.host;
4501
4583
  if (!host || typeof host.getOptionsByLineId !== "function") return null;
4502
4584
  const option = host.getOptionsByLineId(laneId);
4503
- if (!option || !Array.isArray(option.series)) return null;
4504
- const lanes = host.currentTemplate && host.currentTemplate.lanes || [];
4505
- const lane = lanes.find((l) => l.laneId === laneId);
4506
- if (!lane) return null;
4507
- this.appendSeriesToOption(option, lane);
4585
+ if (!option) return null;
4586
+ this.appendSeriesToOption(option);
4508
4587
  return option;
4509
4588
  }
4510
- /** 删点后走整份 option 替换,ECharts 才会丢掉缩短后的旧 data。8.25 */
4511
4589
  _flushLane(laneId) {
4512
- const option = this._syncCachedOption(laneId);
4513
- if (option && this.host && typeof this.host.flushLaneChartOption === "function") {
4514
- option.__kdTrendSynced = true;
4515
- try {
4516
- this.host.flushLaneChartOption(laneId, option);
4517
- } finally {
4518
- delete option.__kdTrendSynced;
4519
- }
4520
- this.updateCursor(laneId);
4521
- return;
4522
- }
4590
+ this._syncCachedOption(laneId);
4523
4591
  this.renderLane(laneId, true);
4524
4592
  }
4525
4593
  _chartTrendSeriesIds(chart) {
@@ -4539,6 +4607,59 @@ class TrendLineManager {
4539
4607
  return [];
4540
4608
  }
4541
4609
  }
4610
+ applyDataZoomSkipTrend(option) {
4611
+ if (!option || !Array.isArray(option.series)) return;
4612
+ option.series = option.series.filter((s) => !this._isTrendSeriesOpt(s));
4613
+ }
4614
+ ensureDataZoomSkipsTrend(chart) {
4615
+ this._stripResidualTrendSeries(chart);
4616
+ }
4617
+ dataZoomSeriesIndex(chart) {
4618
+ if (!chart || chart.isDisposed()) return null;
4619
+ try {
4620
+ const list = chart.getModel().getSeries() || [];
4621
+ const indexes = [];
4622
+ for (let i = 0; i < list.length; i++) {
4623
+ const sm = list[i];
4624
+ const opt = sm && sm.option || {};
4625
+ const name = Array.isArray(sm.name) ? sm.name[0] : sm.name;
4626
+ const id = opt.id || sm.id;
4627
+ if (this._isTrendSeriesOpt({ name, id })) continue;
4628
+ indexes.push(i);
4629
+ }
4630
+ return indexes;
4631
+ } catch (e) {
4632
+ return null;
4633
+ }
4634
+ }
4635
+ /** 滚轮缩放:每帧最多重画一次;followUp 时再补一帧对齐轴。8.31 */
4636
+ _scheduleZoomTrendPatch(laneId, opts = {}) {
4637
+ if (this._destroyed || this.dragSession) return;
4638
+ const followUp = opts.followUp !== false;
4639
+ if (laneId != null && laneId !== "*") this._zoomTrendPatchLanes.add(laneId);
4640
+ else {
4641
+ const lanes = this.host.currentTemplate && this.host.currentTemplate.lanes || [];
4642
+ lanes.forEach((l) => l && l.laneId != null && this._zoomTrendPatchLanes.add(l.laneId));
4643
+ }
4644
+ if (followUp) this._zoomTrendNeedFollowUp = true;
4645
+ if (this._zoomTrendPatchRaf) return;
4646
+ this._zoomTrendPatchRaf = requestAnimationFrame(() => {
4647
+ this._zoomTrendPatchRaf = 0;
4648
+ if (this._destroyed || this.dragSession) return;
4649
+ const lanes = Array.from(this._zoomTrendPatchLanes);
4650
+ this._zoomTrendPatchLanes.clear();
4651
+ const needFollowUp = this._zoomTrendNeedFollowUp;
4652
+ this._zoomTrendNeedFollowUp = false;
4653
+ lanes.forEach((id) => this.renderLane(id, false));
4654
+ if (!needFollowUp) return;
4655
+ if (this._zoomTrendPatchRaf2) cancelAnimationFrame(this._zoomTrendPatchRaf2);
4656
+ this._zoomTrendPatchRaf2 = requestAnimationFrame(() => {
4657
+ this._zoomTrendPatchRaf2 = 0;
4658
+ if (this._destroyed || this.dragSession) return;
4659
+ lanes.forEach((id) => this.renderLane(id, false));
4660
+ });
4661
+ });
4662
+ }
4542
4663
  _findKnotAtPointer(chart, target, offsetX, offsetY, radius = TREND_HIT_RADIUS) {
4543
4664
  let best = null;
4544
4665
  let bestDist = radius;
@@ -4547,7 +4668,7 @@ class TrendLineManager {
4547
4668
  const knots = seg.knots || [];
4548
4669
  for (let i = 0; i < knots.length; i++) {
4549
4670
  const knot = knots[i];
4550
- const px = this._knotPixel(chart, target, knot);
4671
+ const px = this._knotHitPixel(chart, target, knot);
4551
4672
  if (px) {
4552
4673
  const dist = Math.hypot(px[0] - offsetX, px[1] - offsetY);
4553
4674
  if (dist <= bestDist) {
@@ -4556,7 +4677,7 @@ class TrendLineManager {
4556
4677
  }
4557
4678
  }
4558
4679
  if (!canMirror) continue;
4559
- const mx = this._knotPixel(chart, target, knot, "mirror");
4680
+ const mx = this._knotHitPixel(chart, target, knot, "mirror");
4560
4681
  if (!mx) continue;
4561
4682
  const mirrorDist = Math.hypot(mx[0] - offsetX, mx[1] - offsetY);
4562
4683
  if (mirrorDist <= bestDist) {
@@ -4569,6 +4690,7 @@ class TrendLineManager {
4569
4690
  }
4570
4691
  /** 单击空白处加点;延迟执行以便和双击断段区分。命中已有点则不加点。返回 true 表示已消费本次点击。8.21 */
4571
4692
  handleClick(e, laneId) {
4693
+ if (!this._isTrendDrawEnabled()) return false;
4572
4694
  if (!this._alive()) return false;
4573
4695
  if (this.dragSession) {
4574
4696
  this._endDrag(true);
@@ -4586,13 +4708,14 @@ class TrendLineManager {
4586
4708
  this._clearClickTimer();
4587
4709
  this.clickTimer = setTimeout(() => {
4588
4710
  this.clickTimer = null;
4589
- if (!this._alive()) return;
4711
+ if (!this._alive() || !this._isTrendDrawEnabled()) return;
4590
4712
  this._addPoint(chart, target, offsetX, offsetY);
4591
4713
  }, TREND_CLICK_DELAY_MS);
4592
4714
  return true;
4593
4715
  }
4594
4716
  /** 双击空白处断开当前段;会清掉单击定时器,避免双击再打出一个点。8.21 */
4595
4717
  handleDblClick(e, laneId) {
4718
+ if (!this._isTrendDrawEnabled()) return false;
4596
4719
  this._clearClickTimer();
4597
4720
  const target = this.getTargetByLane(laneId);
4598
4721
  if (!target || !target.editable) return false;
@@ -4610,6 +4733,7 @@ class TrendLineManager {
4610
4733
  }
4611
4734
  /** 右键命中控制点时弹出「删除控制点」。打开菜单时不要 setOption,否则会吞掉菜单点击。8.21 */
4612
4735
  handleContextMenu(e, laneId) {
4736
+ if (!this._isTrendDrawEnabled()) return false;
4613
4737
  const target = this.getTargetByLane(laneId);
4614
4738
  if (!target || !target.editable) return false;
4615
4739
  const chart = this.getChart(laneId);
@@ -4634,6 +4758,10 @@ class TrendLineManager {
4634
4758
  /** 指针靠近控制点时先停地应力平移,按下时才来得及拖点。8.22 */
4635
4759
  onZrHover(e, laneId) {
4636
4760
  if (!this._alive()) return;
4761
+ if (!this._isTrendDrawEnabled()) {
4762
+ if (this._panLockedByHover) this._setPanLocked(false, true);
4763
+ return;
4764
+ }
4637
4765
  if (this.dragSession) {
4638
4766
  e.__ecRoamConsumed = true;
4639
4767
  if (typeof e.stop === "function") e.stop();
@@ -4663,12 +4791,15 @@ class TrendLineManager {
4663
4791
  }
4664
4792
  /** 左键拖点与右键删点同一套命中(zr offset + _findKnotAtPointer)。8.25 */
4665
4793
  onZrMouseDown(e, laneId) {
4794
+ var _a;
4666
4795
  if (!this._alive()) return;
4667
- if (e.which != null && e.which !== 1 && e.event && e.event.button !== 0) return;
4796
+ if (!this._isTrendDrawEnabled()) return;
4797
+ if (!this._isPrimaryButton(e)) return;
4668
4798
  if (this.dragSession) {
4669
- e.__ecRoamConsumed = true;
4670
- if (typeof e.stop === "function") e.stop();
4671
- this._endDrag(true);
4799
+ if (e && e.event) {
4800
+ e.event.preventDefault();
4801
+ e.event.stopPropagation();
4802
+ }
4672
4803
  return;
4673
4804
  }
4674
4805
  const target = this.getTargetByLane(laneId);
@@ -4677,15 +4808,18 @@ class TrendLineManager {
4677
4808
  const { offsetX, offsetY } = eventOffsetInChart(chart, e);
4678
4809
  const hit = this._findKnotAtPointer(chart, target, offsetX, offsetY);
4679
4810
  if (!hit) return;
4811
+ const native = e.event || e;
4812
+ if (native) {
4813
+ native.preventDefault();
4814
+ native.stopPropagation();
4815
+ (_a = native.stopImmediatePropagation) == null ? void 0 : _a.call(native);
4816
+ }
4817
+ if (e && typeof e.stop === "function") e.stop();
4680
4818
  e.__ecRoamConsumed = true;
4681
- if (typeof e.stop === "function") e.stop();
4682
4819
  e.cancelBubble = true;
4683
- if (e.event) {
4684
- e.event.preventDefault();
4685
- e.event.stopPropagation();
4686
- }
4687
4820
  this._clearClickTimer();
4688
4821
  this.activeKey = target.key;
4822
+ this._setPanLocked(true, true);
4689
4823
  this._startDrag(chart, target, hit.knot, e, hit.role);
4690
4824
  }
4691
4825
  /** 沿深度增大方向追加控制点;曲线值限制在该线 min/max 内。8.21 */
@@ -4722,18 +4856,73 @@ class TrendLineManager {
4722
4856
  this._stripSegMirror(seg);
4723
4857
  knot = { ...knotDraft };
4724
4858
  } else if (isMoxingCalc(target.line) && seg.lithType) {
4725
- knot = {
4726
- ...knotDraft,
4727
- mirrorValue: this._calcMirrorValue(value, seg, chart, target.paramId, depth)
4728
- };
4729
- if (knotDraft.plotValue != null) {
4730
- knot.plotMirrorValue = this._calcMirrorValue(knotDraft.plotValue, seg, chart, target.paramId, depth);
4731
- }
4859
+ const landing = this._getLandingLithType(target, seg);
4860
+ knot = this._buildKnotForLith(chart, target, seg, depth, clickX, landing);
4732
4861
  }
4733
4862
  seg.knots = [...rest, knot].sort((a, b) => a.depth - b.depth);
4734
4863
  this.renderLane(target.laneId);
4735
4864
  this._emitChange(target, { redraw: false });
4736
4865
  }
4866
+ /** 下次单击落点岩性:门限编辑 landingLithType > 主线 lithType。8.31 */
4867
+ _getLandingLithType(target, seg) {
4868
+ const cfg = target && target.line && target.line.doubleConfig || {};
4869
+ return cfg.landingLithType || this._landingLithByParam[String(target.paramId)] || seg && seg.lithType || cfg.lithType || "mudstone";
4870
+ }
4871
+ /** 门限编辑确定后设置下次落点岩性(不改主/镜像配置)。8.31 */
4872
+ setLandingLithType(paramId, lithType) {
4873
+ const found = this._findLineByParamId(paramId);
4874
+ if (!found) return;
4875
+ const next = lithType === "sandstone" ? "sandstone" : "mudstone";
4876
+ this._landingLithByParam[String(paramId)] = next;
4877
+ if (found.line) {
4878
+ found.line.doubleConfig = {
4879
+ ...found.line.doubleConfig || {},
4880
+ landingLithType: next
4881
+ };
4882
+ }
4883
+ }
4884
+ /**
4885
+ * 按目标岩性写主线或镜像:seg.lithType 是主线岩性,另一侧是镜像。
4886
+ * 对齐 geosteering _addGammaKnotForLith。8.31
4887
+ */
4888
+ _buildKnotForLith(chart, target, seg, depth, clickX, targetLith) {
4889
+ const existing = (seg.knots || []).find((k) => Math.abs(k.depth - depth) < 0.05);
4890
+ const knot = existing ? { ...existing, depth } : { depth };
4891
+ const role = seg.lithType === targetLith ? "main" : "mirror";
4892
+ this._applyPointerValue(chart, target, knot, depth, clickX, role);
4893
+ this._fillKnotOtherSide(chart, target, seg, knot);
4894
+ return knot;
4895
+ }
4896
+ /** 只填了一侧时,按偏移补另一侧。8.31 */
4897
+ _fillKnotOtherSide(chart, target, seg, knot) {
4898
+ const hasMain = knot.value != null && Number.isFinite(Number(knot.value));
4899
+ const hasMirror = knot.mirrorValue != null && Number.isFinite(Number(knot.mirrorValue));
4900
+ if (hasMain && !hasMirror) {
4901
+ knot.mirrorValue = this._calcMirrorValue(Number(knot.value), seg, chart, target.paramId, knot.depth);
4902
+ if (knot.plotValue != null && Number.isFinite(Number(knot.plotValue))) {
4903
+ knot.plotMirrorValue = this._calcMirrorValue(
4904
+ Number(knot.plotValue),
4905
+ seg,
4906
+ chart,
4907
+ target.paramId,
4908
+ knot.depth
4909
+ );
4910
+ }
4911
+ return;
4912
+ }
4913
+ if (hasMirror && !hasMain) {
4914
+ knot.value = this._calcMainFromMirror(Number(knot.mirrorValue), seg, chart, target.paramId, knot.depth);
4915
+ if (knot.plotMirrorValue != null && Number.isFinite(Number(knot.plotMirrorValue))) {
4916
+ knot.plotValue = this._calcMainFromMirror(
4917
+ Number(knot.plotMirrorValue),
4918
+ seg,
4919
+ chart,
4920
+ target.paramId,
4921
+ knot.depth
4922
+ );
4923
+ }
4924
+ }
4925
+ }
4737
4926
  /** 取未关闭的最后一段;没有或已 _closed 则开新段。8.21 */
4738
4927
  _ensureActiveSegment(key) {
4739
4928
  if (!this.store[key]) this.store[key] = { segments: [] };
@@ -4811,10 +5000,12 @@ class TrendLineManager {
4811
5000
  _flushTrendLanes(prev) {
4812
5001
  const laneIds = /* @__PURE__ */ new Set();
4813
5002
  (prev || []).forEach((t) => t.laneId && laneIds.add(t.laneId));
4814
- Object.keys(this._seriesIds).forEach((id) => laneIds.add(id));
5003
+ Object.keys(this._graphicIds).forEach((id) => laneIds.add(id));
4815
5004
  this.binds.forEach((_, laneId) => {
4816
5005
  const chart = this.getChart(laneId);
4817
- if (chart && this._chartTrendSeriesIds(chart).length) laneIds.add(laneId);
5006
+ if (chart && (this._listLiveTrendGraphicIds(chart).length || this._chartTrendSeriesIds(chart).length)) {
5007
+ laneIds.add(laneId);
5008
+ }
4818
5009
  });
4819
5010
  if (!laneIds.size) {
4820
5011
  this.renderAll(true);
@@ -4947,22 +5138,40 @@ class TrendLineManager {
4947
5138
  if (startStamp != null && ev.timeStamp === startStamp) return;
4948
5139
  this._endDrag(true);
4949
5140
  };
4950
- const { offsetX, offsetY } = eventOffsetInChart(chart, nativeEvent);
4951
- const px = this._knotPixel(chart, target, knot, role);
5141
+ const { offsetX, offsetY } = eventOffsetInChartRaw(chart, nativeEvent);
5142
+ const px = this._knotDisplayPixel(chart, target, knot, role) || this._knotPixel(chart, target, knot, role);
5143
+ const dom = chart.getDom();
5144
+ const native = nativeEvent && nativeEvent.event || nativeEvent;
5145
+ let pointerId = null;
5146
+ if (dom && native && native.pointerId != null && dom.setPointerCapture) {
5147
+ try {
5148
+ dom.setPointerCapture(native.pointerId);
5149
+ pointerId = native.pointerId;
5150
+ } catch (err) {
5151
+ }
5152
+ }
4952
5153
  this.dragSession = {
4953
5154
  chart,
4954
5155
  target,
4955
5156
  knot,
4956
5157
  role,
5158
+ dom,
5159
+ pointerId,
4957
5160
  onMove,
4958
5161
  onUp,
4959
5162
  onClickEnd,
5163
+ dragOutsideFrozen: false,
4960
5164
  grabDX: px ? px[0] - offsetX : 0,
4961
5165
  grabDY: px ? px[1] - offsetY : 0
4962
5166
  };
4963
5167
  window.addEventListener("mousemove", onMove);
4964
5168
  window.addEventListener("mouseup", onUp);
4965
5169
  window.addEventListener("mousedown", onClickEnd, true);
5170
+ if (dom) {
5171
+ dom.addEventListener("pointermove", onMove);
5172
+ dom.addEventListener("pointerup", onUp);
5173
+ dom.addEventListener("pointercancel", onUp);
5174
+ }
4966
5175
  this.updateCursor(target.laneId);
4967
5176
  }
4968
5177
  _unbindDragWindow() {
@@ -4973,28 +5182,54 @@ class TrendLineManager {
4973
5182
  if (session.onClickEnd) {
4974
5183
  window.removeEventListener("mousedown", session.onClickEnd, true);
4975
5184
  }
5185
+ const dom = session.dom;
5186
+ if (dom) {
5187
+ if (session.onMove) {
5188
+ dom.removeEventListener("pointermove", session.onMove);
5189
+ dom.removeEventListener("pointerup", session.onUp);
5190
+ dom.removeEventListener("pointercancel", session.onUp);
5191
+ }
5192
+ if (session.pointerId != null && dom.releasePointerCapture) {
5193
+ try {
5194
+ dom.releasePointerCapture(session.pointerId);
5195
+ } catch (err) {
5196
+ }
5197
+ }
5198
+ }
4976
5199
  this.dragSession = null;
4977
5200
  }
4978
- /** 拖拽时点跟着鼠标走;夹在相邻点之间,不能越过前后控制点。8.21 */
5201
+ /** 拖拽:网格内跟手;出界夹到 grid 边。画面用 graphic,贴边点不消失。8.31 */
4979
5202
  _onDragMove(nativeEvent) {
4980
5203
  if (!this._alive()) return;
4981
5204
  const session = this.dragSession;
4982
5205
  if (!session) return;
4983
5206
  const { chart, target, knot, role } = session;
4984
- const pos = eventOffsetInChart(chart, nativeEvent);
4985
- const offsetX = pos.offsetX + (session.grabDX || 0);
4986
- const offsetY = pos.offsetY + (session.grabDY || 0);
5207
+ const axis = this._curveAxisOf(chart, target);
5208
+ const raw = eventOffsetInChartRaw(chart, nativeEvent);
5209
+ let offsetX = raw.offsetX + (session.grabDX || 0);
5210
+ let offsetY = raw.offsetY + (session.grabDY || 0);
5211
+ if (isPointerInGrid(chart, offsetX, offsetY, axis.yAxisIndex)) {
5212
+ session.dragOutsideFrozen = false;
5213
+ } else {
5214
+ if (session.dragOutsideFrozen) {
5215
+ this.renderLane(target.laneId);
5216
+ return;
5217
+ }
5218
+ const edge = clampPointerToGrid(chart, offsetX, offsetY, axis.yAxisIndex);
5219
+ offsetX = edge.offsetX;
5220
+ offsetY = edge.offsetY;
5221
+ session.dragOutsideFrozen = true;
5222
+ }
4987
5223
  const data = this._pixelToDragTrend(chart, target, offsetX, offsetY);
4988
- if (!data) return;
5224
+ if (!data || data.value == null) return;
4989
5225
  const range = this._drawValueRange(target, chart, data.depth);
4990
5226
  let depth = snapDepthToEdge(data.depth, range.depthMin, range.depthMax, DEPTH_EDGE_SNAP);
4991
- if (data.value == null) return;
4992
5227
  const clickX = Math.max(range.valueMin, Math.min(range.valueMax, data.value));
4993
5228
  const all = this._allKnots(target.key);
4994
5229
  const idx = all.indexOf(knot);
4995
5230
  if (idx > 0) depth = Math.max(depth, all[idx - 1].depth);
4996
5231
  if (idx >= 0 && idx < all.length - 1) depth = Math.min(depth, all[idx + 1].depth);
4997
- knot.depth = parseFloat(depth.toFixed(3));
5232
+ knot.depth = depth;
4998
5233
  this._applyPointerValue(chart, target, knot, knot.depth, clickX, role);
4999
5234
  this.renderLane(target.laneId);
5000
5235
  }
@@ -5022,6 +5257,20 @@ class TrendLineManager {
5022
5257
  this.host.setInsideDataZoomPanEnabled(true);
5023
5258
  }
5024
5259
  this._ignoreClickUntil = Date.now() + 300;
5260
+ const knot = session.knot;
5261
+ if (knot) {
5262
+ if (Number.isFinite(Number(knot.depth))) knot.depth = parseFloat(Number(knot.depth).toFixed(3));
5263
+ if (Number.isFinite(Number(knot.value))) knot.value = parseFloat(Number(knot.value).toFixed(3));
5264
+ if (knot.mirrorValue != null && Number.isFinite(Number(knot.mirrorValue))) {
5265
+ knot.mirrorValue = parseFloat(Number(knot.mirrorValue).toFixed(3));
5266
+ }
5267
+ if (knot.plotValue != null && Number.isFinite(Number(knot.plotValue))) {
5268
+ knot.plotValue = parseFloat(Number(knot.plotValue).toFixed(3));
5269
+ }
5270
+ if (knot.plotMirrorValue != null && Number.isFinite(Number(knot.plotMirrorValue))) {
5271
+ knot.plotMirrorValue = parseFloat(Number(knot.plotMirrorValue).toFixed(3));
5272
+ }
5273
+ }
5025
5274
  this.updateCursor(session.target.laneId);
5026
5275
  this.renderLane(session.target.laneId, true);
5027
5276
  this._syncCachedOption(session.target.laneId);
@@ -5058,13 +5307,31 @@ class TrendLineManager {
5058
5307
  this.scheduleRender();
5059
5308
  }
5060
5309
  }
5061
- /** 手动填写不画镜像;模型计算或回显数据里已有 mirrorValue 则画第二条线。8.22 */
5310
+ /** 模板里是否有 isDraw,表示处于趋势线编辑态。8.31 */
5311
+ _isTrendEditing() {
5312
+ if (!this.host) return false;
5313
+ const lanes = this.host.currentTemplate && this.host.currentTemplate.lanes || [];
5314
+ for (let i = 0; i < lanes.length; i++) {
5315
+ const lines = lanes[i] && lanes[i].lines || [];
5316
+ for (let j = 0; j < lines.length; j++) {
5317
+ if (isLineDrawable(lines[j])) return true;
5318
+ }
5319
+ }
5320
+ return false;
5321
+ }
5322
+ /**
5323
+ * 是否画镜像(砂岩)线。
5324
+ * 未编辑:严格按回显,有 mirrorValue 就画双线(不被残留的 calcType=hand 挡住)。
5325
+ * 编辑中:手动填写只画主线;模型计算画双线。8.31
5326
+ */
5062
5327
  _canMirror(line, segments) {
5063
- if (isHandCalc(line)) return false;
5064
- if (isMoxingCalc(line)) return true;
5065
- return (segments || []).some(
5328
+ const hasMirrorData = (segments || []).some(
5066
5329
  (seg) => (seg.knots || []).some((k) => k.mirrorValue != null && Number.isFinite(Number(k.mirrorValue)))
5067
5330
  );
5331
+ if (!this._isTrendEditing()) return hasMirrorData;
5332
+ if (isHandCalc(line)) return false;
5333
+ if (isMoxingCalc(line)) return true;
5334
+ return hasMirrorData;
5068
5335
  }
5069
5336
  /** 8137 / 双线回显用伽马红线样式,与 geosteering 只读叠加层一致。8.22 */
5070
5337
  _useGammaStyle(line, segments) {
@@ -5099,6 +5366,10 @@ class TrendLineManager {
5099
5366
  if (x == null || !knot) return null;
5100
5367
  return this._trendToPixel(chart, target, x, knot.depth);
5101
5368
  }
5369
+ /** 命中检测与圆点显示一致:贴边内收后的像素。8.31 */
5370
+ _knotHitPixel(chart, target, knot, role = "main") {
5371
+ return this._knotDisplayPixel(chart, target, knot, role);
5372
+ }
5102
5373
  /** 对数道:取该深度下当前曲线的 lg,和提示框同一套。8.22对数轴 */
5103
5374
  _logCurveXAtDepth(chart, target, depth) {
5104
5375
  const lane = this._laneById(target.laneId);
@@ -5216,6 +5487,17 @@ class TrendLineManager {
5216
5487
  }
5217
5488
  return parseFloat(Number(mirror).toFixed(3));
5218
5489
  }
5490
+ /** 由镜像值反算主线值(门限落在镜像线时补主线)。8.31 */
5491
+ _calcMainFromMirror(mirrorValue, seg, chart, paramId, depth) {
5492
+ const offset = Number(seg && seg.mirrorOffset) || 0;
5493
+ let main = seg && seg.mirrorSide === "right" ? mirrorValue - offset : mirrorValue + offset;
5494
+ if (chart) {
5495
+ const found = this._findLineByParamId(paramId);
5496
+ const range = found ? this._drawValueRange({ laneId: found.laneId, paramId }, chart, depth) : getAxisRange(chart, paramId, depth);
5497
+ main = Math.max(range.valueMin, Math.min(range.valueMax, main));
5498
+ }
5499
+ return parseFloat(Number(main).toFixed(3));
5500
+ }
5219
5501
  /** 泳道内是否已有镜像/砂岩第二条线,切手动填写时要确认。8.22 */
5220
5502
  hasDoubleLines(paramId) {
5221
5503
  const target = this.listDrawableTargets().find((t) => String(t.paramId) === String(paramId));
@@ -5235,6 +5517,7 @@ class TrendLineManager {
5235
5517
  found.line.calcType = "hand";
5236
5518
  delete found.line.doubleConfig;
5237
5519
  }
5520
+ delete this._landingLithByParam[String(paramId)];
5238
5521
  if (!bucket) return;
5239
5522
  bucket.segments = (bucket.segments || []).filter((seg) => seg.lithType !== "sandstone").map((seg) => {
5240
5523
  const next = { ...seg, lithType: seg.lithType || "mudstone", knots: (seg.knots || []).map((k) => {
@@ -5263,8 +5546,14 @@ class TrendLineManager {
5263
5546
  const mirrorSide = form && form.mirrorSide || "left";
5264
5547
  if (found.line) {
5265
5548
  found.line.calcType = "moxing";
5266
- found.line.doubleConfig = { lithType, mirrorSide, mirrorOffset: safeOffset };
5549
+ found.line.doubleConfig = {
5550
+ lithType,
5551
+ mirrorSide,
5552
+ mirrorOffset: safeOffset,
5553
+ landingLithType: lithType
5554
+ };
5267
5555
  }
5556
+ this._landingLithByParam[String(paramId)] = lithType;
5268
5557
  const chart = this.getChart(found.laneId);
5269
5558
  const segs = this.store[key].segments;
5270
5559
  let hasKnots = false;
@@ -5308,19 +5597,23 @@ class TrendLineManager {
5308
5597
  nextValue = parseFloat(Math.max(range.valueMin, Math.min(range.valueMax, value)).toFixed(3));
5309
5598
  }
5310
5599
  const rest = (seg.knots || []).filter((k) => Math.abs(k.depth - nextDepth) >= 0.05);
5311
- const knot = {
5312
- depth: nextDepth,
5313
- value: nextValue,
5314
- mirrorValue: this._calcMirrorValue(nextValue, seg, chart, found.paramId, nextDepth)
5600
+ const target = {
5601
+ key,
5602
+ laneId: found.laneId,
5603
+ paramId: found.paramId,
5604
+ line: found.line,
5605
+ segments: this.store[key] && this.store[key].segments || []
5315
5606
  };
5316
- if (plotValue != null && Number.isFinite(Number(plotValue))) {
5317
- knot.plotValue = Number(plotValue);
5318
- knot.plotMirrorValue = this._calcMirrorValue(Number(plotValue), seg, chart, found.paramId, nextDepth);
5607
+ const landing = this._getLandingLithType(target, seg);
5608
+ const clickX = plotValue != null && Number.isFinite(Number(plotValue)) ? Number(plotValue) : nextValue;
5609
+ const knot = this._buildKnotForLith(chart, target, seg, nextDepth, clickX, landing);
5610
+ if (knot.value == null && Number.isFinite(nextValue) && landing === seg.lithType) {
5611
+ knot.value = nextValue;
5319
5612
  }
5320
5613
  seg.knots = [...rest, knot].sort((a, b) => a.depth - b.depth);
5321
5614
  this.renderLane(found.laneId);
5322
- const target = this.listDrawableTargets().find((t) => t.key === key);
5323
- if (target) this._emitChange(target, { redraw: false });
5615
+ const emitTarget = this.listDrawableTargets().find((t) => t.key === key);
5616
+ if (emitTarget) this._emitChange(emitTarget, { redraw: false });
5324
5617
  }
5325
5618
  }
5326
5619
  const _sfc_main$6 = {
@@ -5420,6 +5713,11 @@ const _sfc_main$6 = {
5420
5713
  isGeomechanical: {
5421
5714
  type: Boolean,
5422
5715
  default: false
5716
+ },
5717
+ // 与 line-chart-container 一致。8.26
5718
+ canClickSelectLane: {
5719
+ type: Boolean,
5720
+ default: false
5423
5721
  }
5424
5722
  },
5425
5723
  data() {
@@ -5900,12 +6198,24 @@ const _sfc_main$6 = {
5900
6198
  isLaneTrendDraw(lane) {
5901
6199
  return !!(lane && (lane.lines || []).some((line) => isLineDrawable(line)));
5902
6200
  },
5903
- // 获取泳道头部样式:地应力已选中的道都画红框。8.25
6201
+ // 获取泳道头部样式:仅地应力已选中的道画红框;非地应力无选中。8.26
5904
6202
  getLaneHeaderStyle(lane) {
5905
- const base = this.headerStyle;
6203
+ var _a, _b;
6204
+ const base = { ...this.headerStyle };
6205
+ if (this.isKdCurveV2) {
6206
+ const gap = Number((_a = this.currentHeaderStyle) == null ? void 0 : _a.itemGap) || this.itemGap || 4;
6207
+ const hp = Number((_b = this.currentHeaderStyle) == null ? void 0 : _b.headerPadding) || 4;
6208
+ base.boxSizing = "border-box";
6209
+ base.padding = `${hp}px ${gap}px`;
6210
+ }
5906
6211
  const ids = this.activeLaneIds || [];
5907
- const isActive = this.isGeomechanical ? !!(lane && ids.some((id) => id === lane.laneId)) : this.isLaneTrendDraw(lane);
5908
- if (!isActive) return base;
6212
+ const isActive = this.isGeomechanical && !!(lane && ids.some((id) => id === lane.laneId));
6213
+ if (!isActive) {
6214
+ if (this.isKdCurveV2) {
6215
+ base.border = "1px solid transparent";
6216
+ }
6217
+ return base;
6218
+ }
5909
6219
  return {
5910
6220
  ...base,
5911
6221
  boxSizing: "border-box",
@@ -6928,7 +7238,7 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
6928
7238
  }, 8, ["modelValue", "onClose"])
6929
7239
  ], 544);
6930
7240
  }
6931
- const KdLaneContainerComponent = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$6], ["__scopeId", "data-v-814fbe51"]]);
7241
+ const KdLaneContainerComponent = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$6], ["__scopeId", "data-v-953e7fe1"]]);
6932
7242
  const SLIDER_GROUP_ID = "depthSliderGroup";
6933
7243
  function pad2(n) {
6934
7244
  return n < 10 ? "0" + n : "" + n;
@@ -7115,13 +7425,14 @@ const _sfc_main$5 = {
7115
7425
  let processedData = newVal && newVal.data ? Array.isArray(newVal.data) ? newVal.data : [newVal.data] : [];
7116
7426
  if (this.formCache.axisType == "time") {
7117
7427
  const axisKey = ((_c = (_b = (_a = this.getCurrentModeConfig()) == null ? void 0 : _a.datas) == null ? void 0 : _b[0]) == null ? void 0 : _c.xCode) || "timestamp";
7118
- const firstT = processedData[0] && processedData[0][axisKey];
7119
- if (!(typeof firstT === "number" && firstT > 1e11)) {
7120
- processedData = processedData.map((item) => ({
7428
+ processedData = processedData.map((item) => {
7429
+ const axisValue = this.toMillisecondTimestamp(item[axisKey] || item.timestamp);
7430
+ return {
7121
7431
  ...item,
7122
- [axisKey]: this.toMillisecondTimestamp(item[axisKey] || item.timestamp)
7123
- }));
7124
- }
7432
+ [axisKey]: axisValue,
7433
+ time: axisValue
7434
+ };
7435
+ });
7125
7436
  this.cachedCurveData = markRaw(processedData);
7126
7437
  } else {
7127
7438
  const axisKey = ((_f = (_e = (_d = this.getCurrentModeConfig()) == null ? void 0 : _d.datas) == null ? void 0 : _e[0]) == null ? void 0 : _f.xCode) || "depth";
@@ -7184,10 +7495,14 @@ const _sfc_main$5 = {
7184
7495
  const direction = newVal.direction || "bottom";
7185
7496
  if (this.formCache.axisType == "time") {
7186
7497
  const axisKey = ((_l = (_k = (_j = this.getCurrentModeConfig()) == null ? void 0 : _j.datas) == null ? void 0 : _k[0]) == null ? void 0 : _l.xCode) || "timestamp";
7187
- data = data.map((item) => ({
7188
- ...item,
7189
- [axisKey]: this.toMillisecondTimestamp(item[axisKey] || item.timestamp)
7190
- }));
7498
+ data = data.map((item) => {
7499
+ const axisValue = this.toMillisecondTimestamp(item[axisKey] || item.timestamp);
7500
+ return {
7501
+ ...item,
7502
+ [axisKey]: axisValue,
7503
+ time: axisValue
7504
+ };
7505
+ });
7191
7506
  this.cachedCurveData = markRaw(this.deduplicateByUniqueKey(
7192
7507
  this.cachedCurveData,
7193
7508
  data,
@@ -8252,7 +8567,7 @@ function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
8252
8567
  ], 512)
8253
8568
  ], 512);
8254
8569
  }
8255
- const DepthTimeChart = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$5], ["__scopeId", "data-v-300010d5"]]);
8570
+ const DepthTimeChart = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$5], ["__scopeId", "data-v-b3c75abf"]]);
8256
8571
  const curveExportIcon = "data:image/png;base64,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";
8257
8572
  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";
8258
8573
  const refreshIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAAJgklEQVRo3u1aaVRURxbOj/yYHzknc04E3JClwY1RxyW4EBmXMC5xdIwh4MkEkO5+rxskioqAMJIIykQEFdmCERoaxA0XUIlBwCUmIWJwy5hojGbIDBkzkahRQObcO/dW92PR0BBFWh3eOd+pevXqVd3v3Vu37q3uZ57puXqu/79LluWpTyUxraRDrVaOnTRp0rNPHbHEmNeJnK4iIEDn+FQR++8nA6Eo/Y8YpJdqJUl65akh1vTxQLhLOF/ojuFL/Nk0EwICAn7zxJBgU9PI8hwSPFyS5PVkftlMrOEjV2w84QqM6+VDYeOqeWyanzzWpqnR60cLEpLuypK3FuCm2Hm4I3k6lGROwSMGTzya4wn1x12xgUg1fORCcBXg50F6bR0RnPd4mZhWN01DDiFyqR/uTfOCb4pHEAEXuHPMBVuXltq+2jsKwkPZNHWbrG6abD6kndKoZW/iCeMEvHXUFW4fdUESFBQo91w2455non5MBXXlgyBuxXzUSPJJb2/v56ylpTfIs93anzEFbla44s9HVdAGR1R4i6Dc325+5oI//0L7jQoXLEzxAlmWatgCrERKjo1c4geX9g0HEr4ZNysEmTb1m0fub1Pqyn3NQTd8N9oHSFMlOp2un3UcBDmH+BW+UPvBIBLOGW6Uq/BGuTNyyfckLPxUroIzO0ZDwYZpsPav3ric1k5IsEZA6W/q6wyV+e64OCSwSZJ0UVaLSDSSLiYucj5c+9CVCDnfh/+UukBx+mSMWOIn1gn3V1N8qFYHO9Bm/Dy7+5/KnAWul6kgP2k6kPZr1Gqdh9UcBUcJyxf749XiISSYE9S1xmFnrN4+EgQhra6Y+o5tb4Pmd68WDcHYSF+l7/NW9H4BvSkyr/28YCReP+wEP5Y6ibLOjMJNU5CfqyX9Kx1FHscNY8kk1fWkzaVW36fI/jdnvTsTfyx1ZFJgKh3hOtW3b3gZtZJ8gc2tMyEVaenSgnY02t051IhQiiK+L6E19KGjwA+HnJDLgxkvIUcZGo3GrlNrVKvbaVXTu8dhbN6VPBl/OOQI1z5wFCXjy91DQafT1pOgqicuGqe19Vs9CX+lyJVIOcC/SxyRyFHpgEkxczkyX/REphmSpPdfGz0PiQh8zzjogLWEqvwRwGulMzEd9+FIgj+CRtIHc93qsSDtRcb96ROI0ACobYXU2Fkdaos3WzLjKI0UVOcbloRzYgpwzso89KF6oBxSx8+sRpAdQ3XBUPzXgQGg4LtiBwgJUqMlh8ECU/pS4hu+ETwza8A9px7H5DTCKEMj/J4wOuMaeIdtRO7T7eS8g4KeC9Zr8LviAfjP/fbA4PpnxmEUVejOdRBLpvtGpqBH7m0Yl1sP7rkNMCanwUQsuxGGZzXi77Y0wKvhqfSBdJu713FI0uCI0L9ATTETasH+tPEcrBotbQ8LFoahZ+5N8Mi9g4JYTguxEURsWPZdcNtC5DJvgn9wGAYG6gd1GzGO31aFv441Rf2hpshe4B9UL0iaxBqLtxT5v7q6ECbm3QEPYz2MNzaYNGaox1HZDcimOIw05pZ1F4ZsaYLpbxeCpfEeQWqi/0NchDd+u68/COztjwQwrpvCgsRY2ISLZyZXCWITiFiLxhphpHmNCY2ZiY1PPC3SlXbH0/C5CZ2X/AIC9Q+gaQ573g7zgat7+sFVInR1bz+4sqc/bkvypIhcn2AhAS2dkXIGJhrvIBMbf88aazZFM7GxSed566iwlCatj/kTFqWMg30p40TJWLbIDx8oNFOr1S788hUi9s3ufkoJB9Je5FRjjwVi2bMTykymSGusmZihAUe10VgjDtlyFybFHwNLDkSjlXeWpI8Bnr+1LGGL38QHinp4HyJH0HRxl70gdLmwH17e3RdOGgcCbwPtCiLLPm+EJaCyxsYZW2usAUfcY4qvkdu3dDpFAXbNSeMgIYMix8Wd9sCyPXBiym792BY3uLSrL35NuFzYFxhL3/Jr15PxZBztz9xQiR7KGrvPFBsFMc+1n/J6PdfeXsZriK3ma9P8IEqa/zjJ1NGW0+ExwNZ1E5lYK/SBzNUvixPc9he8frRaXlg/bWMVmyK2dveKKU5cV4Xch/tacGAJ76+Zipd29kWeV5EhL4HXuW7TQ2XN0ct8SfV94OKOPvgVgeuVBhe27zoOki1tF2yyPrRReyV9hh4ZNTgh7VucvK4SX1ueLPIyS6Q4udXTIerJXGdQ5lWwcpkPPtRJljneq63MceHBBb7c3gcZqavEeUV6RwEwuWs1bwFMhE1Uy3Vq6yiU4rEz4rya51VwImsgm2HtQ4divGetj5mJF7b1JkK9QcHpPHsMDfFH3mcexfkKr+Oz+f2b57tgRlqsF6opCOiSnIzN7uMsFf69oDcTBC4JUJE5mJPNW115ykTnih46WVt/+D03mseO5zLPZ0faUiE/62zG3hmtLV0T+Wc8v9UOv6AJvthK4JImPbBpODK5rji9ZU1RYnvrQMrwtnOZ54uLmItdeggkXLhWrt6e6A7n823hXL4dnsuzw/P5dkACwKG0oSazJC/6ILbP5/TsZUND/JpKUt1QjE/gsRVsW+dODkeu7vI0h/ct1kxp+mA4l2cLZ4nY2TxbFkDUP80eAGujZvEXreUk1JLHbG3mWlkO53cSo2dCZbY9jWfbPD6XfH8obQiwCT6y8xU2t0UL/ZuOZtIRdq4tnjGyALZAJZMU9bIMV0iMnmFaCxQDcuQuPCP9CMigs0d/zgD4WZBe08R9y9JdxVhiHGPb8Y68p8JFwf5Nj/yHCq1WO4/JlaQMhtMkxOlcG6jOtcHTRNQEvrfFKkMfKE4eBu/HTcSk6BkQHzFbgIlsprZ9G4fhKUNv0b/5XTGeLVab7w+lDgImFRio7Z4fBPnrsUby176In+fYkCA2IMocKg02yGjT1qqPeEZtAq36KPdKncfuKqf0az2YihdzfOQsPJLhwAKzkAKnBLleojyV3Ytgum+BDbQ8Nz8zv1uR4YRx4XOEo+jWzPr+ozU5nLWXHDMVK9IHkHn1gqqsXlglCJHwDIOp5DbRbjC1NdfpWXmaI25Y6UW/AWjFCdZj8ScXjus4YKWvXPfOsrmQ+zd3KEt3gJNMMEsQEPUWvCDaSlOd0BA/Ft4JmwscBFBeFjNfkno9jifHHBvOUZv++nBlYdACjAz1wTURszAhajomrJiOq8NnY9QSbwzWB4pzf+7L7zxRf0PyCw5+gdN3TiT5VJnBLp/bOrPP9Vw9V8/Vc3X79T8J1TZaWjb6HwAAAABJRU5ErkJggg==";
@@ -9528,92 +9843,27 @@ const _sfc_main$3 = {
9528
9843
  return null;
9529
9844
  }
9530
9845
  },
9531
- // notMerge 刷 option 时把当前趋势线 graphic 带回去,避免先消失再画。8.24
9846
+ // notMerge 刷 option 时把当前 graphic(含趋势线)带回去。8.31
9532
9847
  _preserveGraphic(options) {
9533
9848
  if (!options || options.graphic || !this.chart || this.chart.isDisposed()) return;
9534
9849
  try {
9535
9850
  const model = this.chart.getModel();
9536
9851
  const list = model.queryComponents({ mainType: "graphic" }) || [];
9537
9852
  if (!list.length) return;
9538
- const graphic = list.map((m) => m.option).filter((item) => {
9539
- if (!item || !(item.id || item.elements || item.type)) return false;
9540
- const id = String(item.id || "");
9541
- return id.indexOf("trend_") !== 0;
9542
- });
9853
+ const graphic = list.map((m) => m.option).filter((item) => item && (item.id || item.elements || item.type));
9543
9854
  if (graphic.length) options.graphic = graphic;
9544
9855
  } catch (e) {
9545
9856
  }
9546
9857
  },
9547
- // notMerge 时把笛卡尔趋势 series 带回去,避免先消失再画。8.25
9548
- // 只拷绘制字段,禁止展开 model.option(会带上坐标系等内部引用,图表拆不掉)。8.25
9549
- _copyTrendSeriesOption(opt, id) {
9550
- if (!opt) return null;
9551
- const ls = opt.lineStyle || {};
9552
- const is = opt.itemStyle || {};
9553
- return {
9554
- id: opt.id || id,
9555
- name: "trend",
9556
- type: "line",
9557
- data: Array.isArray(opt.data) ? opt.data.slice() : [],
9558
- xAxisIndex: opt.xAxisIndex,
9559
- yAxisIndex: opt.yAxisIndex,
9560
- clip: opt.clip,
9561
- animation: false,
9562
- silent: true,
9563
- large: false,
9564
- z: opt.z,
9565
- zlevel: 0,
9566
- symbol: opt.symbol,
9567
- symbolSize: opt.symbolSize,
9568
- showSymbol: opt.showSymbol,
9569
- hoverAnimation: false,
9570
- legendHoverLink: false,
9571
- connectNulls: false,
9572
- tooltip: { show: false },
9573
- emphasis: { disabled: true },
9574
- lineStyle: {
9575
- color: ls.color,
9576
- width: ls.width,
9577
- type: ls.type
9578
- },
9579
- itemStyle: {
9580
- color: is.color,
9581
- borderColor: is.borderColor,
9582
- borderWidth: is.borderWidth
9583
- }
9584
- };
9585
- },
9858
+ // 趋势线已改 graphic;只剥离残留 trend series,不再从图表拷回。8.31
9586
9859
  _preserveTrendSeries(options) {
9587
- if (!options || !this.chart || this.chart.isDisposed()) return;
9588
- if (options.__kdTrendSynced) return;
9589
- const incoming = Array.isArray(options.series) ? options.series : [];
9590
- const hasTrend = incoming.some((s) => {
9860
+ if (!options || !Array.isArray(options.series)) return;
9861
+ options.series = options.series.filter((s) => {
9591
9862
  if (!s) return false;
9592
9863
  const name = Array.isArray(s.name) ? s.name[0] : s.name;
9593
- if (name === "trend") return true;
9594
9864
  const id = String(s.id || "");
9595
- return id.indexOf("trend_") === 0;
9865
+ return name !== "trend" && id.indexOf("trend_") !== 0;
9596
9866
  });
9597
- if (hasTrend) return;
9598
- try {
9599
- const list = this.chart.getModel().getSeries() || [];
9600
- const trends = [];
9601
- const seen = /* @__PURE__ */ new Set();
9602
- for (let i = 0; i < list.length; i++) {
9603
- const sm = list[i];
9604
- const opt = sm && sm.option || {};
9605
- const name = Array.isArray(sm.name) ? sm.name[0] : sm.name;
9606
- const id = String(opt.id || sm.id || "");
9607
- if (name !== "trend" && id.indexOf("trend_") !== 0) continue;
9608
- if (!id || seen.has(id)) continue;
9609
- seen.add(id);
9610
- const copied = this._copyTrendSeriesOption(opt, id);
9611
- if (copied) trends.push(copied);
9612
- }
9613
- if (!trends.length) return;
9614
- options.series = incoming.concat(trends);
9615
- } catch (e) {
9616
- }
9617
9867
  },
9618
9868
  // dataZoom 写进即将下发的 option,不再二次 setOption 打断 Chrome 平移。8.24
9619
9869
  _applySavedDataZoomToOptions(options, savedState) {
@@ -9927,7 +10177,7 @@ const _hoisted_1$3 = { class: "echarts" };
9927
10177
  function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
9928
10178
  return openBlock(), createElementBlock("div", _hoisted_1$3);
9929
10179
  }
9930
- const resizeEcharts = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3], ["__scopeId", "data-v-5b44c8a6"]]);
10180
+ const resizeEcharts = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3], ["__scopeId", "data-v-4f4caae5"]]);
9931
10181
  const DRAW_POINT_MIN = 600;
9932
10182
  const DRAW_POINT_MAX = 1800;
9933
10183
  function getSeriesDrawThreshold(laneHeightPx) {
@@ -10214,6 +10464,15 @@ const _sfc_main$2 = {
10214
10464
  type: Boolean,
10215
10465
  default: false
10216
10466
  },
10467
+ /**
10468
+ * 泳道选中方式互斥开关。8.26
10469
+ * true:趋势线选中泳道 + 可绘制趋势线;不可单击/双击选中泳道
10470
+ * false:可单击/双击选中泳道;不可趋势线选中/绘制
10471
+ */
10472
+ canClickSelectLane: {
10473
+ type: Boolean,
10474
+ default: false
10475
+ },
10217
10476
  // 已保存的趋势线(geosteering trendLinePoint 数组),传入后回显 8.21
10218
10477
  lineListData: {
10219
10478
  type: Array,
@@ -10496,29 +10755,27 @@ const _sfc_main$2 = {
10496
10755
  return !!(lane && (lane.lines || []).some((line) => isLineDrawable(line)));
10497
10756
  },
10498
10757
  getLaneChartContentStyle(laneId) {
10758
+ var _a;
10499
10759
  const width = this.laneWidthMap && this.laneWidthMap[laneId];
10760
+ const gap = ((_a = this.currentHeaderStyle) == null ? void 0 : _a.itemGap) ?? this.itemGap ?? 4;
10500
10761
  const style = {};
10501
10762
  if (width && Number(width) > 0) {
10502
10763
  Object.assign(style, {
10503
10764
  width: `${width}px`,
10504
- padding: "0",
10765
+ padding: `0 ${gap}px`,
10505
10766
  height: "100%"
10506
10767
  });
10507
10768
  } else {
10508
10769
  Object.assign(style, {
10509
10770
  width: "100%",
10510
10771
  height: "100%",
10511
- padding: "0",
10772
+ padding: `0 ${gap}px`,
10512
10773
  flex: "1"
10513
10774
  });
10514
10775
  }
10515
- if (this.isGeomechanical) {
10516
- style.boxSizing = "border-box";
10517
- style.border = this.isLaneSelected(laneId) ? "1px solid #F86C59" : "1px solid transparent";
10518
- } else if (this.isLaneTrendDrawById(laneId)) {
10519
- style.boxSizing = "border-box";
10520
- style.border = "1px solid #F86C59";
10521
- }
10776
+ style.boxSizing = "border-box";
10777
+ const showRedBorder = this.isGeomechanical && this.isLaneSelected(laneId);
10778
+ style.border = showRedBorder ? "1px solid #F86C59" : "1px solid transparent";
10522
10779
  return style;
10523
10780
  },
10524
10781
  // 按引用摘掉 click/dblclick,避免 zr.off(类型) 误拆趋势线 dblclick。8.25
@@ -10587,6 +10844,10 @@ const _sfc_main$2 = {
10587
10844
  }
10588
10845
  this.scheduleConnectAllCharts();
10589
10846
  },
10847
+ // autoresize 完成后按新宽高重算趋势 graphic,避免回显偏左、点选才往右跳。8.31
10848
+ handleLaneChartSizeChange(laneId) {
10849
+ if (this.trendLineManager) this.trendLineManager.onChartResized(laneId);
10850
+ },
10590
10851
  // 地应力:拖点时彻底停 inside 平移,松手后恢复。8.22
10591
10852
  setInsideDataZoomPanEnabled(enabled) {
10592
10853
  this._chartPanLocked = !enabled;
@@ -10606,6 +10867,7 @@ const _sfc_main$2 = {
10606
10867
  if (opt.end != null) next.end = opt.end;
10607
10868
  if (opt.startValue != null) next.startValue = opt.startValue;
10608
10869
  if (opt.endValue != null) next.endValue = opt.endValue;
10870
+ if (opt.yAxisIndex != null) next.yAxisIndex = opt.yAxisIndex;
10609
10871
  }
10610
10872
  const skip = this.trendLineManager && this.trendLineManager.dataZoomSeriesIndex(chart);
10611
10873
  if (skip && skip.length) next.seriesIndex = skip;
@@ -10614,6 +10876,16 @@ const _sfc_main$2 = {
10614
10876
  chart.setOption({ dataZoom: [next] }, { silent: true, lazyUpdate: false });
10615
10877
  });
10616
10878
  },
10879
+ // connect / 缩放后补回趋势线 dataZoom 排除列表,并重画可视边界。8.26
10880
+ ensureTrendDataZoomOnAllCharts(exceptChart) {
10881
+ if (!this.isGeomechanical || !this.trendLineManager) return;
10882
+ this.getConnectedCharts().forEach((chart) => {
10883
+ if (!chart || chart === exceptChart) return;
10884
+ this.trendLineManager.ensureDataZoomSkipsTrend(chart);
10885
+ const laneId = this.findLaneIdByChart(chart);
10886
+ if (laneId != null) this.trendLineManager._scheduleZoomTrendPatch(laneId);
10887
+ });
10888
+ },
10617
10889
  getConnectedCharts() {
10618
10890
  return Object.values(this.chartRefMap).map((item) => item == null ? void 0 : item.chart).filter((chart) => chart && !chart.isDisposed());
10619
10891
  },
@@ -10641,6 +10913,7 @@ const _sfc_main$2 = {
10641
10913
  this.trendLineManager.setTrendLineList(this.lineListData || [], overwrite);
10642
10914
  },
10643
10915
  breakTrendSegment() {
10916
+ if (!this.isTrendLaneSelectMode()) return false;
10644
10917
  return this.trendLineManager ? this.trendLineManager.breakActiveSegment() : false;
10645
10918
  },
10646
10919
  resetTrendLine(paramId) {
@@ -10659,7 +10932,15 @@ const _sfc_main$2 = {
10659
10932
  isLaneSelected(laneId) {
10660
10933
  return laneId != null && (this.activeLaneIds || []).some((id) => id === laneId);
10661
10934
  },
10935
+ // true:趋势线选中泳道;false:单击/双击选中泳道。8.26
10936
+ isTrendLaneSelectMode() {
10937
+ return !!this.canClickSelectLane;
10938
+ },
10939
+ isManualLaneSelectMode() {
10940
+ return !this.canClickSelectLane;
10941
+ },
10662
10942
  addLaneSelection(laneId) {
10943
+ if (!this.isManualLaneSelectMode()) return false;
10663
10944
  if (laneId == null) return false;
10664
10945
  this.activeLaneId = laneId;
10665
10946
  if (this.isLaneSelected(laneId)) return false;
@@ -10692,14 +10973,18 @@ const _sfc_main$2 = {
10692
10973
  this.activeLaneIds = [];
10693
10974
  this.activeLaneId = null;
10694
10975
  if (!ids.length) return;
10695
- this.updateLanesChartOption().then(() => {
10976
+ if (this.trendLineManager) {
10977
+ ids.forEach((id) => this.trendLineManager.updateCursor(id));
10978
+ this.trendLineManager.scheduleRender();
10979
+ }
10980
+ this.updateLanesChartOption(void 0, ids).then(() => {
10696
10981
  if (this._isUnmounted) return;
10697
10982
  ids.forEach((id) => this.showSelectedPointScatter(id));
10698
10983
  });
10699
10984
  },
10700
- // 切趋势线:只保留当前曲线所在道;单击其它道仍可再选中。8.25
10985
+ // 切趋势线:只保留当前曲线所在道。仅 canClickSelectLane=true。8.26
10701
10986
  selectLaneByParamId(paramId) {
10702
- if (!this.isGeomechanical) return;
10987
+ if (!this.isGeomechanical || !this.isTrendLaneSelectMode()) return;
10703
10988
  if (paramId == null || paramId === "") {
10704
10989
  this.clearActiveLane();
10705
10990
  return;
@@ -10717,6 +11002,7 @@ const _sfc_main$2 = {
10717
11002
  const prevIds = (this.activeLaneIds || []).slice();
10718
11003
  if (prevIds.length === 1 && prevIds[0] === laneId) {
10719
11004
  this.activeLaneId = laneId;
11005
+ if (this.showTooltip) this.toggleTooltip(true);
10720
11006
  return;
10721
11007
  }
10722
11008
  if (this.selectedPoints.length > 0 && this.selectedLaneId && this.selectedLaneId !== laneId) {
@@ -10729,12 +11015,43 @@ const _sfc_main$2 = {
10729
11015
  }
10730
11016
  this.activeLaneIds = [laneId];
10731
11017
  this.activeLaneId = laneId;
10732
- this.updateLanesChartOption().then(() => {
11018
+ if (this.showTooltip) this.toggleTooltip(true);
11019
+ if (this.trendLineManager) {
11020
+ prevIds.forEach((id) => this.trendLineManager.updateCursor(id));
11021
+ this.trendLineManager.updateCursor(laneId);
11022
+ this.trendLineManager.scheduleRender();
11023
+ }
11024
+ const refreshIds = Array.from(/* @__PURE__ */ new Set([...prevIds, laneId]));
11025
+ this.updateLanesChartOption(void 0, refreshIds).then(() => {
10733
11026
  if (this._isUnmounted) return;
10734
- prevIds.forEach((id) => this.showSelectedPointScatter(id));
10735
- this.showSelectedPointScatter(laneId);
11027
+ refreshIds.forEach((id) => this.showSelectedPointScatter(id));
10736
11028
  });
10737
11029
  },
11030
+ // 趋势线编辑:选中泳道跟着当前 isDraw / 正在编辑的曲线走(如表头拖到新道)。8.26
11031
+ syncSelectedLaneToTrendEdit() {
11032
+ if (!this.isGeomechanical || !this.isTrendLaneSelectMode()) return;
11033
+ let paramId = null;
11034
+ if (this.trendLineManager) {
11035
+ const active = this.trendLineManager.getActiveTarget();
11036
+ if (active && active.editable) paramId = active.paramId;
11037
+ if (paramId == null) {
11038
+ const editable = this.trendLineManager.listDrawableTargets().find((t) => t.editable);
11039
+ if (editable) paramId = editable.paramId;
11040
+ }
11041
+ }
11042
+ if (paramId == null) {
11043
+ const lanes = this.currentTemplate && this.currentTemplate.lanes || [];
11044
+ for (let i = 0; i < lanes.length; i++) {
11045
+ const line = (lanes[i].lines || []).find((l) => isLineDrawable(l));
11046
+ if (line) {
11047
+ paramId = line.paramId;
11048
+ break;
11049
+ }
11050
+ }
11051
+ }
11052
+ if (paramId == null || paramId === "") return;
11053
+ this.selectLaneByParamId(paramId);
11054
+ },
10738
11055
  // 根据 paramId 判断曲线是否可见(isUsed === '1')
10739
11056
  isLineVisibleByParamId(paramId) {
10740
11057
  const lanes = this.currentTemplate && this.currentTemplate.lanes || [];
@@ -11315,11 +11632,6 @@ const _sfc_main$2 = {
11315
11632
  this.attachChartConnect();
11316
11633
  this.hideLaneTooltipsForPan();
11317
11634
  },
11318
- endChartPan() {
11319
- if (!this._isPanning) return;
11320
- this._isPanning = false;
11321
- this.restorePointerAfterInteract();
11322
- },
11323
11635
  startChartZoom() {
11324
11636
  if (!this.isGeomechanical) return;
11325
11637
  this.attachChartConnect();
@@ -11334,7 +11646,23 @@ const _sfc_main$2 = {
11334
11646
  this._zoomIdleTimer = 0;
11335
11647
  if (!this._isZooming) return;
11336
11648
  this._isZooming = false;
11337
- if (!this._isPanning && this.trendLineManager) this.trendLineManager.endFollowView();
11649
+ if (this.trendLineManager) {
11650
+ this.getConnectedCharts().forEach((chart) => {
11651
+ this.trendLineManager.ensureDataZoomSkipsTrend(chart);
11652
+ });
11653
+ if (!this._isPanning) this.trendLineManager.endFollowView();
11654
+ }
11655
+ this.restorePointerAfterInteract();
11656
+ },
11657
+ endChartPan() {
11658
+ if (!this._isPanning) return;
11659
+ this._isPanning = false;
11660
+ if (this.trendLineManager) {
11661
+ this.getConnectedCharts().forEach((chart) => {
11662
+ this.trendLineManager.ensureDataZoomSkipsTrend(chart);
11663
+ });
11664
+ this.trendLineManager.endFollowView();
11665
+ }
11338
11666
  this.restorePointerAfterInteract();
11339
11667
  },
11340
11668
  hideAllLaneTooltips(event) {
@@ -11400,18 +11728,24 @@ const _sfc_main$2 = {
11400
11728
  const onDown = (e) => {
11401
11729
  const native = e.event || e;
11402
11730
  if (native.button != null && native.button !== 0) return;
11731
+ if (this.isTrendLaneSelectMode() && this.trendLineManager && this.trendLineManager.shouldBlockChartPan(chart, e)) {
11732
+ return;
11733
+ }
11403
11734
  this.startChartPan();
11404
11735
  };
11405
11736
  const onMove = (e) => {
11406
- var _a, _b;
11737
+ var _a, _b, _c;
11407
11738
  const native = e.event || e;
11408
- if (this.isGeomechanical && native.buttons === 1 && !this._isPanning) {
11739
+ if (!((_a = this.trendLineManager) == null ? void 0 : _a.isDraggingKnot()) && this.isGeomechanical && native.buttons === 1 && !this._isPanning) {
11409
11740
  this.startChartPan();
11410
11741
  }
11742
+ if (this._isPanning && this.trendLineManager) {
11743
+ this.trendLineManager.tickPanFollow();
11744
+ }
11411
11745
  this.schedulePointerSync(
11412
11746
  chart,
11413
- e.offsetX ?? ((_a = e.event) == null ? void 0 : _a.offsetX),
11414
- e.offsetY ?? ((_b = e.event) == null ? void 0 : _b.offsetY),
11747
+ e.offsetX ?? ((_b = e.event) == null ? void 0 : _b.offsetX),
11748
+ e.offsetY ?? ((_c = e.event) == null ? void 0 : _c.offsetY),
11415
11749
  native.clientY
11416
11750
  );
11417
11751
  };
@@ -11459,6 +11793,7 @@ const _sfc_main$2 = {
11459
11793
  await this.updateLanesChartOption();
11460
11794
  if (this.trendLineManager && migratedLanes && migratedLanes.size) {
11461
11795
  migratedLanes.forEach((laneId) => this.trendLineManager._flushLane(laneId));
11796
+ this.syncSelectedLaneToTrendEdit();
11462
11797
  }
11463
11798
  },
11464
11799
  // 线段变化
@@ -11640,12 +11975,9 @@ const _sfc_main$2 = {
11640
11975
  ref.mergeOptions(option, true, false, true);
11641
11976
  },
11642
11977
  // 判断指定泳道是否应该显示tooltip内容
11643
- // 地应力:无选中时所有泳道显示;有选中时已选中的多道都显示。8.25
11978
+ // 地应力悬浮框各道都显示;不因选中趋势编辑泳道而只留一道。8.31
11644
11979
  shouldShowTooltipContent(laneId) {
11645
11980
  if (!this.showTooltip) return false;
11646
- if (this.isGeomechanical && (this.activeLaneIds || []).length && !this.isLaneSelected(laneId)) {
11647
- return false;
11648
- }
11649
11981
  return true;
11650
11982
  },
11651
11983
  // 控制tooltip显示隐藏
@@ -11721,9 +12053,10 @@ const _sfc_main$2 = {
11721
12053
  const clientWidth = this.getDepthTimeLabelWidth(lane);
11722
12054
  const richWidth = Math.max(clientWidth - 6, 24);
11723
12055
  return {
11724
- show: this.shouldShowDepthAxisLabel(group, axisKey),
12056
+ show: true,
11725
12057
  width: clientWidth,
11726
- hideOverlap: true,
12058
+ hideOverlap: dataGroups.length <= 1,
12059
+ showMinLabel: true,
11727
12060
  height: 14,
11728
12061
  verticalAlign: "middle",
11729
12062
  color: getCssVariable("--default-text-color"),
@@ -11891,10 +12224,25 @@ const _sfc_main$2 = {
11891
12224
  let unified = Math.ceil(range / Math.min(12, intervalCount));
11892
12225
  return Math.max(minStep, Math.ceil(unified / minStep) * minStep);
11893
12226
  },
12227
+ /**
12228
+ * 地应力 dataZoom 放大下限:可视点数不得小于 minWindowSize。
12229
+ * 换算成全量数据范围的百分比给 minSpan。8.26
12230
+ */
12231
+ getDataZoomMinSpanPercent() {
12232
+ if (!this.isGeomechanical) return null;
12233
+ const minSize = Number(this.minWindowSize);
12234
+ if (!(minSize > 0)) return null;
12235
+ const drawnLen = this.visibleData && this.visibleData.length || Math.min(
12236
+ Number(this.windowSize) || 0,
12237
+ this.realTimeData && this.realTimeData.length || 0
12238
+ );
12239
+ if (!(drawnLen > 0)) return null;
12240
+ return Math.min(100, Math.max(0, minSize / drawnLen * 100));
12241
+ },
11894
12242
  buildInsideDataZoom(moveOnMouseMove, filterMode) {
11895
12243
  const pan = moveOnMouseMove === void 0 ? this.isGeomechanical && !this._chartPanLocked : !!moveOnMouseMove;
11896
12244
  const mode = filterMode == null ? this.isGeomechanical ? "weakFilter" : "none" : filterMode;
11897
- return {
12245
+ const cfg = {
11898
12246
  type: "inside",
11899
12247
  orient: "vertical",
11900
12248
  // 视窗外的点不画;x 轴仍用表头 min/max,不会跟着被滤掉的点跑偏。8.25
@@ -11906,6 +12254,9 @@ const _sfc_main$2 = {
11906
12254
  throttle: this.isGeomechanical ? 16 : 100
11907
12255
  // 地应力跟手;过大 throttle 会拖影。8.25
11908
12256
  };
12257
+ const minSpan = this.getDataZoomMinSpanPercent();
12258
+ if (minSpan != null) cfg.minSpan = minSpan;
12259
+ return cfg;
11909
12260
  },
11910
12261
  splitPlotDataByGaps(data) {
11911
12262
  if (!data || !data.length) return [data || []];
@@ -12466,8 +12817,8 @@ const _sfc_main$2 = {
12466
12817
  const existingKeys = new Set(
12467
12818
  this.realTimeData.map((item) => item[axisKey])
12468
12819
  );
12469
- const newItems = newData.filter(
12470
- (item) => !existingKeys.has(item[axisKey])
12820
+ const newItems = newData.filter((item) => !existingKeys.has(item[axisKey])).map(
12821
+ (item) => axisType === "time" ? this.normalizeTimeModeItem(item, axisKey) : item
12471
12822
  );
12472
12823
  const merged = [...this.realTimeData, ...newItems];
12473
12824
  if (axisType === "depth") {
@@ -12713,8 +13064,25 @@ const _sfc_main$2 = {
12713
13064
  return timestamp;
12714
13065
  }
12715
13066
  },
12716
- // 更新泳道图表选项
12717
- async updateLanesChartOption(transferData) {
13067
+ // 时间轴数据统一毫秒 timestamp,并补 time 字段(与 depth-time-chart / 桌面版一致)
13068
+ normalizeTimeModeItem(item, axisKey) {
13069
+ if (!item || typeof item !== "object") return item;
13070
+ const key = axisKey || this.getAxisDataKey() || "timestamp";
13071
+ const raw = item[key] != null ? item[key] : item.timestamp != null ? item.timestamp : item.time;
13072
+ const axisValue = this.toMillisecondTimestamp(raw);
13073
+ return {
13074
+ ...item,
13075
+ [key]: axisValue,
13076
+ time: axisValue
13077
+ };
13078
+ },
13079
+ normalizeTimeModeData(data, axisKey) {
13080
+ if (!Array.isArray(data)) return [];
13081
+ const key = axisKey || this.getAxisDataKey() || "timestamp";
13082
+ return data.map((item) => this.normalizeTimeModeItem(item, key));
13083
+ },
13084
+ // 更新泳道图表选项。onlyLaneIds 有值时只重建这些道(选中/取消选中用,避免大数据全量重刷)。8.31
13085
+ async updateLanesChartOption(transferData, onlyLaneIds) {
12718
13086
  if (this._isUnmounted) return;
12719
13087
  if (this.isUpdatingChart) {
12720
13088
  this.pendingChartUpdate = true;
@@ -12727,6 +13095,13 @@ const _sfc_main$2 = {
12727
13095
  this.isUpdatingChart = false;
12728
13096
  return;
12729
13097
  }
13098
+ const laneFilter = onlyLaneIds == null || onlyLaneIds === "" ? null : new Set(
13099
+ (Array.isArray(onlyLaneIds) ? onlyLaneIds : [onlyLaneIds]).filter((id) => id != null && id !== "").map((id) => String(id))
13100
+ );
13101
+ if (laneFilter && !laneFilter.size) {
13102
+ this.isUpdatingChart = false;
13103
+ return;
13104
+ }
12730
13105
  const axisKey = this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType] || (this.formCache.axisType === "time" ? "time" : "depth");
12731
13106
  const paramNameMap = {};
12732
13107
  const paramCodeMap = /* @__PURE__ */ new Map();
@@ -12742,9 +13117,10 @@ const _sfc_main$2 = {
12742
13117
  dataIndexMap.set(String(realTimeData[i][axisKey]), realTimeData[i]);
12743
13118
  }
12744
13119
  try {
12745
- this._laneHasValidPoint = /* @__PURE__ */ Object.create(null);
13120
+ if (!laneFilter) this._laneHasValidPoint = /* @__PURE__ */ Object.create(null);
12746
13121
  for (let laneIndex = 0; laneIndex < lanes.length; laneIndex++) {
12747
13122
  const lane = lanes[laneIndex];
13123
+ if (laneFilter && !laneFilter.has(String(lane.laneId))) continue;
12748
13124
  const axisTypeList = this.currentToolBarConfig.axisTypeList || {
12749
13125
  depth: "depth",
12750
13126
  time: "time"
@@ -12850,7 +13226,7 @@ const _sfc_main$2 = {
12850
13226
  },
12851
13227
  axisPointer: { show: hasValidLineData }
12852
13228
  });
12853
- if (this.isGeomechanical) {
13229
+ if (this.isGeomechanical && !isDepthLane && !isTimeLane) {
12854
13230
  option.yAxis[gridIndex].splitNumber = ySplitCount;
12855
13231
  option.yAxis[gridIndex].minInterval = 1;
12856
13232
  option.yAxis[gridIndex].alignTicks = true;
@@ -13198,10 +13574,22 @@ const _sfc_main$2 = {
13198
13574
  return;
13199
13575
  }
13200
13576
  this.scheduleConnectAllCharts();
13201
- const lanesToRefresh = new Set(
13202
- Object.keys(this.laneSelectedPointPairs || {})
13203
- );
13204
- if (this.selectedLaneId) lanesToRefresh.add(this.selectedLaneId);
13577
+ if (this.trendLineManager) {
13578
+ if (laneFilter) {
13579
+ laneFilter.forEach((id) => this.trendLineManager.renderLane(id, true));
13580
+ } else {
13581
+ this.trendLineManager.scheduleRender();
13582
+ }
13583
+ }
13584
+ const lanesToRefresh = /* @__PURE__ */ new Set();
13585
+ if (laneFilter) {
13586
+ laneFilter.forEach((id) => lanesToRefresh.add(id));
13587
+ } else {
13588
+ Object.keys(this.laneSelectedPointPairs || {}).forEach(
13589
+ (id) => lanesToRefresh.add(id)
13590
+ );
13591
+ if (this.selectedLaneId) lanesToRefresh.add(this.selectedLaneId);
13592
+ }
13205
13593
  if (lanesToRefresh.size > 0) {
13206
13594
  this.$nextTick(() => {
13207
13595
  if (this._isUnmounted) return;
@@ -13342,6 +13730,16 @@ const _sfc_main$2 = {
13342
13730
  }
13343
13731
  return items;
13344
13732
  },
13733
+ // 自定义 tooltip 约定读 mousePositionData.time(桌面版 rowData 亦需该字段)
13734
+ buildTooltipMousePositionData(row) {
13735
+ if (!row || typeof row !== "object") return row || {};
13736
+ if (this.formCache.axisType !== "time") return row;
13737
+ const axisKey = this.getAxisDataKey();
13738
+ const raw = row[axisKey] != null ? row[axisKey] : row.timestamp != null ? row.timestamp : row.time != null ? row.time : null;
13739
+ if (raw == null) return row;
13740
+ const time = this.timestampToYMDHMS(this.toMillisecondTimestamp(raw));
13741
+ return { ...row, time };
13742
+ },
13345
13743
  renderLaneTooltipHtml(laneId) {
13346
13744
  const yValue = this._lastTooltipY;
13347
13745
  const lane = this.findLaneById(laneId);
@@ -13350,7 +13748,7 @@ const _sfc_main$2 = {
13350
13748
  if (this.tooltipFormatter && typeof this.tooltipFormatter === "function") {
13351
13749
  return this.tooltipFormatter({
13352
13750
  series: displaySeries,
13353
- mousePositionData: row
13751
+ mousePositionData: this.buildTooltipMousePositionData(row)
13354
13752
  });
13355
13753
  }
13356
13754
  let html = "<div>";
@@ -13424,7 +13822,7 @@ const _sfc_main$2 = {
13424
13822
  if (isMissingCurveValue(value)) value = null;
13425
13823
  return {
13426
13824
  value: [value, +item[axisKey]],
13427
- rowData: item
13825
+ rowData: this.normalizeTimeModeItem(item, axisKey)
13428
13826
  };
13429
13827
  });
13430
13828
  },
@@ -13592,9 +13990,10 @@ const _sfc_main$2 = {
13592
13990
  this._geoClickTimer = 0;
13593
13991
  }
13594
13992
  },
13595
- // 地应力:双击已选中泳道,只取消这一道,其它选中保留。8.25
13993
+ // 地应力:双击已选中泳道,只取消这一道,其它选中保留。仅手动选中模式。8.26
13596
13994
  handleChartDblClick(e, laneId) {
13597
13995
  if (this._isUnmounted || !this.isGeomechanical) return;
13996
+ if (!this.isManualLaneSelectMode()) return;
13598
13997
  this._clearGeoClickTimer();
13599
13998
  if (!this.isLaneSelected(laneId)) return;
13600
13999
  if (this._geoSelectClickAt && this._geoSelectLaneId === laneId && Date.now() - this._geoSelectClickAt < 500) {
@@ -13616,7 +14015,7 @@ const _sfc_main$2 = {
13616
14015
  this.selectedParamId = null;
13617
14016
  }
13618
14017
  this.removeLaneSelection(id);
13619
- await this.updateLanesChartOption();
14018
+ await this.updateLanesChartOption(void 0, id);
13620
14019
  if (this._isUnmounted) return;
13621
14020
  this.showSelectedPointScatter(id);
13622
14021
  },
@@ -13627,15 +14026,22 @@ const _sfc_main$2 = {
13627
14026
  const chartRef = this.getChartRefByLaneId(laneId);
13628
14027
  if (!chartRef || !chartRef.chart) return;
13629
14028
  const wasActiveLane = this.isLaneSelected(laneId);
13630
- const trendConsumed = this.trendLineManager && this.trendLineManager.handleClick(e, laneId);
14029
+ const trendConsumed = this.isTrendLaneSelectMode() && this.trendLineManager && this.trendLineManager.handleClick(e, laneId);
13631
14030
  if (!this.isGeomechanical) return;
13632
- if (!wasActiveLane) {
13633
- this._geoSelectClickAt = clickAt;
13634
- this._geoSelectLaneId = laneId;
13635
- this.addLaneSelection(laneId);
13636
- await this.updateLanesChartOption();
13637
- if (this._isUnmounted) return;
13638
- this.showSelectedPointScatter(laneId);
14031
+ if (this.isManualLaneSelectMode()) {
14032
+ if (!wasActiveLane) {
14033
+ this._geoSelectClickAt = clickAt;
14034
+ this._geoSelectLaneId = laneId;
14035
+ this.addLaneSelection(laneId);
14036
+ await this.updateLanesChartOption(void 0, laneId);
14037
+ if (this._isUnmounted) return;
14038
+ this.showSelectedPointScatter(laneId);
14039
+ }
14040
+ } else {
14041
+ if (!wasActiveLane) {
14042
+ if (trendConsumed) return;
14043
+ return;
14044
+ }
13639
14045
  }
13640
14046
  if (trendConsumed) return;
13641
14047
  if (wasActiveLane) {
@@ -13690,7 +14096,6 @@ const _sfc_main$2 = {
13690
14096
  point2: null,
13691
14097
  markAreaId: null
13692
14098
  });
13693
- console.log(clickedPoint, this.laneSelectedPointPairs[laneId]);
13694
14099
  this.showSelectedPointScatter(laneId);
13695
14100
  } else {
13696
14101
  const firstPoint = this.selectedPoints[0];
@@ -13732,7 +14137,7 @@ const _sfc_main$2 = {
13732
14137
  this.selectedParamId = null;
13733
14138
  this.showSelectedPointScatter(laneId);
13734
14139
  }
13735
- if (wasActiveLane) {
14140
+ if (wasActiveLane && this.isManualLaneSelectMode()) {
13736
14141
  const now = clickAt;
13737
14142
  if (this._lastBlankClickLaneId === laneId && this._lastBlankClickTime && now - this._lastBlankClickTime < 500) {
13738
14143
  this._lastBlankClickTime = null;
@@ -13744,7 +14149,7 @@ const _sfc_main$2 = {
13744
14149
  this.selectedParamId = null;
13745
14150
  }
13746
14151
  this.removeLaneSelection(laneId);
13747
- await this.updateLanesChartOption();
14152
+ await this.updateLanesChartOption(void 0, laneId);
13748
14153
  if (this._isUnmounted) return;
13749
14154
  } else {
13750
14155
  this._lastBlankClickTime = now;
@@ -13887,13 +14292,13 @@ const _sfc_main$2 = {
13887
14292
  }
13888
14293
  const chartRef = this.getChartRefByLaneId(laneId);
13889
14294
  if (!chartRef || !chartRef.chart) return;
13890
- if (this.trendLineManager && this.trendLineManager.handleContextMenu(e, laneId)) {
14295
+ if (this.isTrendLaneSelectMode() && this.trendLineManager && this.trendLineManager.handleContextMenu(e, laneId)) {
13891
14296
  return;
13892
14297
  }
13893
14298
  if (!this.isGeomechanical) return;
13894
- if (!this.isLaneSelected(laneId)) {
14299
+ if (this.isManualLaneSelectMode() && !this.isLaneSelected(laneId)) {
13895
14300
  this.addLaneSelection(laneId);
13896
- this.updateLanesChartOption();
14301
+ this.updateLanesChartOption(void 0, laneId);
13897
14302
  }
13898
14303
  const chart = chartRef.chart;
13899
14304
  const pointInPixel = [
@@ -14138,15 +14543,6 @@ const _sfc_main$2 = {
14138
14543
  startPoint,
14139
14544
  endPoint
14140
14545
  });
14141
- console.log(
14142
- {
14143
- markArea,
14144
- menuItem: item,
14145
- startPoint,
14146
- endPoint
14147
- },
14148
- "传递的数据"
14149
- );
14150
14546
  this.closeContextMenu();
14151
14547
  return;
14152
14548
  }
@@ -14158,7 +14554,6 @@ const _sfc_main$2 = {
14158
14554
  return;
14159
14555
  }
14160
14556
  const { topPoint, bottomPoint } = this.findBoundaryPointPair(currentPoint);
14161
- console.log("获取到的起始点和结束点", topPoint, bottomPoint);
14162
14557
  this.$emit("missingPointMenuItemClick", {
14163
14558
  pointInfo: currentPoint,
14164
14559
  menuItem: item,
@@ -14245,7 +14640,6 @@ const _sfc_main$2 = {
14245
14640
  }
14246
14641
  }
14247
14642
  }
14248
- console.log("searchStartIndex", searchStartIndex);
14249
14643
  if (searchStartIndex === -1) return null;
14250
14644
  let boundaryPoint = null;
14251
14645
  if (targetType === "bottom") {
@@ -14332,10 +14726,11 @@ const _sfc_main$2 = {
14332
14726
  // 获取Y轴标签格式化函数
14333
14727
  getYAxisLabelFormatter(isTimeLane, dataGroups, groupIndex, groupMin, groupMax, axisKey) {
14334
14728
  return (value) => {
14729
+ const numValue = Number(value);
14335
14730
  if (isTimeLane) {
14336
14731
  return `{center|${this.timestampToHms(value)}}`;
14337
14732
  }
14338
- if (groupIndex > 0 && value === groupMin) {
14733
+ if (groupIndex > 0 && Number.isFinite(numValue) && Math.abs(numValue - Number(groupMin)) < 1e-4) {
14339
14734
  const prevGroup = dataGroups[groupIndex - 1];
14340
14735
  const prevGroupMax = Math.max(
14341
14736
  ...prevGroup.map((item) => +item[axisKey])
@@ -14344,10 +14739,10 @@ const _sfc_main$2 = {
14344
14739
  return `{center2|${prevGroupMax}/${value}}`;
14345
14740
  return `{center2|${prevGroupMax.toFixed(0)}/${value.toFixed(0)}}`;
14346
14741
  }
14347
- if (groupIndex <= dataGroups.length - 1 && value === groupMax) {
14742
+ if (groupIndex <= dataGroups.length - 1 && Number.isFinite(numValue) && Math.abs(numValue - Number(groupMax)) < 1e-4) {
14348
14743
  return `{center|}`;
14349
14744
  }
14350
- if (groupIndex === 0 && value === groupMin) {
14745
+ if (groupIndex === 0 && Number.isFinite(numValue) && Math.abs(numValue - Number(groupMin)) < 1e-4) {
14351
14746
  return `{center|}`;
14352
14747
  }
14353
14748
  return `{center|${typeof +value === "number" ? Number(Number(value).toFixed(0)) : value}}`;
@@ -14516,7 +14911,6 @@ const _sfc_main$2 = {
14516
14911
  ) : [...areaItem.data].sort((a, b) => Number(a[axisKey]) - Number(b[axisKey]));
14517
14912
  const startData = sortedData[0];
14518
14913
  const endData = sortedData[1];
14519
- console.log("startData", startData, "endData", endData);
14520
14914
  let startY, endY;
14521
14915
  if (this.formCache.axisType === "depth") {
14522
14916
  const startDepth = startData.depth;
@@ -14826,7 +15220,7 @@ const _sfc_main$2 = {
14826
15220
  ySplitCount
14827
15221
  )
14828
15222
  };
14829
- if (this.isGeomechanical) {
15223
+ if (this.isGeomechanical && !isDepthLane) {
14830
15224
  yAxisItem.splitNumber = ySplitCount;
14831
15225
  yAxisItem.minInterval = 1;
14832
15226
  yAxisItem.alignTicks = true;
@@ -15273,12 +15667,25 @@ const _sfc_main$2 = {
15273
15667
  }
15274
15668
  });
15275
15669
  });
15276
- console.log(result, "最新数据");
15277
15670
  this.latestLineDataByParamCode = result;
15278
15671
  return result;
15279
15672
  }
15280
15673
  },
15281
15674
  watch: {
15675
+ // true:趋势线选中模式,初始不选中任何泳道。8.26
15676
+ canClickSelectLane: {
15677
+ handler(val) {
15678
+ if (val) this.clearActiveLane();
15679
+ },
15680
+ immediate: true
15681
+ },
15682
+ // 非地应力:清空选中,不出现任何泳道红框。8.26
15683
+ isGeomechanical: {
15684
+ handler(val) {
15685
+ if (!val) this.clearActiveLane();
15686
+ },
15687
+ immediate: true
15688
+ },
15282
15689
  lineListData: {
15283
15690
  handler() {
15284
15691
  this.$nextTick(() => this.applyLineListData(true));
@@ -15385,13 +15792,7 @@ const _sfc_main$2 = {
15385
15792
  let processedData = newVal && newVal.data || [];
15386
15793
  if (this.formCache.axisType == "time") {
15387
15794
  const axisKey = this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType] || "time";
15388
- const firstT = processedData[0] && processedData[0][axisKey];
15389
- if (!(typeof firstT === "number" && firstT > 1e11)) {
15390
- processedData = processedData.map((item) => ({
15391
- ...item,
15392
- [axisKey]: this.toMillisecondTimestamp(item[axisKey])
15393
- }));
15394
- }
15795
+ processedData = this.normalizeTimeModeData(processedData, axisKey);
15395
15796
  this.realTimeData = processedData;
15396
15797
  } else if (processedData[0] && processedData[0].timestamp) {
15397
15798
  const firstTs = processedData[0].timestamp;
@@ -15451,6 +15852,19 @@ const _sfc_main$2 = {
15451
15852
  }
15452
15853
  }
15453
15854
  });
15855
+ } else if (this.formCache.axisType === "time") {
15856
+ data = this.normalizeTimeModeData(data, axisKey);
15857
+ data.forEach((item) => {
15858
+ const matchIndex = this.realTimeData.findIndex(
15859
+ (d) => d[axisKey] == item[axisKey]
15860
+ );
15861
+ if (matchIndex > -1) {
15862
+ this.realTimeData[matchIndex] = {
15863
+ ...this.realTimeData[matchIndex],
15864
+ ...item
15865
+ };
15866
+ }
15867
+ });
15454
15868
  } else {
15455
15869
  data = data.map((item) => ({
15456
15870
  ...item,
@@ -15472,7 +15886,6 @@ const _sfc_main$2 = {
15472
15886
  await this.$nextTick();
15473
15887
  this.updateLanesChartOption();
15474
15888
  } else {
15475
- console.log(newVal, "newVal");
15476
15889
  let data = newVal && newVal.data || [];
15477
15890
  if (!Array.isArray(data)) {
15478
15891
  data = [data];
@@ -15480,10 +15893,7 @@ const _sfc_main$2 = {
15480
15893
  const direction = newVal.direction || "bottom";
15481
15894
  if (this.formCache.axisType == "time") {
15482
15895
  const axisKey = this.currentToolBarConfig.axisTypeList && this.currentToolBarConfig.axisTypeList[this.formCache.axisType] || "time";
15483
- data = data.map((item) => ({
15484
- ...item,
15485
- [axisKey]: this.toMillisecondTimestamp(item[axisKey])
15486
- }));
15896
+ data = this.normalizeTimeModeData(data, axisKey);
15487
15897
  this.realTimeData = markRaw(
15488
15898
  this.deduplicateByUniqueKey(
15489
15899
  this.realTimeData,
@@ -15611,8 +16021,9 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
15611
16021
  "skip-clone": "",
15612
16022
  "watch-shallow": "",
15613
16023
  "init-options": $data.echartsInitOptions,
15614
- onChartInited: (chart) => $options.handleChartInited(lane.laneId, chart)
15615
- }, null, 8, ["options", "group", "init-options", "onChartInited"]))
16024
+ onChartInited: (chart) => $options.handleChartInited(lane.laneId, chart),
16025
+ onOnSizeChange: () => $options.handleLaneChartSizeChange(lane.laneId)
16026
+ }, null, 8, ["options", "group", "init-options", "onChartInited", "onOnSizeChange"]))
15616
16027
  ], 36))
15617
16028
  ])
15618
16029
  };
@@ -15656,8 +16067,9 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
15656
16067
  "skip-clone": "",
15657
16068
  "watch-shallow": "",
15658
16069
  "init-options": $data.echartsInitOptions,
15659
- onChartInited: (chart) => $options.handleChartInited(lane.laneId, chart)
15660
- }, null, 8, ["options", "group", "init-options", "onChartInited"]))
16070
+ onChartInited: (chart) => $options.handleChartInited(lane.laneId, chart),
16071
+ onOnSizeChange: () => $options.handleLaneChartSizeChange(lane.laneId)
16072
+ }, null, 8, ["options", "group", "init-options", "onChartInited", "onOnSizeChange"]))
15661
16073
  ], 36))
15662
16074
  ])
15663
16075
  };
@@ -15717,7 +16129,7 @@ function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
15717
16129
  ])
15718
16130
  ], 544);
15719
16131
  }
15720
- const chartContainer = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-ec0aa0bf"]]);
16132
+ const chartContainer = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-90f5fe5f"]]);
15721
16133
  const _sfc_main$1 = {
15722
16134
  name: "ParameterPanel",
15723
16135
  props: {
@@ -16373,6 +16785,11 @@ const _sfc_main = {
16373
16785
  type: Boolean,
16374
16786
  default: false
16375
16787
  },
16788
+ // 泳道选中互斥:true=趋势线选中+可绘制;false=单击/双击选中且不可绘制趋势线。8.26
16789
+ canClickSelectLane: {
16790
+ type: Boolean,
16791
+ default: false
16792
+ },
16376
16793
  timeConfig: {
16377
16794
  type: Object,
16378
16795
  default: () => ({})
@@ -17238,7 +17655,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
17238
17655
  ])])) : createCommentVNode("", true)
17239
17656
  ]);
17240
17657
  }
17241
- const FrameLayoutComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-51f78d28"]]);
17658
+ const FrameLayoutComponent = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-de95a42f"]]);
17242
17659
  KdLaneContainerComponent.install = function(app) {
17243
17660
  app.component(KdLaneContainerComponent.name, KdLaneContainerComponent);
17244
17661
  };