@vielzeug/prism 26.10.14 → 26.10.16
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/_dev.cjs.map +1 -1
- package/dist/_dev.js +6 -1
- package/dist/_dev.js.map +1 -1
- package/dist/_tappers.cjs.map +1 -1
- package/dist/_tappers.js +25 -1
- package/dist/_tappers.js.map +1 -1
- package/dist/animation/easing.cjs.map +1 -1
- package/dist/animation/easing.js +15 -1
- package/dist/animation/easing.js.map +1 -1
- package/dist/animation/motion.cjs.map +1 -1
- package/dist/animation/motion.js +15 -1
- package/dist/animation/motion.js.map +1 -1
- package/dist/animation/reveal.cjs.map +1 -1
- package/dist/animation/reveal.js +97 -1
- package/dist/animation/reveal.js.map +1 -1
- package/dist/animation/transition.cjs.map +1 -1
- package/dist/animation/transition.js +39 -1
- package/dist/animation/transition.js.map +1 -1
- package/dist/animation/tween.cjs.map +1 -1
- package/dist/animation/tween.js +7 -1
- package/dist/animation/tween.js.map +1 -1
- package/dist/axes/axis.cjs.map +1 -1
- package/dist/axes/axis.js +76 -1
- package/dist/axes/axis.js.map +1 -1
- package/dist/axes/grid.cjs.map +1 -1
- package/dist/axes/grid.js +29 -1
- package/dist/axes/grid.js.map +1 -1
- package/dist/axes/scale-utils.cjs.map +1 -1
- package/dist/axes/scale-utils.js +10 -1
- package/dist/axes/scale-utils.js.map +1 -1
- package/dist/charts/area/area-chart.cjs.map +1 -1
- package/dist/charts/area/area-chart.js +71 -1
- package/dist/charts/area/area-chart.js.map +1 -1
- package/dist/charts/area/area-renderer.cjs.map +1 -1
- package/dist/charts/area/area-renderer.js +128 -1
- package/dist/charts/area/area-renderer.js.map +1 -1
- package/dist/charts/bar/bar-chart.cjs.map +1 -1
- package/dist/charts/bar/bar-chart.js +228 -1
- package/dist/charts/bar/bar-chart.js.map +1 -1
- package/dist/charts/bar/bar-hit-test.cjs.map +1 -1
- package/dist/charts/bar/bar-hit-test.js +25 -1
- package/dist/charts/bar/bar-hit-test.js.map +1 -1
- package/dist/charts/bar/bar-renderer.cjs.map +1 -1
- package/dist/charts/bar/bar-renderer.js +139 -1
- package/dist/charts/bar/bar-renderer.js.map +1 -1
- package/dist/charts/line/line-chart.cjs.map +1 -1
- package/dist/charts/line/line-chart.js +93 -1
- package/dist/charts/line/line-chart.js.map +1 -1
- package/dist/charts/line/line-renderer.cjs.map +1 -1
- package/dist/charts/line/line-renderer.js +143 -1
- package/dist/charts/line/line-renderer.js.map +1 -1
- package/dist/charts/pie/pie-chart.cjs +1 -1
- package/dist/charts/pie/pie-chart.cjs.map +1 -1
- package/dist/charts/pie/pie-chart.js +207 -1
- package/dist/charts/pie/pie-chart.js.map +1 -1
- package/dist/charts/pie/pie-renderer.cjs.map +1 -1
- package/dist/charts/pie/pie-renderer.js +68 -1
- package/dist/charts/pie/pie-renderer.js.map +1 -1
- package/dist/charts/radar/radar-chart.cjs +1 -1
- package/dist/charts/radar/radar-chart.cjs.map +1 -1
- package/dist/charts/radar/radar-chart.js +281 -1
- package/dist/charts/radar/radar-chart.js.map +1 -1
- package/dist/charts/radar/radar-geometry.cjs.map +1 -1
- package/dist/charts/radar/radar-geometry.js +69 -1
- package/dist/charts/radar/radar-geometry.js.map +1 -1
- package/dist/charts/scatter/scatter-chart.cjs.map +1 -1
- package/dist/charts/scatter/scatter-chart.js +69 -1
- package/dist/charts/scatter/scatter-chart.js.map +1 -1
- package/dist/charts/scatter/scatter-renderer.cjs.map +1 -1
- package/dist/charts/scatter/scatter-renderer.js +57 -1
- package/dist/charts/scatter/scatter-renderer.js.map +1 -1
- package/dist/charts/sparkline/sparkline.cjs +1 -1
- package/dist/charts/sparkline/sparkline.cjs.map +1 -1
- package/dist/charts/sparkline/sparkline.js +251 -1
- package/dist/charts/sparkline/sparkline.js.map +1 -1
- package/dist/core/cartesian-model.cjs +1 -1
- package/dist/core/cartesian-model.cjs.map +1 -1
- package/dist/core/cartesian-model.js +26 -1
- package/dist/core/cartesian-model.js.map +1 -1
- package/dist/core/cartesian-scales.cjs.map +1 -1
- package/dist/core/cartesian-scales.js +38 -1
- package/dist/core/cartesian-scales.js.map +1 -1
- package/dist/core/chart-base.cjs.map +1 -1
- package/dist/core/chart-base.js +62 -1
- package/dist/core/chart-base.js.map +1 -1
- package/dist/core/chart-scaffold.cjs.map +1 -1
- package/dist/core/chart-scaffold.js +103 -1
- package/dist/core/chart-scaffold.js.map +1 -1
- package/dist/core/datum-style.cjs +1 -1
- package/dist/core/datum-style.cjs.map +1 -1
- package/dist/core/datum-style.js +22 -1
- package/dist/core/datum-style.js.map +1 -1
- package/dist/core/ids.cjs.map +1 -1
- package/dist/core/ids.js +8 -1
- package/dist/core/ids.js.map +1 -1
- package/dist/core/layout.cjs.map +1 -1
- package/dist/core/layout.js +22 -1
- package/dist/core/layout.js.map +1 -1
- package/dist/core/polar.cjs.map +1 -1
- package/dist/core/polar.js +13 -1
- package/dist/core/polar.js.map +1 -1
- package/dist/core/responsive.cjs.map +1 -1
- package/dist/core/responsive.js +20 -1
- package/dist/core/responsive.js.map +1 -1
- package/dist/core/series-id.cjs.map +1 -1
- package/dist/core/series-id.js +7 -1
- package/dist/core/series-id.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +9 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +13 -1
- package/dist/interaction/announcer.cjs.map +1 -1
- package/dist/interaction/announcer.js +25 -1
- package/dist/interaction/announcer.js.map +1 -1
- package/dist/interaction/crosshair.cjs.map +1 -1
- package/dist/interaction/crosshair.js +37 -1
- package/dist/interaction/crosshair.js.map +1 -1
- package/dist/interaction/events.cjs.map +1 -1
- package/dist/interaction/events.js +11 -1
- package/dist/interaction/events.js.map +1 -1
- package/dist/interaction/legend.cjs.map +1 -1
- package/dist/interaction/legend.js +31 -1
- package/dist/interaction/legend.js.map +1 -1
- package/dist/interaction/scatter-interaction.cjs.map +1 -1
- package/dist/interaction/scatter-interaction.js +105 -1
- package/dist/interaction/scatter-interaction.js.map +1 -1
- package/dist/interaction/series-interaction.cjs.map +1 -1
- package/dist/interaction/series-interaction.js +163 -1
- package/dist/interaction/series-interaction.js.map +1 -1
- package/dist/interaction/tooltip.cjs +1 -1
- package/dist/interaction/tooltip.cjs.map +1 -1
- package/dist/interaction/tooltip.js +87 -1
- package/dist/interaction/tooltip.js.map +1 -1
- package/dist/prism.cjs +1 -1
- package/dist/prism.cjs.map +1 -1
- package/dist/prism.iife.js +1 -1
- package/dist/prism.iife.js.map +1 -1
- package/dist/prism.js +2930 -1
- package/dist/prism.js.map +1 -1
- package/dist/scales/band.cjs.map +1 -1
- package/dist/scales/band.js +39 -1
- package/dist/scales/band.js.map +1 -1
- package/dist/scales/linear.cjs.map +1 -1
- package/dist/scales/linear.js +43 -1
- package/dist/scales/linear.js.map +1 -1
- package/dist/scales/time.cjs.map +1 -1
- package/dist/scales/time.js +61 -1
- package/dist/scales/time.js.map +1 -1
- package/dist/svg/element.cjs +1 -1
- package/dist/svg/element.cjs.map +1 -1
- package/dist/svg/element.js +16 -1
- package/dist/svg/element.js.map +1 -1
- package/dist/svg/path.cjs.map +1 -1
- package/dist/svg/path.js +48 -1
- package/dist/svg/path.js.map +1 -1
- package/dist/svg/text.cjs.map +1 -1
- package/dist/svg/text.js +13 -1
- package/dist/svg/text.js.map +1 -1
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.js +37 -1
- package/dist/theme/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.js","names":[],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea, resolveMargin } from '../../core/layout';\nimport { seriesDomId } from '../../core/series-id';\nimport { createCrosshair } from '../../interaction/crosshair';\nimport { createSeriesInteraction, ensureMarkerGroup } from '../../interaction/series-interaction';\nimport { createSvgElement } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, LineChartConfig, LineSeriesConfig, XAxisConfig, YAxisConfig } from '../../types';\nimport { computePoints, renderLine } from './line-renderer';\n\nexport function createLineChart(container: HTMLElement, config: LineChartConfig): ChartHandle<LineSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: SVGGElement | null = null;\n let rightAxis: SVGGElement | null = null;\n let seriesList = config.series;\n\n return createChartScaffold(\n container,\n config,\n (ctx, reason) => {\n const { groups, legend, tooltip } = ctx;\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\n const hasRight = seriesList.some((series) => series.yAxis === 'right');\n const hasLeftData = seriesList.some((series) => series.yAxis !== 'right' && series.data.length > 0);\n // The right axis widens the right margin; the effective margin stays local to this\n // render pass (and is handed to the interaction layer) instead of mutating shared dims.\n const margin = {\n ...resolveMargin(config.margin),\n right:\n config.margin?.right ??\n (hasRight ? (config.rightYAxis?.label ? 72 : 50) : resolveMargin(config.margin).right),\n };\n const area = chartArea(dims.width, dims.height, margin);\n const allData = seriesList.map((series) => series.data);\n const allX = allData.flat().map((datum) => datum.key);\n const leftY = seriesList\n .filter((series) => series.yAxis !== 'right')\n .flatMap((series) => series.data.map((datum) => datum.value));\n const rightY = seriesList\n .filter((series) => series.yAxis === 'right')\n .flatMap((series) => series.data.map((datum) => datum.value));\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.replaceChildren();\n rightAxis?.replaceChildren();\n\n return;\n }\n\n if (config.crosshair && !crosshair) {\n crosshair = createCrosshair(ctx.chartArea, config.crosshair);\n }\n\n const xScale = buildXScale(allX, area.width);\n const yScale = buildYScale(leftY, area.height);\n const rightYScale = buildYScale(rightY, area.height);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n } else {\n groups.grid.replaceChildren();\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig && (!hasRight || hasLeftData)) {\n const axis = { ...yAxisConfig, position: hasRight ? ('left' as const) : (yAxisConfig.position ?? 'left') };\n positionAxis(groups.yAxis, axis.position, area.width, area.height);\n renderAxis(groups.yAxis, yScale, axis, area.height, 'left');\n } else {\n groups.yAxis.replaceChildren();\n }\n\n if (hasRight) {\n if (!rightAxis) {\n rightAxis = createSvgElement('g', { class: 'prism-y-axis-right' });\n ctx.chartArea.appendChild(rightAxis);\n }\n const axis = { ...config.rightYAxis, position: 'right' as const };\n positionAxis(rightAxis, 'right', area.width, area.height);\n renderAxis(rightAxis, rightYScale, axis, area.height, 'right');\n } else {\n rightAxis?.replaceChildren();\n }\n\n while (groups.series.children.length > seriesList.length) {\n groups.series.removeChild(groups.series.lastChild!);\n }\n\n const allPoints: Point[][] = [];\n\n for (let i = 0; i < seriesList.length; i++) {\n const series = seriesList[i];\n let group = groups.series.children[i] as SVGGElement | undefined;\n\n if (!group) {\n group = createSvgElement('g', { class: 'prism-line-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const seriesScale = series.yAxis === 'right' ? rightYScale : yScale;\n const points = computePoints(allData[i], xScale, seriesScale);\n\n allPoints.push(points);\n\n renderLine(group, points, {\n bounds: { height: area.height, width: area.width },\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n marks: series.data,\n pointRadius: series.pointRadius ?? 3,\n showPoints: series.showPoints ?? false,\n strokeWidth: series.strokeWidth,\n transition: reason === 'resize' ? false : config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.js","names":["crosshair","markers","rightAxis","seriesList","config","createChartScaffold","container","ctx","seriesColor","i","s","dims","hasRight","series","hasLeftData","margin","resolveMargin","area","chartArea","allData","allX","datum","leftY","rightY","clearCartesianDom","groups","legend","tooltip","createCrosshair","xScale","buildXScale","yScale","buildYScale","rightYScale","xAxisConfig","yAxisConfig","renderGrid","resolveTicks","resolveTickCount","positionAxis","renderAxis","axis","createSvgElement","allPoints","group","seriesDomId","seriesScale","points","computePoints","renderLine","reason","ensureMarkerGroup","createSeriesInteraction","data"],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea, resolveMargin } from '../../core/layout';\nimport { seriesDomId } from '../../core/series-id';\nimport { createCrosshair } from '../../interaction/crosshair';\nimport { createSeriesInteraction, ensureMarkerGroup } from '../../interaction/series-interaction';\nimport { createSvgElement } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, LineChartConfig, LineSeriesConfig, XAxisConfig, YAxisConfig } from '../../types';\nimport { computePoints, renderLine } from './line-renderer';\n\nexport function createLineChart(container: HTMLElement, config: LineChartConfig): ChartHandle<LineSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: SVGGElement | null = null;\n let rightAxis: SVGGElement | null = null;\n let seriesList = config.series;\n\n return createChartScaffold(\n container,\n config,\n (ctx, reason) => {\n const { groups, legend, tooltip } = ctx;\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\n const hasRight = seriesList.some((series) => series.yAxis === 'right');\n const hasLeftData = seriesList.some((series) => series.yAxis !== 'right' && series.data.length > 0);\n // The right axis widens the right margin; the effective margin stays local to this\n // render pass (and is handed to the interaction layer) instead of mutating shared dims.\n const margin = {\n ...resolveMargin(config.margin),\n right:\n config.margin?.right ??\n (hasRight ? (config.rightYAxis?.label ? 72 : 50) : resolveMargin(config.margin).right),\n };\n const area = chartArea(dims.width, dims.height, margin);\n const allData = seriesList.map((series) => series.data);\n const allX = allData.flat().map((datum) => datum.key);\n const leftY = seriesList\n .filter((series) => series.yAxis !== 'right')\n .flatMap((series) => series.data.map((datum) => datum.value));\n const rightY = seriesList\n .filter((series) => series.yAxis === 'right')\n .flatMap((series) => series.data.map((datum) => datum.value));\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.replaceChildren();\n rightAxis?.replaceChildren();\n\n return;\n }\n\n if (config.crosshair && !crosshair) {\n crosshair = createCrosshair(ctx.chartArea, config.crosshair);\n }\n\n const xScale = buildXScale(allX, area.width);\n const yScale = buildYScale(leftY, area.height);\n const rightYScale = buildYScale(rightY, area.height);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n } else {\n groups.grid.replaceChildren();\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig && (!hasRight || hasLeftData)) {\n const axis = { ...yAxisConfig, position: hasRight ? ('left' as const) : (yAxisConfig.position ?? 'left') };\n positionAxis(groups.yAxis, axis.position, area.width, area.height);\n renderAxis(groups.yAxis, yScale, axis, area.height, 'left');\n } else {\n groups.yAxis.replaceChildren();\n }\n\n if (hasRight) {\n if (!rightAxis) {\n rightAxis = createSvgElement('g', { class: 'prism-y-axis-right' });\n ctx.chartArea.appendChild(rightAxis);\n }\n const axis = { ...config.rightYAxis, position: 'right' as const };\n positionAxis(rightAxis, 'right', area.width, area.height);\n renderAxis(rightAxis, rightYScale, axis, area.height, 'right');\n } else {\n rightAxis?.replaceChildren();\n }\n\n while (groups.series.children.length > seriesList.length) {\n groups.series.removeChild(groups.series.lastChild!);\n }\n\n const allPoints: Point[][] = [];\n\n for (let i = 0; i < seriesList.length; i++) {\n const series = seriesList[i];\n let group = groups.series.children[i] as SVGGElement | undefined;\n\n if (!group) {\n group = createSvgElement('g', { class: 'prism-line-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const seriesScale = series.yAxis === 'right' ? rightYScale : yScale;\n const points = computePoints(allData[i], xScale, seriesScale);\n\n allPoints.push(points);\n\n renderLine(group, points, {\n bounds: { height: area.height, width: area.width },\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n marks: series.data,\n pointRadius: series.pointRadius ?? 3,\n showPoints: series.showPoints ?? false,\n strokeWidth: series.strokeWidth,\n transition: reason === 'resize' ? false : config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-renderer.cjs","names":[],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"sVA4BA,IAAM,EAAmB,IAAI,QAGvB,EAAc,IAAI,QAExB,SAAS,UAAU,EAAc,EAA2C,CAC1E,OAAO,IAAU,WAAa,EAAA,aAAa,CAAG,EAAI,IAAU,OAAS,EAAA,SAAS,CAAG,EAAI,EAAA,SAAS,CAAG,CACnG,CAEA,SAAgB,WAAW,EAAqB,EAAiB,EAAkC,CACjG,IAAM,EAAS,EAAA,cAAc,EAAQ,KAAK,EACpC,EAAQ,EAAQ,OAAS,CAAC,EAC1B,EAAS,EAAA,cAAc,EAAQ,UAAU,EACzC,EAAM,EAAO,SACb,EAAS,EAAA,cAAc,EAAO,MAAM,EAEtC,EAA8B,KAC9B,EAA4B,CAAC,EAC7B,EAA6B,CAAC,EAElC,GAAI,EAAQ,CACV,EAAO,EAAA,iBAAiB,EAAO,EAAO,MAAM,EAE5C,IAAM,EAAW,CAAC,GAAG,EAAO,iBAAiC,kBAAkB,CAAC,EAEhF,IAAK,IAAM,KAAS,EAAS,MAAM,EAAK,MAAM,EAAG,EAAM,OAAO,EAE9D,EAAW,EAAK,KAAK,EAAG,IAAM,CAC5B,IAAM,EAAQ,EAAS,GAEvB,GAAI,EAAO,OAAO,EAElB,IAAM,EAAU,EAAA,iBAAiB,OAAQ,CAAE,MAAO,kBAAmB,KAAM,MAAO,CAAC,EAInF,OAFA,EAAO,YAAY,CAAO,EAEnB,CACT,CAAC,EAED,IAAK,GAAM,CAAC,EAAG,KAAQ,EAAK,QAAQ,EAClC,EAAA,cAAc,EAAS,GAAI,CACzB,QAAS,EAAI,QACb,OAAQ,EAAQ,MAChB,mBAAoB,EAAI,KACxB,eAAgB,EAAQ,aAAe,CACzC,CAAC,EACD,EAAS,EAAE,CAAC,MAAM,YAAc,EAAQ,cAAgB,IAAA,GAAY,GAAK,OAAO,EAAQ,WAAW,CAEvG,KAAO,CACL,IAAM,EAAW,CAAC,GAAG,EAAO,iBAAiC,kBAAkB,CAAC,EAEhF,EAAO,EAAS,IAAM,KAEtB,IAAK,IAAM,KAAS,EAAS,MAAM,CAAC,EAAG,EAAM,OAAO,EAE/C,IACH,EAAO,EAAA,iBAAiB,OAAQ,CAAE,MAAO,kBAAmB,KAAM,MAAO,CAAC,EAC1E,EAAO,YAAY,CAAI,GAGzB,EAAA,cAAc,EAAM,CAClB,QAAS,IAAA,GACT,OAAQ,EAAQ,MAChB,mBAAoB,IAAA,GACpB,eAAgB,EAAQ,aAAe,CACzC,CAAC,EACD,EAAK,MAAM,YAAc,EAAQ,cAAgB,IAAA,GAAY,GAAK,OAAO,EAAQ,WAAW,CAC9F,CAEA,IAAM,KAAQ,GAAuB,CACnC,GAAI,EACF,IAAK,GAAM,CAAC,EAAG,KAAQ,EAAK,QAAQ,EAClC,EAAA,cAAc,EAAS,GAAI,CAAE,EAAG,UAAU,EAAI,MAAM,EAAI,MAAO,EAAI,IAAM,CAAC,EAAG,EAAQ,KAAK,CAAE,CAAC,OAG/F,EAAA,cAAc,EAAO,CAAE,EAAG,UAAU,EAAK,EAAQ,KAAK,CAAE,CAAC,CAE7D,EAEI,EAAY,EAAO,cAA2B,kBAAkB,EAYpE,GAVI,EAAQ,WACL,IACH,EAAY,EAAA,iBAAiB,IAAK,CAAE,MAAO,iBAAkB,CAAC,EAC9D,EAAO,YAAY,CAAS,GAEzB,AAEL,KADA,EAAU,OAAO,EACL,MAGV,IAAQ,EAAG,CAMb,GALA,EAAiB,IAAI,CAAM,CAAC,GAAG,EAC/B,EAAA,aAAa,CAAM,EACnB,KAAK,CAAM,EACX,EAAY,IAAI,EAAQ,CAAM,EAE1B,EAAW,CACb,KAAO,EAAU,SAAS,OAAS,EAAO,QAAQ,EAAU,YAAY,EAAU,SAAU,EAE5F,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,IAAI,EAAI,EAAU,SAAS,GAEtB,IACH,EAAI,EAAA,iBAAiB,SAAU,CAAE,MAAO,gBAAiB,CAAC,EAC1D,EAAU,YAAY,CAAC,GAGzB,EAAA,cAAc,EAAG,CACf,GAAI,EAAO,EAAE,CAAC,EACd,GAAI,EAAO,EAAE,CAAC,EACd,KAAM,EAAQ,MACd,QAAS,EAAM,EAAE,EAAE,QACnB,EAAG,EAAQ,WACb,CAAC,CACH,CACF,CAEA,MACF,CAEA,EAAiB,IAAI,CAAM,CAAC,GAAG,EAC/B,EAAA,aAAa,CAAM,EAEnB,IAAM,EAAU,CAAC,EAAY,IAAI,CAAM,EAEvC,GAAI,EAAW,CACb,KAAO,EAAU,SAAS,OAAS,EAAO,QAAQ,EAAU,YAAY,EAAU,SAAU,EAE5F,IAAK,IAAI,EAAI,EAAU,SAAS,OAAQ,EAAI,EAAO,OAAQ,IAAK,CAC9D,IAAM,EAAI,EAAA,iBAAiB,SAAU,CAAE,MAAO,gBAAiB,CAAC,EAEhE,EAAA,cAAc,EAAG,CACf,KAAM,EAAQ,MACd,QAAS,EAAM,EAAE,EAAE,QACnB,EAAG,EAAQ,WACb,CAAC,EACD,EAAU,YAAY,CAAC,CACzB,CAEA,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,SAAS,OAAQ,IAC7C,EAAA,cAAc,EAAU,SAAS,GAAwB,CAAE,QAAS,EAAM,EAAE,EAAE,OAAQ,CAAC,CAE3F,CAEA,GAAI,EAAS,CAIX,GAHA,KAAK,CAAM,EACX,EAAY,IAAI,EAAQ,CAAM,EAE1B,EACF,IAAK,GAAM,CAAC,EAAG,KAAU,EAAO,QAAQ,EAAG,CACzC,IAAM,EAAI,EAAU,SAAS,GAEzB,GAAG,EAAA,cAAc,EAAG,CAAE,GAAI,EAAM,EAAG,GAAI,EAAM,CAAE,CAAC,CACtD,CAGF,GAAI,EAAO,OAAS,EAAG,CACrB,IAAM,EAAe,GAAQ,EAAS,GAChC,EAAc,EAAQ,cAAgB,OAAO,WAAW,iBAAiB,CAAY,CAAC,CAAC,WAAW,GAAK,GACvG,EAAS,EACX,EAAK,KAAK,EAAK,KAAO,CACpB,EAAG,EAAS,EAAE,CAAC,aAAa,GAAG,EAC/B,IAAK,EAAI,KAAO,EAAO,OAAS,GAChC,MAAO,EAAI,OAAS,EAAO,OAAS,EACtC,EAAE,EACF,CAAC,CAAE,EAAG,EAAM,aAAa,GAAG,EAAI,IAAK,EAAG,MAAO,CAAE,CAAC,EAGtD,EAAA,gBACE,EACA,EAAQ,OACR,EACA,KAAK,IAAI,EAAa,EAAQ,WAAa,EAAQ,YAAc,EAAI,CAAC,EAAI,EAC1E,EAAA,cAAc,EAAQ,WAAY,CAAE,gBAAiB,GAAI,CAAC,EAC1D,EAAQ,cACV,CACF,CAEA,MACF,CAEA,IAAM,EAAmB,CAAC,EACpB,EAAQ,EAAY,IAAI,CAAM,GAAK,EAEzC,IAAK,GAAM,CAAC,EAAG,KAAO,EAAO,QAAQ,EACnC,EAAQ,KAAK,EAAM,IAAM,EAAM,GAAG,EAAE,GAAK,CAAE,EAG7C,IAAM,WAAc,GAAoB,CACtC,IAAM,EAAwB,EAAO,KAAK,EAAI,IAAM,CAClD,IAAM,EAAO,EAAQ,IAAM,EAE3B,MAAO,CAAE,EAAG,EAAA,YAAY,EAAK,EAAG,EAAG,EAAG,CAAC,EAAG,EAAG,EAAA,YAAY,EAAK,EAAG,EAAG,EAAG,CAAC,CAAE,CAC5E,CAAC,EAKD,GAHA,EAAY,IAAI,EAAQ,CAAY,EACpC,KAAK,CAAY,EAEb,EACF,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,IAAM,EAAI,EAAU,SAAS,GAEzB,GAAG,EAAA,cAAc,EAAG,CAAE,GAAI,EAAa,EAAE,CAAC,EAAG,GAAI,EAAa,EAAE,CAAC,CAAE,CAAC,CAC1E,CAEJ,EAIA,WAAW,CAAC,EAEZ,EAAiB,IACf,EACA,EAAA,WAAW,CACT,MAAO,EACP,SAAU,EACV,SACA,eAAkB,CAChB,EAAiB,OAAO,CAAM,EAC9B,EAAY,IAAI,EAAQ,CAAM,CAChC,EACA,QAAU,GAAa,WAAW,EAAS,CAAC,CAAC,EAC7C,OAAQ,EAAQ,cAClB,CAAC,CACH,CACF,CAEA,SAAgB,cAAc,EAAyB,EAA8B,EAAgC,CASnH,OARI,EAAK,KAAM,GAAM,EAAE,KAAO,IAAI,GAIvB,EAAK,KAAM,GAAM,OAAO,EAAE,KAAQ,QAAQ,EAI9C,EAAK,IAAK,IAAO,CACtB,EAAG,EAAO,IAAI,EAAE,GAAoB,EACpC,EAAG,EAAO,IAAI,EAAE,KAAK,CACvB,EAAE,CACJ"}
|
|
1
|
+
{"version":3,"file":"line-renderer.cjs","names":["monotonePath","stepPath","linePath","hasStyledRuns","resolveMotion","resolveEasing","computeStyleRuns","createSvgElement","tweenNumber","startTween","require_element","require_easing","require_motion","require_tween","require_transition","require_datum_style","require_path","require_reveal","activeAnimations","drawnPoints","curve","pts","styled","options","marks","motion","dur","easing","path","runs","runPaths","points","existing","parent","extra","reuse","created","r","run","stale","dotsGroup","i","c","isMount","point","renderedPath","strokeWidth","traces","fromPts","drawn","to","interpolated","from","e","progress","data","d","xScale","yScale"],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,144 @@
|
|
|
1
|
-
import"../../_dev.js";
|
|
1
|
+
import "../../_dev.js";
|
|
2
|
+
import { createSvgElement as e, setAttributes as t } from "../../svg/element.js";
|
|
3
|
+
import { resolveEasing as n } from "../../animation/easing.js";
|
|
4
|
+
import { resolveMotion as r } from "../../animation/motion.js";
|
|
5
|
+
import { tweenNumber as i } from "../../animation/tween.js";
|
|
6
|
+
import { startTween as a } from "../../animation/transition.js";
|
|
7
|
+
import { computeStyleRuns as o, hasStyledRuns as s } from "../../core/datum-style.js";
|
|
8
|
+
import { linePath as c, monotonePath as l, stepPath as u } from "../../svg/path.js";
|
|
9
|
+
import { cancelReveal as d, playTraceReveal as f } from "../../animation/reveal.js";
|
|
10
|
+
//#region src/charts/line/line-renderer.ts
|
|
11
|
+
var p = /* @__PURE__ */ new WeakMap(), m = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
function buildPath(e, t) {
|
|
13
|
+
return t === "monotone" ? l(e) : t === "step" ? u(e) : c(e);
|
|
14
|
+
}
|
|
15
|
+
function renderLine(c, l, u) {
|
|
16
|
+
let h = s(u.marks), g = u.marks ?? [], _ = r(u.transition), v = _.duration, y = n(_.easing), b = null, x = [], S = [];
|
|
17
|
+
if (h) {
|
|
18
|
+
x = o(g, l.length);
|
|
19
|
+
let n = [...c.querySelectorAll(".prism-line-path")];
|
|
20
|
+
for (let e of n.slice(x.length)) e.remove();
|
|
21
|
+
S = x.map((t, r) => {
|
|
22
|
+
let i = n[r];
|
|
23
|
+
if (i) return i;
|
|
24
|
+
let a = e("path", {
|
|
25
|
+
class: "prism-line-path",
|
|
26
|
+
fill: "none"
|
|
27
|
+
});
|
|
28
|
+
return c.appendChild(a), a;
|
|
29
|
+
});
|
|
30
|
+
for (let [e, n] of x.entries()) t(S[e], {
|
|
31
|
+
opacity: n.opacity,
|
|
32
|
+
stroke: u.color,
|
|
33
|
+
"stroke-dasharray": n.dash,
|
|
34
|
+
"stroke-width": u.strokeWidth ?? 2
|
|
35
|
+
}), S[e].style.strokeWidth = u.strokeWidth === void 0 ? "" : String(u.strokeWidth);
|
|
36
|
+
} else {
|
|
37
|
+
let n = [...c.querySelectorAll(".prism-line-path")];
|
|
38
|
+
b = n[0] ?? null;
|
|
39
|
+
for (let e of n.slice(1)) e.remove();
|
|
40
|
+
b || (b = e("path", {
|
|
41
|
+
class: "prism-line-path",
|
|
42
|
+
fill: "none"
|
|
43
|
+
}), c.appendChild(b)), t(b, {
|
|
44
|
+
opacity: void 0,
|
|
45
|
+
stroke: u.color,
|
|
46
|
+
"stroke-dasharray": void 0,
|
|
47
|
+
"stroke-width": u.strokeWidth ?? 2
|
|
48
|
+
}), b.style.strokeWidth = u.strokeWidth === void 0 ? "" : String(u.strokeWidth);
|
|
49
|
+
}
|
|
50
|
+
let draw = (e) => {
|
|
51
|
+
if (h) for (let [n, r] of x.entries()) t(S[n], { d: buildPath(e.slice(r.start, r.end + 1), u.curve) });
|
|
52
|
+
else t(b, { d: buildPath(e, u.curve) });
|
|
53
|
+
}, C = c.querySelector(".prism-line-dots");
|
|
54
|
+
if (u.showPoints ? C || (C = e("g", { class: "prism-line-dots" }), c.appendChild(C)) : C &&= (C.remove(), null), v === 0) {
|
|
55
|
+
if (p.get(c)?.(), d(c), draw(l), m.set(c, l), C) {
|
|
56
|
+
for (; C.children.length > l.length;) C.removeChild(C.lastChild);
|
|
57
|
+
for (let n = 0; n < l.length; n++) {
|
|
58
|
+
let r = C.children[n];
|
|
59
|
+
r || (r = e("circle", { class: "prism-line-dot" }), C.appendChild(r)), t(r, {
|
|
60
|
+
cx: l[n].x,
|
|
61
|
+
cy: l[n].y,
|
|
62
|
+
fill: u.color,
|
|
63
|
+
opacity: g[n]?.opacity,
|
|
64
|
+
r: u.pointRadius
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
p.get(c)?.(), d(c);
|
|
71
|
+
let w = !m.has(c);
|
|
72
|
+
if (C) {
|
|
73
|
+
for (; C.children.length > l.length;) C.removeChild(C.lastChild);
|
|
74
|
+
for (let n = C.children.length; n < l.length; n++) {
|
|
75
|
+
let r = e("circle", { class: "prism-line-dot" });
|
|
76
|
+
t(r, {
|
|
77
|
+
fill: u.color,
|
|
78
|
+
opacity: g[n]?.opacity,
|
|
79
|
+
r: u.pointRadius
|
|
80
|
+
}), C.appendChild(r);
|
|
81
|
+
}
|
|
82
|
+
for (let e = 0; e < C.children.length; e++) t(C.children[e], { opacity: g[e]?.opacity });
|
|
83
|
+
}
|
|
84
|
+
if (w) {
|
|
85
|
+
if (draw(l), m.set(c, l), C) for (let [e, n] of l.entries()) {
|
|
86
|
+
let r = C.children[e];
|
|
87
|
+
r && t(r, {
|
|
88
|
+
cx: n.x,
|
|
89
|
+
cy: n.y
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (l.length > 1) {
|
|
93
|
+
let e = b ?? S[0], t = u.strokeWidth ?? (Number.parseFloat(getComputedStyle(e).strokeWidth) || 2), n = h ? x.map((e, t) => ({
|
|
94
|
+
d: S[t].getAttribute("d"),
|
|
95
|
+
end: e.end / (l.length - 1),
|
|
96
|
+
start: e.start / (l.length - 1)
|
|
97
|
+
})) : [{
|
|
98
|
+
d: b.getAttribute("d"),
|
|
99
|
+
end: 1,
|
|
100
|
+
start: 0
|
|
101
|
+
}];
|
|
102
|
+
f(c, u.bounds, n, Math.max(t, u.showPoints ? u.pointRadius * 2 : 0) + 2, r(u.transition, { defaultDuration: 420 }), u.disposalSignal);
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
let T = [], E = m.get(c) ?? l;
|
|
107
|
+
for (let [e, t] of l.entries()) T.push(E[e] ?? E.at(-1) ?? t);
|
|
108
|
+
let paintFrame = (e) => {
|
|
109
|
+
let n = l.map((t, n) => {
|
|
110
|
+
let r = T[n] ?? t;
|
|
111
|
+
return {
|
|
112
|
+
x: i(r.x, t.x, e),
|
|
113
|
+
y: i(r.y, t.y, e)
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
if (m.set(c, n), draw(n), C) for (let e = 0; e < l.length; e++) {
|
|
117
|
+
let r = C.children[e];
|
|
118
|
+
r && t(r, {
|
|
119
|
+
cx: n[e].x,
|
|
120
|
+
cy: n[e].y
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
paintFrame(0), p.set(c, a({
|
|
125
|
+
count: 1,
|
|
126
|
+
duration: v,
|
|
127
|
+
easing: y,
|
|
128
|
+
onComplete: () => {
|
|
129
|
+
p.delete(c), m.set(c, l);
|
|
130
|
+
},
|
|
131
|
+
onFrame: (e) => paintFrame(e(0)),
|
|
132
|
+
signal: u.disposalSignal
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
function computePoints(e, t, n) {
|
|
136
|
+
return e.some((e) => e.key == null) || e.some((e) => typeof e.key == "string"), e.map((e) => ({
|
|
137
|
+
x: t.map(e.key),
|
|
138
|
+
y: n.map(e.value)
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { computePoints, renderLine };
|
|
143
|
+
|
|
2
144
|
//# sourceMappingURL=line-renderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-renderer.js","names":[],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-renderer.js","names":["activeAnimations","drawnPoints","curve","monotonePath","pts","stepPath","linePath","styled","hasStyledRuns","options","marks","motion","resolveMotion","dur","easing","resolveEasing","path","runs","runPaths","computeStyleRuns","points","existing","parent","extra","reuse","created","createSvgElement","r","run","setAttributes","stale","dotsGroup","cancelReveal","i","c","isMount","point","renderedPath","strokeWidth","traces","fromPts","drawn","to","interpolated","from","tweenNumber","startTween","progress","data","d","xScale","yScale"],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { cancelReveal, playTraceReveal } from '../../animation/reveal';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport { computeStyleRuns, type DatumMark, hasStyledRuns, type StyleRun } from '../../core/datum-style';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface LineRenderOptions {\n /** Plot-area size in area-local coordinates: bounds the entrance mask. */\n bounds: { height: number; width: number };\n color: string;\n curve: 'linear' | 'monotone' | 'step';\n /** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */\n disposalSignal?: AbortSignal;\n /** Per-datum presentation parallel to `points`; styled runs split the line into subpaths. */\n marks?: readonly DatumMark[];\n pointRadius: number;\n showPoints: boolean;\n /** Explicit width beats the `--prism-line-width` theme token. */\n strokeWidth?: number;\n transition?: TransitionOption;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\n// Geometry currently on screen, so an update interpolates from it even when the\n// series hides its point markers (the dots would otherwise be the only record).\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildPath(pts: Point[], curve: LineRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\nexport function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void {\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let path: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let runPaths: SVGPathElement[] = [];\n\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n runPaths = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n runPaths[r].style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-line-path')];\n\n path = existing[0] ?? null;\n\n for (const stale of existing.slice(1)) stale.remove();\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-line-path', fill: 'none' });\n parent.appendChild(path);\n }\n\n setAttributes(path, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': options.strokeWidth ?? 2,\n });\n path.style.strokeWidth = options.strokeWidth === undefined ? '' : String(options.strokeWidth);\n }\n\n const draw = (pts: Point[]): void => {\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(runPaths[r], { d: buildPath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else {\n setAttributes(path!, { d: buildPath(pts, options.curve) });\n }\n };\n\n let dotsGroup = parent.querySelector<SVGGElement>('.prism-line-dots');\n\n if (options.showPoints) {\n if (!dotsGroup) {\n dotsGroup = createSvgElement('g', { class: 'prism-line-dots' });\n parent.appendChild(dotsGroup);\n }\n } else if (dotsGroup) {\n dotsGroup.remove();\n dotsGroup = null;\n }\n\n if (dur === 0) {\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = 0; i < points.length; i++) {\n let c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (!c) {\n c = createSvgElement('circle', { class: 'prism-line-dot' });\n dotsGroup.appendChild(c);\n }\n\n setAttributes(c, {\n cx: points[i].x,\n cy: points[i].y,\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n }\n }\n\n return;\n }\n\n activeAnimations.get(parent)?.();\n cancelReveal(parent);\n\n const isMount = !drawnPoints.has(parent);\n\n if (dotsGroup) {\n while (dotsGroup.children.length > points.length) dotsGroup.removeChild(dotsGroup.lastChild!);\n\n for (let i = dotsGroup.children.length; i < points.length; i++) {\n const c = createSvgElement('circle', { class: 'prism-line-dot' });\n\n setAttributes(c, {\n fill: options.color,\n opacity: marks[i]?.opacity,\n r: options.pointRadius,\n });\n dotsGroup.appendChild(c);\n }\n\n for (let i = 0; i < dotsGroup.children.length; i++) {\n setAttributes(dotsGroup.children[i] as SVGCircleElement, { opacity: marks[i]?.opacity });\n }\n }\n\n if (isMount) {\n draw(points);\n drawnPoints.set(parent, points);\n\n if (dotsGroup) {\n for (const [i, point] of points.entries()) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: point.x, cy: point.y });\n }\n }\n\n if (points.length > 1) {\n const renderedPath = path ?? runPaths[0];\n const strokeWidth = options.strokeWidth ?? (Number.parseFloat(getComputedStyle(renderedPath).strokeWidth) || 2);\n const traces = styled\n ? runs.map((run, i) => ({\n d: runPaths[i].getAttribute('d')!,\n end: run.end / (points.length - 1),\n start: run.start / (points.length - 1),\n }))\n : [{ d: path!.getAttribute('d')!, end: 1, start: 0 }];\n\n // A wide trace also uncovers markers as it reaches them, without a second timeline.\n playTraceReveal(\n parent,\n options.bounds,\n traces,\n Math.max(strokeWidth, options.showPoints ? options.pointRadius * 2 : 0) + 2,\n resolveMotion(options.transition, { defaultDuration: 420 }),\n options.disposalSignal,\n );\n }\n\n return;\n }\n\n const fromPts: Point[] = [];\n const drawn = drawnPoints.get(parent) ?? points;\n\n for (const [i, to] of points.entries()) {\n fromPts.push(drawn[i] ?? drawn.at(-1) ?? to);\n }\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => {\n const from = fromPts[i] ?? to;\n\n return { x: tweenNumber(from.x, to.x, e), y: tweenNumber(from.y, to.y, e) };\n });\n\n drawnPoints.set(parent, interpolated);\n draw(interpolated);\n\n if (dotsGroup) {\n for (let i = 0; i < points.length; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement | undefined;\n\n if (c) setAttributes(c, { cx: interpolated[i].x, cy: interpolated[i].y });\n }\n }\n };\n\n // The starting geometry goes on screen immediately: `startTween` only paints on\n // the first frame callback, which would otherwise leave one blank frame.\n paintFrame(0);\n\n activeAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computePoints: datum.key is null or undefined: data must use the Datum shape { key, value }. Did you pass { x, y } instead?',\n );\n } else if (data.some((d) => typeof d.key === 'string')) {\n warn('computePoints: string keys are not supported for line/area charts: use numeric or Date keys.');\n }\n\n return data.map((d) => ({\n x: xScale.map(d.key as Date | number),\n y: yScale.map(d.value),\n }));\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../svg/element.cjs"),t=require("../../svg/text.cjs"),n=require("../../core/chart-scaffold.cjs"),r=require("../../theme/index.cjs"),i=require("../../animation/easing.cjs"),a=require("../../animation/motion.cjs"),o=require("../../animation/tween.cjs"),s=require("../../animation/transition.cjs"),c=require("./pie-renderer.cjs");var l=2*Math.PI,u=12;function labelFits(e,n){let r=e.outerRadius-e.innerRadius,i=(e.outerRadius+e.innerRadius)/2,a=(e.endAngle-e.startAngle-2*e.padAngle)*i;return r>=u*1.4&&a>=t.estimateTextWidth(n,u)+8}var d=-Math.PI/2,f=Math.PI/2;function semiAngles(e){return e===`semi`?{end:f,start:d}:{end:l,start:0}}function createPieChart(t,l){let u=l.variant??`pie`,d=l.padPixels??(u===`pie`?0:8),f=l.cornerRadius??(u===`pie`?0:8),p=l.data,m=e.createSvgElement(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),h=e.createSvgElement(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),g=e.createSvgElement(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),_=[],v=[],y=null;function renderLabels(t){g.replaceChildren();for(let n=0;n<_.length;n++){let r=_[n],i=t[n];if(!i?.label||!labelFits(r,i.label))continue;let{x:a,y:o}=c.arcCentroid(r),s=e.createSvgElement(`text`,{class:`prism-pie-label`});e.setAttributes(s,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:a,y:o}),s.textContent=i.label,g.appendChild(s)}}return n.createRadialScaffold(t,{a11y:l.a11y,legend:l.legend,tooltip:l.tooltip},n=>{let{legend:b,svg:x,tooltip:S}=n,C=p.some(e=>e.value>0);b?.update(C?p.map((e,t)=>({color:e.color??r.seriesColor(t),name:e.label??``})):[]),x.contains(m)||(x.appendChild(m),x.appendChild(h),x.appendChild(g));let{height:w,width:T}=n.dimensions,E=u===`semi`,D=T/2,O=E?w*.85:w/2,k=E?Math.min(D,O)-8:Math.min(T,w)/2-8,A=u===`pie`?0:Math.round(k*.55),j=l.innerRadius===void 0?A:l.innerRadius,M=Math.max(j+1,k),N=p,{end:P,start:F}=semiAngles(u);for(_=c.computeArcs(N,D,O,M,j,F,P,d,f,e=>r.seriesColor(e),!1),e.setAttributes(m,{cx:D,cy:O,r:j>0?j:0}),m.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);h.children.length>_.length;)h.removeChild(h.lastChild);g.replaceChildren();let I=a.resolveMotion(l.transition),L=I.duration,R=i.resolveEasing(I.easing);for(let t=0;t<_.length;t++){let n=_[t],r=h.children[t];r||(r=e.createSvgElement(`path`,{class:`prism-pie-slice`}),h.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=l.onClick||l.onHover?`pointer`:``}y?.();let z=v.length===0,B=v;y=s.startTween({count:1,duration:L,easing:R,onComplete:()=>renderLabels(N),onFrame:t=>{let n=t(0);if(z){let t=o.tweenNumber(F,P,n);v=_.map((n,r)=>{let i=h.children[r];if(!i)return n;if(t<=n.startAngle)return e.setAttributes(i,{d:``}),{...n,endAngle:n.startAngle};let a=Math.min(n.endAngle,t);return e.setAttributes(i,{d:c.arcPath({...n,endAngle:a})}),{...n,endAngle:a}})
|
|
1
|
+
const e=require("../../svg/element.cjs"),t=require("../../svg/text.cjs"),n=require("../../core/chart-scaffold.cjs"),r=require("../../theme/index.cjs"),i=require("../../animation/easing.cjs"),a=require("../../animation/motion.cjs"),o=require("../../animation/tween.cjs"),s=require("../../animation/transition.cjs"),c=require("./pie-renderer.cjs");var l=2*Math.PI,u=12;function labelFits(e,n){let r=e.outerRadius-e.innerRadius,i=(e.outerRadius+e.innerRadius)/2,a=(e.endAngle-e.startAngle-2*e.padAngle)*i;return r>=u*1.4&&a>=t.estimateTextWidth(n,u)+8}var d=-Math.PI/2,f=Math.PI/2;function semiAngles(e){return e===`semi`?{end:f,start:d}:{end:l,start:0}}function createPieChart(t,l){let u=l.variant??`pie`,d=l.padPixels??(u===`pie`?0:8),f=l.cornerRadius??(u===`pie`?0:8),p=l.data,m=e.createSvgElement(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),h=e.createSvgElement(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),g=e.createSvgElement(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),_=[],v=[],y=null;function renderLabels(t){g.replaceChildren();for(let n=0;n<_.length;n++){let r=_[n],i=t[n];if(!i?.label||!labelFits(r,i.label))continue;let{x:a,y:o}=c.arcCentroid(r),s=e.createSvgElement(`text`,{class:`prism-pie-label`});e.setAttributes(s,{"dominant-baseline":`middle`,fill:`var(--prism-pie-label-color, #fff)`,"font-family":`var(--prism-font-family, system-ui)`,"font-size":`var(--prism-pie-label-size, 12px)`,"text-anchor":`middle`,x:a,y:o}),s.textContent=i.label,g.appendChild(s)}}return n.createRadialScaffold(t,{a11y:l.a11y,legend:l.legend,tooltip:l.tooltip},n=>{let{legend:b,svg:x,tooltip:S}=n,C=p.some(e=>e.value>0);b?.update(C?p.map((e,t)=>({color:e.color??r.seriesColor(t),name:e.label??``})):[]),x.contains(m)||(x.appendChild(m),x.appendChild(h),x.appendChild(g));let{height:w,width:T}=n.dimensions,E=u===`semi`,D=T/2,O=E?w*.85:w/2,k=E?Math.min(D,O)-8:Math.min(T,w)/2-8,A=u===`pie`?0:Math.round(k*.55),j=l.innerRadius===void 0?A:l.innerRadius,M=Math.max(j+1,k),N=p,{end:P,start:F}=semiAngles(u);for(_=c.computeArcs(N,D,O,M,j,F,P,d,f,e=>r.seriesColor(e),!1),e.setAttributes(m,{cx:D,cy:O,r:j>0?j:0}),m.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);h.children.length>_.length;)h.removeChild(h.lastChild);g.replaceChildren();let I=a.resolveMotion(l.transition),L=I.duration,R=i.resolveEasing(I.easing);for(let t=0;t<_.length;t++){let n=_[t],r=h.children[t];r||(r=e.createSvgElement(`path`,{class:`prism-pie-slice`}),h.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=l.onClick||l.onHover?`pointer`:``}y?.();let z=v.length===0,B=v;y=s.startTween({count:1,duration:L,easing:R,onComplete:()=>renderLabels(N),onFrame:t=>{let n=t(0);if(z){let t=o.tweenNumber(F,P,n);v=_.map((n,r)=>{let i=h.children[r];if(!i)return n;if(t<=n.startAngle)return e.setAttributes(i,{d:``}),{...n,endAngle:n.startAngle};let a=Math.min(n.endAngle,t);return e.setAttributes(i,{d:c.arcPath({...n,endAngle:a})}),{...n,endAngle:a}})}else v=_.map((t,r)=>{let i=h.children[r],a=B.at(-1),s=B[r]??{...t,endAngle:a?.endAngle??F,startAngle:a?.endAngle??F},l={...t,endAngle:o.tweenNumber(s.endAngle,t.endAngle,n),innerRadius:o.tweenNumber(s.innerRadius,t.innerRadius,n),outerRadius:o.tweenNumber(s.outerRadius,t.outerRadius,n),padAngle:o.tweenNumber(s.padAngle,t.padAngle,n),startAngle:o.tweenNumber(s.startAngle,t.startAngle,n)};return i&&e.setAttributes(i,{d:l.endAngle-l.startAngle<=1e-6?``:c.arcPath(l)}),l})},signal:n.disposalSignal}),S?.hide();let V=_.reduce((e,t)=>e+Math.max(0,t.slice.value),0),H=-1,describe=e=>{let t=V>0?Math.round(Math.max(0,e.slice.value)/V*1e3)/10:0;return`${e.slice.label??`Slice ${e.index+1}`}: ${e.slice.value} (${t}%)`},setActive=e=>{H=e,h.classList.toggle(`prism-pie-focused`,e>=0);for(let[t,n]of[...h.children].entries())n.classList.toggle(`prism-pie-slice--active`,t===e)},activate=(e,r)=>{let i=_[e];if(!i)return;setActive(e),l.onHover?.({index:e,originalEvent:r,slice:i.slice});let a=describe(i);if(!S){n.announcer.announce(a);return}let{x:o,y:s}=c.arcCentroid(i),u=x.getBoundingClientRect(),d=t.getBoundingClientRect();S.show(o+(u.left-d.left),s+(u.top-d.top),{key:e,value:i.slice.value},{color:i.color,data:[],name:i.slice.label??``},a)},deactivate=()=>{setActive(-1),S?.hide(),n.announcer.clear(),l.onHover?.(null)},hitAt=e=>{let t=x.getBoundingClientRect();return hitTestArc(_,e.clientX-t.left,e.clientY-t.top,u)},onMouseMove=e=>{let t=hitAt(e);t>=0?t!==H&&activate(t,e):H>=0&&deactivate()},onClick=e=>{if(!l.onClick)return;let t=hitAt(e);t>=0&&l.onClick({index:t,originalEvent:e,slice:_[t].slice})},onKeyDown=e=>{let t=_.length;if(t===0)return;let n={ArrowDown:1,ArrowLeft:-1,ArrowRight:1,ArrowUp:-1};e.key in n?(e.preventDefault(),activate(H<0?n[e.key]>0?0:t-1:(H+n[e.key]+t)%t,e)):e.key===`Home`||e.key===`End`?(e.preventDefault(),activate(e.key===`Home`?0:t-1,e)):(e.key===`Enter`||e.key===` `)&&H>=0&&l.onClick?(e.preventDefault(),l.onClick({index:H,originalEvent:e,slice:_[H].slice})):e.key===`Escape`&&deactivate()};return{onClick,onKeyDown,onMouseLeave:deactivate,onMouseMove}},e=>{p=e})}function hitTestArc(e,t,n,r){for(let i=0;i<e.length;i++){let a=e[i],o=t-a.centerX,s=n-a.centerY,c=Math.sqrt(o*o+s*s);if(c<a.outerRadius&&c>=a.innerRadius){let e=Math.atan2(o,-s);if(r===`semi`){if(e>=a.startAngle-1e-9&&e<=a.endAngle+1e-9)return i}else{let t=e<0?e+l:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}exports.createPieChart=createPieChart;
|
|
2
2
|
//# sourceMappingURL=pie-chart.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart.cjs","names":[],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { estimateTextWidth } from '../../svg/text';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n/** Default `--prism-pie-label-size` in px, used to decide whether a label fits its slice. */\nconst LABEL_FONT_SIZE = 12;\n\n/** A label fits when its slice is wide enough along the centroid arc and thick enough radially. */\nfunction labelFits(arc: Arc, label: string): boolean {\n const thickness = arc.outerRadius - arc.innerRadius;\n const midRadius = (arc.outerRadius + arc.innerRadius) / 2;\n const arcLength = (arc.endAngle - arc.startAngle - 2 * arc.padAngle) * midRadius;\n\n return thickness >= LABEL_FONT_SIZE * 1.4 && arcLength >= estimateTextWidth(label, LABEL_FONT_SIZE) + 8;\n}\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n // The geometry actually on screen right now (mid-tween included): the update\n // morph interpolates from this, so interrupting a tween never jumps.\n let drawnArcs: Arc[] = [];\n let activeTween: (() => void) | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label || !labelFits(arc, slice.label)) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n return createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n const hasSlices = data.some((slice) => slice.value > 0);\n legend?.update(\n hasSlices ? data.map((slice, i) => ({ color: slice.color ?? seriesColor(i), name: slice.label ?? '' })) : [],\n );\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n activeTween?.();\n\n // Mount sweeps the ring in once; an update morphs every slice from its\n // drawn angles to the new ones, which reads as the data changing rather\n // than the chart redrawing.\n const isMount = drawnArcs.length === 0;\n const fromArcs = drawnArcs;\n\n activeTween = startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => renderLabels(slices),\n onFrame: (progress) => {\n const e = progress(0);\n\n if (isMount) {\n const revealAngle = tweenNumber(start, end, e);\n\n drawnArcs = currentArcs.map((a, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) return a;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n\n return { ...a, endAngle: a.startAngle };\n }\n\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n\n return { ...a, endAngle: visibleEnd };\n });\n\n return;\n }\n\n drawnArcs = currentArcs.map((to, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n const lastDrawn = fromArcs.at(-1);\n // A slice that was not drawn before grows out of the end of the last drawn one.\n const from: Arc = fromArcs[j] ?? {\n ...to,\n endAngle: lastDrawn?.endAngle ?? start,\n startAngle: lastDrawn?.endAngle ?? start,\n };\n const morphed: Arc = {\n ...to,\n endAngle: tweenNumber(from.endAngle, to.endAngle, e),\n innerRadius: tweenNumber(from.innerRadius, to.innerRadius, e),\n outerRadius: tweenNumber(from.outerRadius, to.outerRadius, e),\n padAngle: tweenNumber(from.padAngle, to.padAngle, e),\n startAngle: tweenNumber(from.startAngle, to.startAngle, e),\n };\n\n if (!el) return morphed;\n\n setAttributes(el, {\n d: morphed.endAngle - morphed.startAngle <= 1e-6 ? '' : arcPath(morphed),\n });\n\n return morphed;\n });\n },\n signal: ctx.disposalSignal,\n });\n\n tooltip?.hide();\n\n const total = currentArcs.reduce((sum, arc) => sum + Math.max(0, arc.slice.value), 0);\n let activeIndex = -1;\n\n const describe = (arc: Arc): string => {\n const percent = total > 0 ? Math.round((Math.max(0, arc.slice.value) / total) * 1000) / 10 : 0;\n\n return `${arc.slice.label ?? `Slice ${arc.index + 1}`}: ${arc.slice.value} (${percent}%)`;\n };\n\n const setActive = (index: number): void => {\n activeIndex = index;\n pieGroup.classList.toggle('prism-pie-focused', index >= 0);\n for (const [i, el] of [...pieGroup.children].entries())\n el.classList.toggle('prism-pie-slice--active', i === index);\n };\n\n const activate = (index: number, originalEvent: Event): void => {\n const arc = currentArcs[index];\n\n if (!arc) return;\n\n setActive(index);\n config.onHover?.({ index, originalEvent, slice: arc.slice });\n\n const text = describe(arc);\n\n if (!tooltip) {\n ctx.announcer.announce(text);\n\n return;\n }\n\n const { x, y } = arcCentroid(arc);\n const svgRect = svg.getBoundingClientRect();\n const contR = container.getBoundingClientRect();\n\n tooltip.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: index, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n text,\n );\n };\n\n const deactivate = (): void => {\n setActive(-1);\n tooltip?.hide();\n ctx.announcer.clear();\n config.onHover?.(null);\n };\n\n const hitAt = (e: MouseEvent): number => {\n const svgRect = svg.getBoundingClientRect();\n\n return hitTestArc(currentArcs, e.clientX - svgRect.left, e.clientY - svgRect.top, variant);\n };\n\n const onMouseMove = (e: MouseEvent): void => {\n const hit = hitAt(e);\n\n if (hit >= 0) {\n if (hit !== activeIndex) activate(hit, e);\n } else if (activeIndex >= 0) {\n deactivate();\n }\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const hit = hitAt(e);\n\n if (hit >= 0) config.onClick({ index: hit, originalEvent: e, slice: currentArcs[hit].slice });\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n const count = currentArcs.length;\n\n if (count === 0) return;\n\n const step: Record<string, number> = { ArrowDown: 1, ArrowLeft: -1, ArrowRight: 1, ArrowUp: -1 };\n\n if (e.key in step) {\n e.preventDefault();\n activate(\n activeIndex < 0 ? (step[e.key] > 0 ? 0 : count - 1) : (activeIndex + step[e.key] + count) % count,\n e,\n );\n } else if (e.key === 'Home' || e.key === 'End') {\n e.preventDefault();\n activate(e.key === 'Home' ? 0 : count - 1, e);\n } else if ((e.key === 'Enter' || e.key === ' ') && activeIndex >= 0 && config.onClick) {\n e.preventDefault();\n config.onClick({ index: activeIndex, originalEvent: e, slice: currentArcs[activeIndex].slice });\n } else if (e.key === 'Escape') {\n deactivate();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: deactivate, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pie-chart.cjs","names":["estimateTextWidth","createSvgElement","arcCentroid","createRadialScaffold","seriesColor","computeArcs","resolveMotion","resolveEasing","startTween","tweenNumber","arcPath","require_element","require_text","require_chart_scaffold","require_index","require_easing","require_motion","require_tween","require_transition","require_pie_renderer","TWO_PI","LABEL_FONT_SIZE","thickness","arc","midRadius","arcLength","label","SEMI_START","SEMI_END","variant","config","padPixels","cornerRadius","data","bgCircle","pieGroup","labelGroup","currentArcs","drawnArcs","activeTween","i","slice","slices","text","container","ctx","hasSlices","legend","svg","h","w","isSemi","cx","cy","outer","defaultInner","inner","outerR","start","end","motion","dur","easing","path","isMount","fromArcs","e","progress","revealAngle","el","j","a","visibleEnd","lastDrawn","from","to","morphed","tooltip","total","sum","activeIndex","percent","index","svgRect","contR","x","y","hit","count","step","next","arcs","dx","mx","dy","my","dist","rawAngle","angle"],"sources":["../../../src/charts/pie/pie-chart.ts"],"sourcesContent":["import { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\nimport { startTween } from '../../animation/transition';\nimport { tweenNumber } from '../../animation/tween';\nimport type { ChartEventHandlers } from '../../core/chart-scaffold';\nimport { createRadialScaffold } from '../../core/chart-scaffold';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport { estimateTextWidth } from '../../svg/text';\nimport { seriesColor } from '../../theme';\nimport type { ChartHandle, PieChartConfig, PieSliceConfig } from '../../types';\nimport { type Arc, arcCentroid, arcPath, computeArcs } from './pie-renderer';\n\nconst TWO_PI = 2 * Math.PI;\n/** Default `--prism-pie-label-size` in px, used to decide whether a label fits its slice. */\nconst LABEL_FONT_SIZE = 12;\n\n/** A label fits when its slice is wide enough along the centroid arc and thick enough radially. */\nfunction labelFits(arc: Arc, label: string): boolean {\n const thickness = arc.outerRadius - arc.innerRadius;\n const midRadius = (arc.outerRadius + arc.innerRadius) / 2;\n const arcLength = (arc.endAngle - arc.startAngle - 2 * arc.padAngle) * midRadius;\n\n return thickness >= LABEL_FONT_SIZE * 1.4 && arcLength >= estimateTextWidth(label, LABEL_FONT_SIZE) + 8;\n}\n\nconst SEMI_START = -Math.PI / 2; // -90° = 9-o'clock (left)\nconst SEMI_END = Math.PI / 2; // +90° = 3-o'clock (right) → true 180° half-circle\n\nfunction semiAngles(variant: PieChartConfig['variant']): { end: number; start: number } {\n return variant === 'semi' ? { end: SEMI_END, start: SEMI_START } : { end: TWO_PI, start: 0 };\n}\n\nexport function createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle<PieSliceConfig[]> {\n const variant = config.variant ?? 'pie';\n const padPixels = config.padPixels ?? (variant === 'pie' ? 0 : 8);\n const cornerRadius = config.cornerRadius ?? (variant === 'pie' ? 0 : 8);\n let data = config.data;\n\n // Pie SVG elements live directly on the SVG (not inside chartArea groups).\n // We create them once and reuse across renders.\n const bgCircle = createSvgElement('circle', { class: 'prism-pie-bg', 'pointer-events': 'none' });\n const pieGroup = createSvgElement('g', {\n class: 'prism-pie-slices',\n 'shape-rendering': 'geometricPrecision',\n });\n const labelGroup = createSvgElement('g', { class: 'prism-pie-labels', 'pointer-events': 'none' });\n\n // Current arcs shared between renderFn and event handlers via closure.\n let currentArcs: Arc[] = [];\n // The geometry actually on screen right now (mid-tween included): the update\n // morph interpolates from this, so interrupting a tween never jumps.\n let drawnArcs: Arc[] = [];\n let activeTween: (() => void) | null = null;\n\n function renderLabels(slices: PieSliceConfig[]): void {\n labelGroup.replaceChildren();\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n const slice = slices[i];\n\n if (!slice?.label || !labelFits(arc, slice.label)) continue;\n\n const { x, y } = arcCentroid(arc);\n const text = createSvgElement('text', { class: 'prism-pie-label' });\n\n setAttributes(text, {\n 'dominant-baseline': 'middle',\n fill: 'var(--prism-pie-label-color, #fff)',\n 'font-family': 'var(--prism-font-family, system-ui)',\n 'font-size': 'var(--prism-pie-label-size, 12px)',\n 'text-anchor': 'middle',\n x,\n y,\n });\n\n text.textContent = slice.label;\n labelGroup.appendChild(text);\n }\n }\n\n return createRadialScaffold(\n container,\n {\n a11y: config.a11y,\n legend: config.legend,\n tooltip: config.tooltip,\n },\n (ctx): ChartEventHandlers => {\n const { legend, svg, tooltip } = ctx;\n const hasSlices = data.some((slice) => slice.value > 0);\n legend?.update(\n hasSlices ? data.map((slice, i) => ({ color: slice.color ?? seriesColor(i), name: slice.label ?? '' })) : [],\n );\n\n // Append pie groups to SVG on first render (idempotent).\n if (!svg.contains(bgCircle)) {\n svg.appendChild(bgCircle);\n svg.appendChild(pieGroup);\n svg.appendChild(labelGroup);\n }\n\n const { height: h, width: w } = ctx.dimensions;\n const isSemi = variant === 'semi';\n const cx = w / 2;\n const cy = isSemi ? h * 0.85 : h / 2;\n const padding = 8;\n const outer = isSemi ? Math.min(cx, cy) - padding : Math.min(w, h) / 2 - padding;\n const defaultInner = variant === 'pie' ? 0 : Math.round(outer * 0.55);\n const inner = config.innerRadius !== undefined ? config.innerRadius : defaultInner;\n const outerR = Math.max(inner + 1, outer);\n\n const slices = data;\n const { end, start } = semiAngles(variant);\n\n currentArcs = computeArcs(\n slices,\n cx,\n cy,\n outerR,\n inner,\n start,\n end,\n padPixels,\n cornerRadius,\n (i) => seriesColor(i),\n false,\n );\n\n setAttributes(bgCircle, { cx, cy, r: inner > 0 ? inner : 0 });\n bgCircle.setAttribute('style', 'fill:var(--prism-bg,#fff)');\n\n while (pieGroup.children.length > currentArcs.length) pieGroup.removeChild(pieGroup.lastChild!);\n\n labelGroup.replaceChildren();\n\n const motion = resolveMotion(config.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n for (let i = 0; i < currentArcs.length; i++) {\n const arc = currentArcs[i];\n let path = pieGroup.children[i] as SVGPathElement | undefined;\n\n if (!path) {\n path = createSvgElement('path', { class: 'prism-pie-slice' });\n pieGroup.appendChild(path);\n }\n\n path.setAttribute('fill', arc.color);\n path.setAttribute('stroke', 'none');\n path.style.cursor = config.onClick || config.onHover ? 'pointer' : '';\n }\n\n activeTween?.();\n\n // Mount sweeps the ring in once; an update morphs every slice from its\n // drawn angles to the new ones, which reads as the data changing rather\n // than the chart redrawing.\n const isMount = drawnArcs.length === 0;\n const fromArcs = drawnArcs;\n\n activeTween = startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => renderLabels(slices),\n onFrame: (progress) => {\n const e = progress(0);\n\n if (isMount) {\n const revealAngle = tweenNumber(start, end, e);\n\n drawnArcs = currentArcs.map((a, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) return a;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n\n return { ...a, endAngle: a.startAngle };\n }\n\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n\n return { ...a, endAngle: visibleEnd };\n });\n\n return;\n }\n\n drawnArcs = currentArcs.map((to, j) => {\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n const lastDrawn = fromArcs.at(-1);\n // A slice that was not drawn before grows out of the end of the last drawn one.\n const from: Arc = fromArcs[j] ?? {\n ...to,\n endAngle: lastDrawn?.endAngle ?? start,\n startAngle: lastDrawn?.endAngle ?? start,\n };\n const morphed: Arc = {\n ...to,\n endAngle: tweenNumber(from.endAngle, to.endAngle, e),\n innerRadius: tweenNumber(from.innerRadius, to.innerRadius, e),\n outerRadius: tweenNumber(from.outerRadius, to.outerRadius, e),\n padAngle: tweenNumber(from.padAngle, to.padAngle, e),\n startAngle: tweenNumber(from.startAngle, to.startAngle, e),\n };\n\n if (!el) return morphed;\n\n setAttributes(el, {\n d: morphed.endAngle - morphed.startAngle <= 1e-6 ? '' : arcPath(morphed),\n });\n\n return morphed;\n });\n },\n signal: ctx.disposalSignal,\n });\n\n tooltip?.hide();\n\n const total = currentArcs.reduce((sum, arc) => sum + Math.max(0, arc.slice.value), 0);\n let activeIndex = -1;\n\n const describe = (arc: Arc): string => {\n const percent = total > 0 ? Math.round((Math.max(0, arc.slice.value) / total) * 1000) / 10 : 0;\n\n return `${arc.slice.label ?? `Slice ${arc.index + 1}`}: ${arc.slice.value} (${percent}%)`;\n };\n\n const setActive = (index: number): void => {\n activeIndex = index;\n pieGroup.classList.toggle('prism-pie-focused', index >= 0);\n for (const [i, el] of [...pieGroup.children].entries())\n el.classList.toggle('prism-pie-slice--active', i === index);\n };\n\n const activate = (index: number, originalEvent: Event): void => {\n const arc = currentArcs[index];\n\n if (!arc) return;\n\n setActive(index);\n config.onHover?.({ index, originalEvent, slice: arc.slice });\n\n const text = describe(arc);\n\n if (!tooltip) {\n ctx.announcer.announce(text);\n\n return;\n }\n\n const { x, y } = arcCentroid(arc);\n const svgRect = svg.getBoundingClientRect();\n const contR = container.getBoundingClientRect();\n\n tooltip.show(\n x + (svgRect.left - contR.left),\n y + (svgRect.top - contR.top),\n { key: index, value: arc.slice.value },\n { color: arc.color, data: [], name: arc.slice.label ?? '' },\n text,\n );\n };\n\n const deactivate = (): void => {\n setActive(-1);\n tooltip?.hide();\n ctx.announcer.clear();\n config.onHover?.(null);\n };\n\n const hitAt = (e: MouseEvent): number => {\n const svgRect = svg.getBoundingClientRect();\n\n return hitTestArc(currentArcs, e.clientX - svgRect.left, e.clientY - svgRect.top, variant);\n };\n\n const onMouseMove = (e: MouseEvent): void => {\n const hit = hitAt(e);\n\n if (hit >= 0) {\n if (hit !== activeIndex) activate(hit, e);\n } else if (activeIndex >= 0) {\n deactivate();\n }\n };\n\n const onClick = (e: MouseEvent): void => {\n if (!config.onClick) return;\n\n const hit = hitAt(e);\n\n if (hit >= 0) config.onClick({ index: hit, originalEvent: e, slice: currentArcs[hit].slice });\n };\n\n const onKeyDown = (e: KeyboardEvent): void => {\n const count = currentArcs.length;\n\n if (count === 0) return;\n\n const step: Record<string, number> = { ArrowDown: 1, ArrowLeft: -1, ArrowRight: 1, ArrowUp: -1 };\n\n if (e.key in step) {\n e.preventDefault();\n activate(\n activeIndex < 0 ? (step[e.key] > 0 ? 0 : count - 1) : (activeIndex + step[e.key] + count) % count,\n e,\n );\n } else if (e.key === 'Home' || e.key === 'End') {\n e.preventDefault();\n activate(e.key === 'Home' ? 0 : count - 1, e);\n } else if ((e.key === 'Enter' || e.key === ' ') && activeIndex >= 0 && config.onClick) {\n e.preventDefault();\n config.onClick({ index: activeIndex, originalEvent: e, slice: currentArcs[activeIndex].slice });\n } else if (e.key === 'Escape') {\n deactivate();\n }\n };\n\n return { onClick, onKeyDown, onMouseLeave: deactivate, onMouseMove };\n },\n (next) => {\n data = next;\n },\n );\n}\n\nfunction hitTestArc(arcs: Arc[], mx: number, my: number, variant: PieChartConfig['variant']): number {\n for (let i = 0; i < arcs.length; i++) {\n const arc = arcs[i];\n const dx = mx - arc.centerX;\n const dy = my - arc.centerY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < arc.outerRadius && dist >= arc.innerRadius) {\n const rawAngle = Math.atan2(dx, -dy);\n\n if (variant === 'semi') {\n if (rawAngle >= arc.startAngle - 1e-9 && rawAngle <= arc.endAngle + 1e-9) return i;\n } else {\n const angle = rawAngle < 0 ? rawAngle + TWO_PI : rawAngle;\n\n if (angle >= arc.startAngle - 1e-9 && angle <= arc.endAngle + 1e-9) return i;\n }\n }\n }\n\n return -1;\n}\n"],"mappings":"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"}
|