@opendata-ai/openchart-vanilla 7.0.3 → 7.1.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
@@ -5259,6 +5259,7 @@ function renderAnnotations(parent, layout) {
5259
5259
 
5260
5260
  // src/renderers/axes.ts
5261
5261
  import {
5262
+ AXIS_TITLE_OFFSET_COMPACT,
5262
5263
  estimateTextWidth as estimateTextWidth2,
5263
5264
  getAxisTitleOffset,
5264
5265
  TICK_LABEL_OFFSET
@@ -5473,7 +5474,17 @@ function renderAxis(parent, axis, orientation, layout) {
5473
5474
  transform: `rotate(90, ${titleX}, ${area.y + area.height / 2})`
5474
5475
  });
5475
5476
  } else {
5476
- const titleOffset = getAxisTitleOffset(layout.dimensions.width);
5477
+ const AXIS_TITLE_GAP = 8;
5478
+ const maxTickLabelWidth = axis.ticks.reduce((max, t) => {
5479
+ const w = estimateTextWidth2(
5480
+ t.label,
5481
+ axis.tickLabelStyle.fontSize,
5482
+ axis.tickLabelStyle.fontWeight ?? 400
5483
+ );
5484
+ return Math.max(max, w);
5485
+ }, 0);
5486
+ const dynamicOffset = TICK_LABEL_OFFSET + maxTickLabelWidth + AXIS_TITLE_GAP;
5487
+ const titleOffset = Math.max(dynamicOffset, AXIS_TITLE_OFFSET_COMPACT);
5477
5488
  setAttrs2(axisLabel, {
5478
5489
  x: area.x - titleOffset,
5479
5490
  y: area.y + area.height / 2,
@@ -6027,14 +6038,6 @@ function renderRectMark(mark, index2) {
6027
6038
  shapeEl.setAttribute("stroke-width", String(mark.strokeWidth));
6028
6039
  }
6029
6040
  g.appendChild(shapeEl);
6030
- if (mark.label?.visible) {
6031
- const label = createSVGElement2("text");
6032
- label.setAttribute("class", "oc-mark-label");
6033
- setAttrs2(label, { x: mark.label.x, y: mark.label.y });
6034
- applyTextStyle(label, mark.label.style);
6035
- label.textContent = mark.label.text;
6036
- g.appendChild(label);
6037
- }
6038
6041
  return g;
6039
6042
  }
6040
6043
  function renderArcMark(mark, index2) {
@@ -6208,6 +6211,32 @@ function renderMarks(parent, layout) {
6208
6211
  g.appendChild(el);
6209
6212
  }
6210
6213
  parent.appendChild(g);
6214
+ let labelsGroup;
6215
+ for (let i = 0; i < layout.marks.length; i++) {
6216
+ const mark = layout.marks[i];
6217
+ if (mark.type !== "rect") continue;
6218
+ const rect = mark;
6219
+ if (!rect.label?.visible) continue;
6220
+ if (!labelsGroup) {
6221
+ labelsGroup = createSVGElement2("g");
6222
+ labelsGroup.setAttribute("class", "oc-mark-labels");
6223
+ }
6224
+ const label = createSVGElement2("text");
6225
+ label.setAttribute("class", "oc-mark-label");
6226
+ setAttrs2(label, { x: rect.label.x, y: rect.label.y });
6227
+ applyTextStyle(label, rect.label.style);
6228
+ label.textContent = rect.label.text;
6229
+ if (currentAnimation?.enabled) {
6230
+ const idx = rect.animationIndex ?? i;
6231
+ label.setAttribute("data-animation-index", String(idx));
6232
+ label.style.setProperty(
6233
+ "--oc-mark-index",
6234
+ String(idx)
6235
+ );
6236
+ }
6237
+ labelsGroup.appendChild(label);
6238
+ }
6239
+ return labelsGroup;
6211
6240
  }
6212
6241
 
6213
6242
  // src/renderers/metrics.ts
@@ -6263,7 +6292,9 @@ function renderChartSVG(layout, container, opts) {
6263
6292
  // overflow is "hidden", which clips this phantom extent. Setting
6264
6293
  // overflow:visible prevents the clipping. Chart marks are already
6265
6294
  // constrained by a clipPath, so nothing bleeds out.
6266
- overflow: "visible"
6295
+ overflow: "visible",
6296
+ // Hint browsers to enable sub-pixel font hinting and kerning for chart text.
6297
+ "text-rendering": "optimizeLegibility"
6267
6298
  });
6268
6299
  svg.style.height = `${height}px`;
6269
6300
  svg.setAttribute("role", layout.a11y.role);
@@ -6331,7 +6362,7 @@ function renderChartSVG(layout, container, opts) {
6331
6362
  renderAxes(svg, layout);
6332
6363
  const clippedGroup = createSVGElement2("g");
6333
6364
  clippedGroup.setAttribute("clip-path", `url(#${clipId})`);
6334
- renderMarks(clippedGroup, layout);
6365
+ const markLabelsOverlay = renderMarks(clippedGroup, layout);
6335
6366
  const hasLineOrAreaWithDataPoints = layout.marks.some(
6336
6367
  (m2) => (m2.type === "line" || m2.type === "area") && m2.dataPoints && m2.dataPoints.length > 0
6337
6368
  );
@@ -6376,6 +6407,9 @@ function renderChartSVG(layout, container, opts) {
6376
6407
  clippedGroup.appendChild(dotsGroup);
6377
6408
  }
6378
6409
  svg.appendChild(clippedGroup);
6410
+ if (markLabelsOverlay) {
6411
+ svg.appendChild(markLabelsOverlay);
6412
+ }
6379
6413
  renderAnnotations(svg, layout);
6380
6414
  renderEndpointLabels(svg, layout);
6381
6415
  const epEntries = layout.endpointLabels?.entries ?? [];
@@ -6383,7 +6417,7 @@ function renderChartSVG(layout, container, opts) {
6383
6417
  const pointEls = clippedGroup.querySelectorAll("circle.oc-mark-point");
6384
6418
  for (const entry of epEntries) {
6385
6419
  if (!entry.marker) continue;
6386
- const mx = entry.marker.x;
6420
+ const mx = entry.marker.dataX;
6387
6421
  const my = entry.marker.y;
6388
6422
  for (const el of pointEls) {
6389
6423
  const cx = Number(el.getAttribute("cx"));