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