rapid-spreadjs 1.0.185 → 1.0.187

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/index.esm.js CHANGED
@@ -5313,117 +5313,132 @@ const EChartsUtilsAll = {
5313
5313
  return option;
5314
5314
  },
5315
5315
  /**
5316
- * 筛分
5316
+ * 筛分(动态多折线版)
5317
+ * 与 chart50 主体逻辑一致(x轴 0.45 次方变换、按x排序、空值过滤、markLine 模拟x轴标签等),
5318
+ * 区别在于折线数量不再固定为 3 条,而是根据 chartLinesJson 中的折线配置数量动态生成 N 条线:
5319
+ * - 每条线的图例名取 lineData[i].legend
5320
+ * - 每条线的颜色取 lineData[i].lineColor
5321
+ * - 每条线的 Y 数据取 yDataArr[i]
5322
+ * - 符号与线型按索引循环取预设值(首线保持实心方块+实线,与 chart50 一致)
5317
5323
  * @param config 折线配置
5318
- * @param xDataArr x轴原始数据(二维数组)
5319
- * @param yDataArr y轴原始数据(二维数组)
5324
+ * @param xDataArr x轴原始数据(二维数组,取 xDataArr[0] 作为共享x轴)
5325
+ * @param yDataArr y轴原始数据(二维数组,yDataArr[i] 对应第 i 条线)
5320
5326
  * @returns 返回ECharts配置项
5321
5327
  */
5322
5328
  chart50: (config, xDataArr, yDataArr) => {
5323
5329
  let lineData = JSON.parse(config.chartLinesJson);
5324
- let title = '', //config.chartTitle,
5325
- xName = config.chartXName, yName = config.chartYName;
5326
- // x轴原始数据、y轴原始数据、y轴原始数据(上限)、y轴原始数据(下限)
5327
- const xDataSourceOld = xDataArr[0], yDataSourceOld = yDataArr[0], yDataSourceSxOld = yDataArr[1], yDataSourceXxOld = yDataArr[2];
5330
+ let title = '', xName = config.chartXName, yName = config.chartYName;
5331
+ // 折线数量:以 chartLinesJson 中配置的折线条数为准
5332
+ const lineCount = Array.isArray(lineData) ? lineData.length : 0;
5333
+ // x轴原始数据(共享一份)
5334
+ const xDataSourceOld = xDataArr[0];
5328
5335
  const allData = [];
5329
5336
  xDataSourceOld.forEach((item, index) => {
5330
- allData.push({
5331
- x: item,
5332
- y: yDataSourceOld[index],
5333
- ySx: yDataSourceSxOld[index],
5334
- yXx: yDataSourceXxOld[index],
5335
- });
5337
+ const point = { x: item };
5338
+ // 将每条线的 y 值都收进同一个点对象,key 为 y0/y1/y2...
5339
+ for (let i = 0; i < lineCount; i++) {
5340
+ point['y' + i] = (yDataArr[i] || [])[index];
5341
+ }
5342
+ allData.push(point);
5336
5343
  });
5337
5344
  allData.sort(function (a, b) {
5338
5345
  return a.x - b.x;
5339
5346
  });
5340
- const xDataSource = [], yDataSource = [], yDataSourceSx = [], yDataSourceXx = [];
5341
- // 记录上限或下限中值为null的个数
5342
- let sxValNullCount = 0;
5343
- yDataSourceSxOld.forEach((item, index) => {
5344
- if (item == null || item == '/') {
5345
- sxValNullCount++;
5346
- }
5347
- });
5348
- // 如果上限或下限值中的所有值都为null,则只展示筛分曲线的折线
5349
- if (sxValNullCount == yDataSourceSxOld.length) {
5350
- allData.forEach((item, index) => {
5351
- xDataSource.push(item.x);
5352
- yDataSource.push(item.y);
5353
- yDataSourceSx.push(item.ySx);
5354
- yDataSourceXx.push(item.yXx);
5355
- });
5356
- }
5357
- else {
5358
- // 只获取上限或下限中值不为null的点
5359
- allData.forEach((item, index) => {
5360
- if (item.ySx != null && item.ySx != '/' && item.yXx != null && item.yXx != '/') {
5361
- xDataSource.push(item.x);
5362
- yDataSource.push(item.y);
5363
- yDataSourceSx.push(item.ySx);
5364
- yDataSourceXx.push(item.yXx);
5347
+ // 每条线的数据数组
5348
+ const yDataSources = [];
5349
+ for (let i = 0; i < lineCount; i++) {
5350
+ yDataSources.push([]);
5351
+ }
5352
+ // 统计各条线中值为 null 或 "/" 的个数(用于后续空值过滤逻辑,保持与 chart50 一致的行为)
5353
+ const nullCounts = [];
5354
+ for (let i = 0; i < lineCount; i++) {
5355
+ let cnt = 0;
5356
+ (yDataArr[i] || []).forEach((item) => {
5357
+ if (item == null || item == '/') {
5358
+ cnt++;
5365
5359
  }
5366
5360
  });
5361
+ nullCounts.push(cnt);
5367
5362
  }
5368
- // x轴需要的数据(x轴原始数据的0.45次方,并修约0.01)、x轴需要的上限数据(x轴原始数据的0.45次方,并修约0.01)、x轴需要的下限数据(x轴原始数据的0.45次方,并修约0.01)、标记线需要的数据
5369
- let xData = [], xDataSx = [], xDataXx = [], markLineData = [];
5363
+ // 若任意一条线存在非空值,则按“所有线均非空”过滤出有效点;否则保留全部点(与 chart50 上限/下限过滤逻辑保持语义一致)
5364
+ const hasAnyValid = nullCounts.some((cnt, i) => cnt < (yDataArr[i] || []).length);
5365
+ allData.forEach((item) => {
5366
+ if (!hasAnyValid) {
5367
+ for (let i = 0; i < lineCount; i++) {
5368
+ yDataSources[i].push(item['y' + i]);
5369
+ }
5370
+ return;
5371
+ }
5372
+ // 存在有效值时,仅当所有线该点均非空才保留
5373
+ let allValid = true;
5374
+ for (let i = 0; i < lineCount; i++) {
5375
+ const v = item['y' + i];
5376
+ if (v == null || v == '/') {
5377
+ allValid = false;
5378
+ break;
5379
+ }
5380
+ }
5381
+ if (allValid) {
5382
+ for (let i = 0; i < lineCount; i++) {
5383
+ yDataSources[i].push(item['y' + i]);
5384
+ }
5385
+ }
5386
+ });
5387
+ // x轴数据:x轴原始数据的0.45次方,并修约0.001
5388
+ let xData = [];
5389
+ let markLineData = [];
5370
5390
  // x和y轴的字体大小
5371
5391
  const xyFontSize = 10;
5372
- // 组装数据
5373
- xDataSource.forEach((item, index) => {
5374
- // 得到x轴原始数据的0.45次方值,并修约0.001
5392
+ // 组装 x 轴与 markLine(所有线共用同一套 x 值)
5393
+ xDataSourceOld.forEach((item, index) => {
5375
5394
  const val045 = Number(EChartsUtilsComm.getRound(item ** 0.45, 0.001));
5376
- xData.push([val045, yDataSource[index]]);
5377
5395
  markLineData.push({
5378
5396
  name: item + '',
5379
5397
  xAxis: val045,
5380
5398
  label: {
5381
- show: xDataSource.length >= 6 && index % 2 != 0 && index < 6 ? false : true, // 控制x轴的名称某些点是否显示,避免重叠的情况
5399
+ show: xDataSourceOld.length >= 6 && index % 2 != 0 && index < 6 ? false : true,
5382
5400
  fontSize: xyFontSize,
5383
5401
  },
5384
5402
  });
5385
- xDataSx.push([val045, yDataSourceSx[index]]);
5386
- xDataXx.push([val045, yDataSourceXx[index]]);
5403
+ xData.push(val045);
5387
5404
  });
5405
+ // 符号与线型预设值(循环取用)
5406
+ const symbolPresets = ['rect', 'triangle', 'circle', 'diamond', 'roundRect', 'arrow'];
5407
+ const lineTypePresets = ['solid', 'dotted', [10, 5], 'dashed', [2, 2], [6, 3, 2, 3]];
5388
5408
  /**
5389
- * 获取series需要的3条线配置
5390
- * @param type 线类型(1:筛分曲线、2:上限、3:下限)
5391
- * @param data 对应的坐标点数据
5409
+ * 获取 series 需要的单条线配置(动态版)
5410
+ * @param index 第几条线
5411
+ * @param data 对应的坐标点数据([x, y])
5392
5412
  */
5393
- const getLineObj = (type, data) => {
5394
- const name = type == 1 ? '筛分曲线' : type == 2 ? '上限' : '下限';
5395
- const symbol = type == 1 ? 'rect' : type == 2 ? 'triangle' : 'circle';
5396
- const lineType = type == 1 ? 'solid' : type == 2 ? 'dotted' : [10, 5];
5397
- const color = type == 1 ? lineData[0].lineColor : type == 2 ? lineData[1].lineColor : lineData[2].lineColor; //type == 1 ? '#F56C6C' : type == 2 ? '#409EFF' : '#000';
5413
+ const getLineObj = (index, data) => {
5414
+ const lineCfg = lineData[index] || {};
5415
+ // 图例名:优先取 lineData[index].legend,其次用序号兜底
5416
+ const name = lineCfg.legend != null && lineCfg.legend !== '' ? lineCfg.legend : '折线' + (index + 1);
5417
+ // 颜色:优先取 lineData[index].lineColor,其次循环取预设色
5418
+ const color = lineCfg.lineColor != null && lineCfg.lineColor !== '' ? lineCfg.lineColor : null;
5419
+ const symbol = symbolPresets[index % symbolPresets.length];
5420
+ const lineType = lineTypePresets[index % lineTypePresets.length];
5398
5421
  let obj = {
5399
5422
  name: name,
5400
5423
  type: 'line',
5401
- smooth: true, // 平滑的线条
5402
- // 设置数据点形状(实心),参考文档:https://echarts.apache.org/zh/option.html#series-line.symbol
5424
+ smooth: true,
5403
5425
  symbol: symbol,
5404
5426
  symbolSize: 5,
5405
- z: 10, // 控制曲线的浮动层级,避免在markLine下方被遮住
5406
- // 线条的颜色
5427
+ z: 10,
5407
5428
  lineStyle: {
5408
5429
  color: color,
5409
- // 线条类型(solid:实线、dashed:粗虚线、dotted:细虚线)
5410
5430
  type: lineType,
5411
5431
  },
5412
- // 线条上数据点的颜色
5413
5432
  itemStyle: {
5414
5433
  color: color,
5415
5434
  },
5416
5435
  data: data,
5417
- connectNulls: true, // 是否连接空数据
5436
+ connectNulls: true,
5418
5437
  markLine: {
5419
- symbol: '', // 取消箭头
5420
- silent: true, // 取消鼠标hover事件
5438
+ symbol: '',
5439
+ silent: true,
5421
5440
  label: {
5422
- // 标线的文本,模拟x轴显示的内容
5423
- position: 'start', // 改变label位置
5424
- //rotate: 45, // 设置文字旋转度数(注意:ECharts官网文档居然没有rotate这个属性的说明)
5425
- // backgroundColor:'#fff'
5426
- // color:'#f00',// 文字颜色
5441
+ position: 'start',
5427
5442
  formatter: (data) => {
5428
5443
  return data.name;
5429
5444
  },
@@ -5439,40 +5454,48 @@ const EChartsUtilsAll = {
5439
5454
  if (xData.length == 0) {
5440
5455
  yValIsAllNull = true;
5441
5456
  }
5442
- let nullCount = 0;
5443
- xData.forEach((item) => {
5444
- if (item[1] == null || item[1] == undefined || item[1] == '/') {
5445
- nullCount++;
5457
+ // 组装每条线的 [x, y] 坐标点数据
5458
+ const seriesDataList = [];
5459
+ for (let i = 0; i < lineCount; i++) {
5460
+ const linePoints = [];
5461
+ for (let j = 0; j < xData.length; j++) {
5462
+ linePoints.push([xData[j], yDataSources[i][j]]);
5446
5463
  }
5447
- });
5448
- if (nullCount == xData.length) {
5449
- yValIsAllNull = true;
5464
+ seriesDataList.push(linePoints);
5450
5465
  }
5451
- if (yDataSourceSxOld.some((item) => item != null && item != undefined && item != '/') ||
5452
- yDataSourceXxOld.some((item) => item != null && item != undefined && item != '/')) {
5453
- yValIsAllNull = false;
5454
- }
5455
- if (xData.filter((x) => x[1] == 0).length == xData.length &&
5456
- xDataSx.filter((x) => x[1] == 0).length == xDataSx.length &&
5457
- xDataXx.filter((x) => x[1] == 0).length == xDataXx.length) {
5466
+ let nullCount = 0;
5467
+ seriesDataList.forEach((linePoints) => {
5468
+ linePoints.forEach((item) => {
5469
+ if (item[1] == null || item[1] == undefined || item[1] == '/') {
5470
+ nullCount++;
5471
+ }
5472
+ });
5473
+ });
5474
+ if (nullCount == xData.length * lineCount) {
5458
5475
  yValIsAllNull = true;
5459
5476
  }
5460
- if (!yDataArr[0].some((x) => x != '' && x != '/' && x != null && x != undefined) &&
5461
- !yDataArr[1].some((x) => x != '' && x != '/' && x != null && x != undefined) &&
5462
- !yDataArr[2].some((x) => x != '' && x != '/' && x != null && x != undefined)) {
5477
+ if (yDataArr.every((arr) => !arr.some((x) => x != '' && x != '/' && x != null && x != undefined))) {
5463
5478
  yValIsAllNull = true;
5464
5479
  }
5480
+ // 图例名称与选中状态(动态)
5481
+ const legendNames = [];
5482
+ const legendSelected = {};
5483
+ for (let i = 0; i < lineCount; i++) {
5484
+ const lineCfg = lineData[i] || {};
5485
+ const name = lineCfg.legend != null && lineCfg.legend !== '' ? lineCfg.legend : '折线' + (i + 1);
5486
+ legendNames.push(name);
5487
+ legendSelected[name] = true;
5488
+ }
5489
+ // series 动态生成
5490
+ const series = seriesDataList.map((linePoints, i) => getLineObj(i, !yValIsAllNull ? linePoints : []));
5465
5491
  let option = {
5466
5492
  grid: {
5467
- // show: true,// 是否显示外边框线
5468
- // borderColor: '#f00',// 外边框线颜色
5469
5493
  top: 20,
5470
5494
  left: 30,
5471
5495
  right: 10,
5472
5496
  bottom: 35,
5473
5497
  containLabel: true,
5474
5498
  },
5475
- // 提示框组件,参考文档:https://echarts.apache.org/zh/option.html#tooltip
5476
5499
  tooltip: {
5477
5500
  trigger: 'axis',
5478
5501
  formatter: function (datas, ticket) {
@@ -5485,7 +5508,6 @@ const EChartsUtilsAll = {
5485
5508
  }
5486
5509
  },
5487
5510
  },
5488
- // 顶部的标题,参考文档:https://echarts.apache.org/zh/option.html#title
5489
5511
  title: [
5490
5512
  {
5491
5513
  show: true,
@@ -5508,29 +5530,22 @@ const EChartsUtilsAll = {
5508
5530
  },
5509
5531
  },
5510
5532
  ],
5511
- // 图例,参考文档:https://echarts.apache.org/zh/option.html#legend
5512
5533
  legend: {
5513
- // show: !yValIsAllNull,
5514
5534
  top: '0px',
5515
5535
  left: 'center',
5516
- data: ['筛分曲线', '上限', '下限'],
5517
- selected: {
5518
- 筛分曲线: true, // 显示
5519
- 上限: true, // 显示
5520
- 下限: true, // 显示
5521
- },
5522
- selectedMode: 'multiple', // 用于控制图例的选择模式(single:单选、multiple:多选、false:禁止选择)
5536
+ data: legendNames,
5537
+ selected: legendSelected,
5538
+ selectedMode: 'multiple',
5523
5539
  },
5524
5540
  xAxis: {
5525
5541
  type: 'value',
5526
- axisTick: { show: false }, // 隐藏刻度线
5527
- axisLabel: { show: false }, // 隐藏刻度值
5528
- // 网格线,参考文档:https://echarts.apache.org/zh/option.html#xAxis.splitLine
5542
+ axisTick: { show: false },
5543
+ axisLabel: { show: false },
5529
5544
  splitLine: {
5530
- show: false, // 隐藏分割线
5545
+ show: false,
5531
5546
  },
5532
- min: xData.length > 0 ? (xData[0][0] > 0.2 ? xData[0][0] - 0.2 : 0) : null, //控制x轴的最小值
5533
- max: xData.length > 0 ? xData[xData.length - 1][0] + 0.1 : null,
5547
+ min: xData.length > 0 ? (xData[0] > 0.2 ? xData[0] - 0.2 : 0) : null,
5548
+ max: xData.length > 0 ? xData[xData.length - 1] + 0.1 : null,
5534
5549
  },
5535
5550
  yAxis: [
5536
5551
  {
@@ -5542,23 +5557,19 @@ const EChartsUtilsAll = {
5542
5557
  splitLine: {
5543
5558
  show: true,
5544
5559
  lineStyle: {
5545
- color: '#e0e6f1', // '#e0e6f1',
5560
+ color: '#e0e6f1',
5546
5561
  type: 'solid',
5547
5562
  },
5548
5563
  },
5549
5564
  min: 0,
5550
5565
  max: 100,
5551
- splitNumber: 10, // 设置y轴分隔的段数,如0~100之间默认情况可能会按照0、20、40、60……的间隔显示,设置相应的数字后就会根据实际情况显示的更细,如0、10、20、30……
5566
+ splitNumber: 10,
5552
5567
  axisLabel: {
5553
5568
  fontSize: xyFontSize,
5554
5569
  },
5555
5570
  },
5556
5571
  ],
5557
- series: [
5558
- getLineObj(1, !yValIsAllNull ? xData : []),
5559
- getLineObj(2, !yValIsAllNull ? xDataSx : []),
5560
- getLineObj(3, !yValIsAllNull ? xDataXx : []),
5561
- ],
5572
+ series: series,
5562
5573
  };
5563
5574
  return option;
5564
5575
  },
@@ -23973,22 +23984,18 @@ const FormulaUtils = {
23973
23984
  optional: false,
23974
23985
  },
23975
23986
  {
23976
- name: '目标点x坐标',
23977
- repeatable: false,
23978
- optional: false,
23979
- },
23980
- {
23981
- name: '目标点y坐标',
23987
+ name: '目标点坐标,格式如 (3.5,6.5)',
23982
23988
  repeatable: false,
23983
23989
  optional: false,
23984
23990
  },
23985
23991
  ],
23986
23992
  funCallback: (spread, sheet, retData) => {
23987
- // 如果传递的参数小于3个,则返回/
23988
- if (retData.allCellVals.length < 3) {
23993
+ // 如果传递的参数小于2个,则返回/
23994
+ if (retData.allCellVals.length < 2) {
23989
23995
  return '/';
23990
23996
  }
23991
- let points = retData.allCellVals[0], xPoint = retData.allCellVals[1], yPoint = retData.allCellVals[2];
23997
+ const pointStrArr = retData.allCellVals[1].replace('(', '').replace(')', '').split(',');
23998
+ let points = retData.allCellVals[0], xPoint = pointStrArr[0], yPoint = pointStrArr[1];
23992
23999
  // 1. 格式校验
23993
24000
  if (typeof points !== 'string' || !points)
23994
24001
  return '/';