@opendata-ai/openchart-engine 6.15.0 → 6.16.0

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.js CHANGED
@@ -596,7 +596,7 @@ function evaluateFieldPredicate(datum, pred) {
596
596
  return pred.valid ? isValid : !isValid;
597
597
  }
598
598
  if (pred.equal !== void 0) {
599
- return value2 === pred.equal;
599
+ return value2 == pred.equal;
600
600
  }
601
601
  const numValue = Number(value2);
602
602
  if (pred.lt !== void 0) {
@@ -616,7 +616,7 @@ function evaluateFieldPredicate(datum, pred) {
616
616
  return numValue >= min4 && numValue <= max4;
617
617
  }
618
618
  if (pred.oneOf !== void 0) {
619
- return pred.oneOf.includes(value2);
619
+ return pred.oneOf.some((v) => v == value2);
620
620
  }
621
621
  return true;
622
622
  }
@@ -727,6 +727,13 @@ function getSequentialColor(scales, value2, fallback = DEFAULT_COLOR) {
727
727
  }
728
728
 
729
729
  // src/charts/bar/compute.ts
730
+ function orientGradientForHorizontalBar(grad) {
731
+ if (grad.gradient !== "linear") return grad;
732
+ const lg = grad;
733
+ const isDefaultVertical = (lg.x1 === void 0 || lg.x1 === 0) && (lg.y1 === void 0 || lg.y1 === 0) && (lg.x2 === void 0 || lg.x2 === 0) && (lg.y2 === void 0 || lg.y2 === 1);
734
+ if (!isDefaultVertical) return grad;
735
+ return { ...lg, x1: 0, y1: 0, x2: 1, y2: 0 };
736
+ }
730
737
  var MIN_BAR_WIDTH = 1;
731
738
  function formatBarValue(value2) {
732
739
  if (Math.abs(value2) >= 1e3) return abbreviateNumber(value2);
@@ -837,7 +844,7 @@ function computeStackedBars(data, valueField, categoryField, colorField, xScale,
837
844
  y: bandY,
838
845
  width: barWidth,
839
846
  height: bandwidth,
840
- fill: color2,
847
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
841
848
  cornerRadius: 0,
842
849
  data: row,
843
850
  aria,
@@ -884,7 +891,7 @@ function computeGroupedBars(data, valueField, categoryField, colorField, xScale,
884
891
  y: subY,
885
892
  width: barWidth,
886
893
  height: subBandHeight,
887
- fill: color2,
894
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
888
895
  cornerRadius: 2,
889
896
  data: row,
890
897
  aria,
@@ -915,7 +922,7 @@ function computeColoredBars(data, valueField, categoryField, colorField, xScale,
915
922
  y: bandY,
916
923
  width: barWidth,
917
924
  height: bandwidth,
918
- fill: color2,
925
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
919
926
  cornerRadius: 2,
920
927
  data: row,
921
928
  aria,
@@ -956,7 +963,7 @@ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, band
956
963
  y: bandY,
957
964
  width: barWidth,
958
965
  height: bandwidth,
959
- fill: color2,
966
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
960
967
  cornerRadius: 2,
961
968
  data: row,
962
969
  aria,
@@ -6748,7 +6755,7 @@ function validateChartSpec(spec, errors) {
6748
6755
  message: `Spec error: encoding.${channel} must have a "field" string`,
6749
6756
  path: `encoding.${channel}.field`,
6750
6757
  code: "MISSING_FIELD",
6751
- suggestion: `Add a field name from your data columns: ${availableColumns}`
6758
+ suggestion: `For constant colors, use mark.fill (e.g., mark: { type: "bar", fill: "#1b7fa3" }) instead of encoding.${channel}. Encoding channels require a data field: ${availableColumns}`
6752
6759
  });
6753
6760
  continue;
6754
6761
  }
@@ -8116,7 +8123,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
8116
8123
  }
8117
8124
  }
8118
8125
  if (maxLabelWidth > 0) {
8119
- margins.right = Math.max(margins.right, padding + maxLabelWidth + 16);
8126
+ margins.right = Math.max(margins.right, padding + maxLabelWidth + 8);
8120
8127
  }
8121
8128
  }
8122
8129
  }
@@ -8492,14 +8499,18 @@ function buildPointScale(channel, data, rangeStart, rangeEnd) {
8492
8499
  function buildOrdinalColorScale(channel, data, palette) {
8493
8500
  const explicitDomain = channel.scale?.domain;
8494
8501
  const values = explicitDomain ? explicitDomain.map(String) : applyCategoricalSort(uniqueStrings(fieldValues(data, channel.field)), channel.sort);
8495
- const scale = ordinal().domain(values).range(palette);
8502
+ const explicitRange = channel.scale?.range;
8503
+ const colors = explicitRange ?? palette;
8504
+ const scale = ordinal().domain(values).range(colors);
8496
8505
  return { scale, type: "ordinal", channel };
8497
8506
  }
8498
8507
  function buildSequentialColorScale(channel, data, palette) {
8499
8508
  const values = parseNumbers(fieldValues(data, channel.field));
8500
8509
  const domainMin = min2(values) ?? 0;
8501
8510
  const domainMax = max2(values) ?? 1;
8502
- const scale = linear2().domain([domainMin, domainMax]).range([palette[0], palette[palette.length - 1]]).clamp(true);
8511
+ const explicitRange = channel.scale?.range;
8512
+ const colors = explicitRange ?? palette;
8513
+ const scale = linear2().domain([domainMin, domainMax]).range([colors[0], colors[colors.length - 1]]).clamp(true);
8503
8514
  return { scale, type: "sequential", channel };
8504
8515
  }
8505
8516
  function buildPositionalScale(channel, data, rangeStart, rangeEnd, chartType, axis) {
@@ -8723,14 +8734,23 @@ function extractColorEntries(spec, theme) {
8723
8734
  if ("condition" in colorEnc) return [];
8724
8735
  if (colorEnc.type === "quantitative") return [];
8725
8736
  const uniqueValues = [...new Set(spec.data.map((d) => String(d[colorEnc.field])))];
8726
- const palette = theme.colors.categorical;
8737
+ const explicitDomain = colorEnc.scale?.domain;
8738
+ const explicitRange = colorEnc.scale?.range;
8739
+ const palette = explicitRange ?? theme.colors.categorical;
8727
8740
  const shape = swatchShapeForType(spec.markType);
8728
- return uniqueValues.map((value2, i) => ({
8729
- label: value2,
8730
- color: palette[i % palette.length],
8731
- shape,
8732
- active: true
8733
- }));
8741
+ return uniqueValues.map((value2, i) => {
8742
+ let colorIndex = i;
8743
+ if (explicitDomain && explicitRange) {
8744
+ const domainIdx = explicitDomain.indexOf(value2);
8745
+ if (domainIdx >= 0) colorIndex = domainIdx;
8746
+ }
8747
+ return {
8748
+ label: value2,
8749
+ color: palette[colorIndex % palette.length],
8750
+ shape,
8751
+ active: true
8752
+ };
8753
+ });
8734
8754
  }
8735
8755
  function entriesThatFit(entries, maxWidth, maxRows, labelStyle) {
8736
8756
  let row = 1;
@@ -9908,8 +9928,13 @@ function computeCategoryColors(data, column, theme, darkMode) {
9908
9928
  if (raw == null) continue;
9909
9929
  const key = String(raw);
9910
9930
  let bg;
9911
- if (explicitMap[key]) {
9931
+ let isExplicit = false;
9932
+ if (explicitMap[key] != null) {
9933
+ if (explicitMap[key] === "transparent" || explicitMap[key] === "none") {
9934
+ continue;
9935
+ }
9912
9936
  bg = explicitMap[key];
9937
+ isExplicit = true;
9913
9938
  } else if (autoAssigned.has(key)) {
9914
9939
  bg = autoAssigned.get(key);
9915
9940
  } else {
@@ -9917,7 +9942,7 @@ function computeCategoryColors(data, column, theme, darkMode) {
9917
9942
  nextPaletteIndex++;
9918
9943
  autoAssigned.set(key, bg);
9919
9944
  }
9920
- if (darkMode) {
9945
+ if (darkMode && !isExplicit) {
9921
9946
  bg = adaptColorForDarkMode(bg, lightBg, darkBg);
9922
9947
  }
9923
9948
  const textColor = accessibleTextColor(bg);
@@ -11132,16 +11157,21 @@ function compileChart(spec, options) {
11132
11157
  const renderSpec = renderData !== chartSpec.data ? { ...chartSpec, data: renderData } : chartSpec;
11133
11158
  const scales = computeScales(renderSpec, chartArea, renderSpec.data);
11134
11159
  if (scales.color) {
11160
+ const hasExplicitRange = !!(renderSpec.encoding.color && "field" in renderSpec.encoding.color && renderSpec.encoding.color.scale?.range?.length);
11135
11161
  if (scales.color.type === "sequential") {
11136
- const seqStops = Object.values(theme.colors.sequential)[0] ?? theme.colors.categorical;
11137
- scales.color.scale.range([
11138
- seqStops[0],
11139
- seqStops[seqStops.length - 1]
11140
- ]);
11162
+ if (!hasExplicitRange) {
11163
+ const seqStops = Object.values(theme.colors.sequential)[0] ?? theme.colors.categorical;
11164
+ scales.color.scale.range([
11165
+ seqStops[0],
11166
+ seqStops[seqStops.length - 1]
11167
+ ]);
11168
+ }
11141
11169
  } else {
11142
- scales.color.scale.range(
11143
- theme.colors.categorical
11144
- );
11170
+ if (!hasExplicitRange) {
11171
+ scales.color.scale.range(
11172
+ theme.colors.categorical
11173
+ );
11174
+ }
11145
11175
  }
11146
11176
  }
11147
11177
  scales.defaultColor = chartSpec.markDef.fill ?? theme.colors.categorical[0];