Summary
assembleECharts places the categorical legend (and the matching legend-title graphic) at an absolute left in design-canvas pixels. That is correct when the host inits ECharts at _width × _height. It breaks as soon as a host puts the chart in a fluid container and calls the official chart.resize().
This is not an ECharts resize() bug. resize() only changes the canvas / grid / axes; it does not rewrite option pixel fields. Flint is the one emitting legend.left relative to _width.
Verified against flint-chart@0.4.1. The same left: legendLeftPx path is still in main (packages/flint-js/src/echarts/instantiate-spec.ts, legend-positioning block). I did not find an existing issue for this.
Repro
Slope Chart (any multi-series cartesian chart with a right-side categorical legend works):
import { assembleECharts } from 'flint-chart/echarts';
import * as echarts from 'echarts';
const option = assembleECharts({
data: { values: [
{ period: '2024', team: 'Alpha', nps: 32 },
{ period: '2025', team: 'Alpha', nps: 48 },
{ period: '2024', team: 'Beta', nps: 41 },
{ period: '2025', team: 'Beta', nps: 39 },
{ period: '2024', team: 'Gamma', nps: 28 },
{ period: '2025', team: 'Gamma', nps: 52 },
{ period: '2024', team: 'Delta', nps: 55 },
{ period: '2025', team: 'Delta', nps: 61 },
]},
semantic_types: { period: 'Year', team: 'Name', nps: 'Score' },
chart_spec: {
chartType: 'Slope Chart',
encodings: {
x: { field: 'period' },
y: { field: 'nps' },
color: { field: 'team' },
},
baseSize: { width: 420, height: 280 },
},
});
// Typical host: fill the reading column, then resize.
const el = document.getElementById('chart');
el.style.width = '100%'; // e.g. 800px
el.style.height = option._height + 'px';
const chart = echarts.init(el);
chart.setOption(option);
chart.resize();
Assembled bookkeeping on 0.4.1:
| field |
value |
_width / _height |
534 × 377 |
grid.right |
112 (plot ends at canvasW − 112) |
legend.left |
422 |
legend-title graphic.left |
422 |
422 + 112 = 534. The legend’s left edge is meant to sit on the plot’s right edge only when the canvas is 534px wide.
Actual
- Canvas 534px (Flint’s contract): legend sits in the reserved gutter. Correct.
- Canvas 800px +
resize(): plot stretches to 800 − 112 = 688, legend stays at left: 422 → overlaps the series.
- Canvas 350px +
resize(): legend.left: 422 is past the right edge → clipped / gone.
grid.left / grid.right as pixel insets still work at any width. Only left-origin design coordinates (legend.left, title graphic.left, and similarly series.radius: 'NNpx' on sunburst/pie) do not.
Expected
One of:
- Document the contract in the ECharts assemble docs: hosts must init/size the DOM to
_width × _height (or CSS-scale that box). Fluid width: 100% + resize() is unsupported.
- Emit fluid-safe positions so official
resize() keeps the legend in the gutter:
legend.right (and the title graphic) instead of legend.left: designW − gutter, or
left: 'right' / percent, with grid.right still reserving the same gutter.
Option 2 is a small change in ecApplyLayoutToSpec and would let note/editor hosts follow the ECharts handbook (width: 100% + resize()) without rewriting Flint’s option.
A host-side conversion of left → right = _width - left is wrong: ECharts right is the inset to the component’s right edge, so the legend grows left into the plot even at design size.
Why this shows up in hosts
Flint’s own MCP / gallery path paints at a fixed canvas (create_chart_view is described as fixed-size). Editors that share a reading column with prose (and iPhone/iPad widths) cannot dedicate _width forever, and resize() is the documented ECharts way to follow the container.
Related but separate: sunburst/pie radius: [\${n}px`, ...]` is also design-canvas-absolute and clips when the live box is smaller. Happy to split that if you want a narrower first fix.
Environment
flint-chart@0.4.1 (reproduced)
main as of 2026-08-15 still uses legendLeftPx = effectiveChartWidth - rightMarginPx
- Apache ECharts 5 / 6 (behavior of
legend.left vs resize() is the same)
Summary
assembleEChartsplaces the categorical legend (and the matching legend-titlegraphic) at an absoluteleftin design-canvas pixels. That is correct when the host inits ECharts at_width × _height. It breaks as soon as a host puts the chart in a fluid container and calls the officialchart.resize().This is not an ECharts
resize()bug.resize()only changes the canvas / grid / axes; it does not rewrite option pixel fields. Flint is the one emittinglegend.leftrelative to_width.Verified against
flint-chart@0.4.1. The sameleft: legendLeftPxpath is still inmain(packages/flint-js/src/echarts/instantiate-spec.ts, legend-positioning block). I did not find an existing issue for this.Repro
Slope Chart (any multi-series cartesian chart with a right-side categorical legend works):
Assembled bookkeeping on 0.4.1:
_width/_heightgrid.rightcanvasW − 112)legend.leftgraphic.left422 + 112 = 534. The legend’s left edge is meant to sit on the plot’s right edge only when the canvas is 534px wide.Actual
resize(): plot stretches to800 − 112 = 688, legend stays atleft: 422→ overlaps the series.resize():legend.left: 422is past the right edge → clipped / gone.grid.left/grid.rightas pixel insets still work at any width. Only left-origin design coordinates (legend.left, titlegraphic.left, and similarlyseries.radius: 'NNpx'on sunburst/pie) do not.Expected
One of:
_width × _height(or CSS-scale that box). Fluidwidth: 100%+resize()is unsupported.resize()keeps the legend in the gutter:legend.right(and the title graphic) instead oflegend.left: designW − gutter, orleft: 'right'/ percent, withgrid.rightstill reserving the same gutter.Option 2 is a small change in
ecApplyLayoutToSpecand would let note/editor hosts follow the ECharts handbook (width: 100%+resize()) without rewriting Flint’s option.A host-side conversion of
left → right = _width - leftis wrong: EChartsrightis the inset to the component’s right edge, so the legend grows left into the plot even at design size.Why this shows up in hosts
Flint’s own MCP / gallery path paints at a fixed canvas (
create_chart_viewis described as fixed-size). Editors that share a reading column with prose (and iPhone/iPad widths) cannot dedicate_widthforever, andresize()is the documented ECharts way to follow the container.Related but separate: sunburst/pie
radius: [\${n}px`, ...]` is also design-canvas-absolute and clips when the live box is smaller. Happy to split that if you want a narrower first fix.Environment
flint-chart@0.4.1(reproduced)mainas of 2026-08-15 still useslegendLeftPx = effectiveChartWidth - rightMarginPxlegend.leftvsresize()is the same)