@vielzeug/prism 26.10.2 → 26.10.4
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/README.md +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js.map +1 -1
- package/dist/_tappers.cjs +2 -0
- package/dist/_tappers.cjs.map +1 -0
- package/dist/_tappers.d.ts +10 -0
- package/dist/_tappers.d.ts.map +1 -0
- package/dist/_tappers.js +2 -0
- package/dist/_tappers.js.map +1 -0
- package/dist/animation/easing.cjs +1 -1
- package/dist/animation/easing.cjs.map +1 -1
- package/dist/animation/easing.d.ts +15 -1
- package/dist/animation/easing.d.ts.map +1 -1
- package/dist/animation/easing.js +1 -1
- package/dist/animation/easing.js.map +1 -1
- package/dist/animation/motion.cjs +1 -1
- package/dist/animation/motion.cjs.map +1 -1
- package/dist/animation/motion.d.ts +17 -2
- package/dist/animation/motion.d.ts.map +1 -1
- package/dist/animation/motion.js +1 -1
- package/dist/animation/motion.js.map +1 -1
- package/dist/animation/transition.cjs +1 -1
- package/dist/animation/transition.cjs.map +1 -1
- package/dist/animation/transition.d.ts +32 -3
- package/dist/animation/transition.d.ts.map +1 -1
- package/dist/animation/transition.js +1 -1
- package/dist/animation/transition.js.map +1 -1
- package/dist/charts/area/area-chart.cjs +1 -1
- package/dist/charts/area/area-chart.cjs.map +1 -1
- package/dist/charts/area/area-chart.d.ts.map +1 -1
- package/dist/charts/area/area-chart.js +1 -1
- package/dist/charts/area/area-chart.js.map +1 -1
- package/dist/charts/area/area-renderer.cjs +1 -1
- package/dist/charts/area/area-renderer.cjs.map +1 -1
- package/dist/charts/area/area-renderer.d.ts +2 -2
- package/dist/charts/area/area-renderer.d.ts.map +1 -1
- package/dist/charts/area/area-renderer.js +1 -1
- package/dist/charts/area/area-renderer.js.map +1 -1
- package/dist/charts/bar/bar-chart.cjs +1 -1
- package/dist/charts/bar/bar-chart.cjs.map +1 -1
- package/dist/charts/bar/bar-chart.d.ts.map +1 -1
- package/dist/charts/bar/bar-chart.js +1 -1
- package/dist/charts/bar/bar-chart.js.map +1 -1
- package/dist/charts/bar/bar-renderer.cjs +1 -1
- package/dist/charts/bar/bar-renderer.cjs.map +1 -1
- package/dist/charts/bar/bar-renderer.d.ts +2 -2
- package/dist/charts/bar/bar-renderer.d.ts.map +1 -1
- package/dist/charts/bar/bar-renderer.js +1 -1
- package/dist/charts/bar/bar-renderer.js.map +1 -1
- package/dist/charts/line/line-chart.cjs +1 -1
- package/dist/charts/line/line-chart.cjs.map +1 -1
- package/dist/charts/line/line-chart.d.ts.map +1 -1
- package/dist/charts/line/line-chart.js +1 -1
- package/dist/charts/line/line-chart.js.map +1 -1
- package/dist/charts/line/line-renderer.cjs +1 -1
- package/dist/charts/line/line-renderer.cjs.map +1 -1
- package/dist/charts/line/line-renderer.d.ts +4 -2
- package/dist/charts/line/line-renderer.d.ts.map +1 -1
- package/dist/charts/line/line-renderer.js +1 -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.d.ts.map +1 -1
- package/dist/charts/pie/pie-chart.js +1 -1
- package/dist/charts/pie/pie-chart.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.d.ts.map +1 -1
- package/dist/charts/radar/radar-chart.js +1 -1
- package/dist/charts/radar/radar-chart.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.d.ts.map +1 -1
- package/dist/charts/sparkline/sparkline.js +1 -1
- package/dist/charts/sparkline/sparkline.js.map +1 -1
- package/dist/core/chart-scaffold.cjs +1 -1
- package/dist/core/chart-scaffold.cjs.map +1 -1
- package/dist/core/chart-scaffold.d.ts.map +1 -1
- package/dist/core/chart-scaffold.js +1 -1
- package/dist/core/chart-scaffold.js.map +1 -1
- package/dist/core/responsive.cjs +1 -1
- package/dist/core/responsive.cjs.map +1 -1
- package/dist/core/responsive.d.ts.map +1 -1
- package/dist/core/responsive.js +1 -1
- package/dist/core/responsive.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/interaction/crosshair.cjs +1 -1
- package/dist/interaction/crosshair.cjs.map +1 -1
- package/dist/interaction/crosshair.d.ts +7 -0
- package/dist/interaction/crosshair.d.ts.map +1 -1
- package/dist/interaction/crosshair.js +1 -1
- package/dist/interaction/crosshair.js.map +1 -1
- package/dist/interaction/series-interaction.cjs +1 -1
- package/dist/interaction/series-interaction.cjs.map +1 -1
- package/dist/interaction/series-interaction.d.ts +3 -1
- package/dist/interaction/series-interaction.d.ts.map +1 -1
- package/dist/interaction/series-interaction.js +1 -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.d.ts.map +1 -1
- package/dist/interaction/tooltip.js +1 -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 +1 -1
- package/dist/prism.js.map +1 -1
- package/dist/theme/index.cjs +1 -1
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.d.ts +9 -4
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/prism.css +18 -4
- package/dist/types.d.ts +76 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -18
- package/dist/animation/index.d.ts +0 -6
- package/dist/animation/index.d.ts.map +0 -1
- package/dist/axes/index.d.ts +0 -3
- package/dist/axes/index.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -7
- package/dist/core/index.d.ts.map +0 -1
- package/dist/devtools/index.d.ts +0 -52
- package/dist/devtools/index.d.ts.map +0 -1
- package/dist/devtools.cjs +0 -2
- package/dist/devtools.cjs.map +0 -1
- package/dist/devtools.js +0 -2
- package/dist/devtools.js.map +0 -1
- package/dist/interaction/index.d.ts +0 -8
- package/dist/interaction/index.d.ts.map +0 -1
- package/dist/scales/index.d.ts +0 -4
- package/dist/scales/index.d.ts.map +0 -1
- package/dist/svg/index.d.ts +0 -5
- package/dist/svg/index.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.cjs","names":[],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount } 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 } 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) => {\n const { groups, legend, tooltip } = ctx;\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 dims.margin.right =\n config.margin?.right ?? (hasRight ? (config.rightYAxis?.label ? 72 : 50) : resolveMargin(config.margin).right);\n const area = chartArea(dims.width, dims.height, dims.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 if (config.yAxis?.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n config.yAxis.grid,\n area.width,\n 'horizontal',\n resolveTickCount(config.yAxis, area.height, 'left'),\n );\n } else {\n groups.grid.replaceChildren();\n }\n\n if (config.xAxis?.grid) {\n renderGrid(\n groups.grid,\n xScale,\n config.xAxis.grid,\n area.height,\n 'vertical',\n resolveTickCount(config.xAxis, area.width, 'bottom'),\n );\n }\n\n if (config.xAxis) {\n positionAxis(groups.xAxis, config.xAxis.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, config.xAxis, area.width, 'bottom');\n }\n\n if (config.yAxis && (!hasRight || hasLeftData)) {\n const axis = { ...config.yAxis, position: hasRight ? ('left' as const) : (config.yAxis.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 points = computePoints(allData[i], xScale, series.yAxis === 'right' ? rightYScale : yScale);\n\n allPoints.push(points);\n\n renderLine(group, points, {\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: config.transition,\n });\n }\n\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\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 markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.cjs","names":[],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount } 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) => {\n const { groups, legend, tooltip } = ctx;\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.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : (config.yAxis ?? { grid: true });\n\n if (yAxisConfig && yAxisConfig.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n 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 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 baselineY: seriesScale.map(0),\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: config.transition,\n });\n }\n\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\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 });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/line/line-chart.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/line/line-chart.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAA4B,MAAM,aAAa,CAAC;AAG5G,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,GAAG,WAAW,CAAC,gBAAgB,EAAE,CAAC,CAmKhH"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createSvgElement as e}from"../../svg/element.js";import{positionAxis as t,renderAxis as n,resolveTickCount as r}from"../../axes/axis.js";import{renderGrid as i}from"../../axes/grid.js";import{buildXScale as a,buildYScale as o}from"../../core/cartesian-scales.js";import{chartArea as s,resolveMargin as c}from"../../core/layout.js";import{clearCartesianDom as l,createChartScaffold as u}from"../../core/chart-scaffold.js";import{seriesDomId as d}from"../../core/series-id.js";import{createCrosshair as f}from"../../interaction/crosshair.js";import{createSeriesInteraction as p,ensureMarkerGroup as m}from"../../interaction/series-interaction.js";import{seriesColor as h}from"../../theme/index.js";import{computePoints as g,renderLine as _}from"./line-renderer.js";function createLineChart(v,y){let b=null,x=null,S=null,C=y.series;return u(v,y,u=>{let{groups:v,legend:w,tooltip:T}=u,E=u.dimensions,D=C.some(e=>e.yAxis===`right`),O=C.some(e=>e.yAxis!==`right`&&e.data.length>0)
|
|
1
|
+
import{createSvgElement as e}from"../../svg/element.js";import{positionAxis as t,renderAxis as n,resolveTickCount as r}from"../../axes/axis.js";import{renderGrid as i}from"../../axes/grid.js";import{buildXScale as a,buildYScale as o}from"../../core/cartesian-scales.js";import{chartArea as s,resolveMargin as c}from"../../core/layout.js";import{clearCartesianDom as l,createChartScaffold as u}from"../../core/chart-scaffold.js";import{seriesDomId as d}from"../../core/series-id.js";import{createCrosshair as f}from"../../interaction/crosshair.js";import{createSeriesInteraction as p,ensureMarkerGroup as m}from"../../interaction/series-interaction.js";import{seriesColor as h}from"../../theme/index.js";import{computePoints as g,renderLine as _}from"./line-renderer.js";function createLineChart(v,y){let b=null,x=null,S=null,C=y.series;return u(v,y,u=>{let{groups:v,legend:w,tooltip:T}=u,E=u.dimensions,D=C.some(e=>e.yAxis===`right`),O=C.some(e=>e.yAxis!==`right`&&e.data.length>0),k={...c(y.margin),right:y.margin?.right??(D?y.rightYAxis?.label?72:50:c(y.margin).right)},A=s(E.width,E.height,k),j=C.map(e=>e.data),M=j.flat().map(e=>e.key),N=C.filter(e=>e.yAxis!==`right`).flatMap(e=>e.data.map(e=>e.value)),P=C.filter(e=>e.yAxis===`right`).flatMap(e=>e.data.map(e=>e.value));if(M.length===0){l(v,w,T,b),x?.replaceChildren(),S?.replaceChildren();return}y.crosshair&&!b&&(b=f(u.chartArea,y.crosshair));let F=a(M,A.width),I=o(N,A.height),L=o(P,A.height),R=y.xAxis===!1?!1:y.xAxis??{},z=y.yAxis===!1?!1:y.yAxis??{grid:!0};if(z&&z.grid&&(!D||O)?i(v.grid,I,z.grid,A.width,`horizontal`,r(z,A.height,`left`)):v.grid.replaceChildren(),R&&R.grid&&i(v.grid,F,R.grid,A.height,`vertical`,r(R,A.width,`bottom`)),R?(t(v.xAxis,R.position??`bottom`,A.width,A.height),n(v.xAxis,F,R,A.width,`bottom`)):v.xAxis.replaceChildren(),z&&(!D||O)){let e={...z,position:D?`left`:z.position??`left`};t(v.yAxis,e.position,A.width,A.height),n(v.yAxis,I,e,A.height,`left`)}else v.yAxis.replaceChildren();if(D){S||(S=e(`g`,{class:`prism-y-axis-right`}),u.chartArea.appendChild(S));let r={...y.rightYAxis,position:`right`};t(S,`right`,A.width,A.height),n(S,L,r,A.height,`right`)}else S?.replaceChildren();for(;v.series.children.length>C.length;)v.series.removeChild(v.series.lastChild);let B=[];for(let t=0;t<C.length;t++){let n=C[t],r=v.series.children[t];r||(r=e(`g`,{class:`prism-line-series`}),v.series.appendChild(r)),r.setAttribute(`data-series-id`,d(n,t));let i=n.yAxis===`right`?L:I,a=g(j[t],F,i);B.push(a),_(r,a,{baselineY:i.map(0),color:h(t,n.color),curve:n.curve??`linear`,disposalSignal:u.disposalSignal,marks:n.data,pointRadius:n.pointRadius??3,showPoints:n.showPoints??!1,strokeWidth:n.strokeWidth,transition:y.transition})}return w?.update(C.map((e,t)=>({color:h(t,e.color),name:e.name}))),T?.hide(),x=m(u.chartArea,x),p({announcer:u.announcer,colors:()=>C.map((e,t)=>h(t,e.color)),crosshair:b,dims:()=>u.dimensions,getData:()=>j,getPoints:()=>B,getSeriesList:()=>C,margin:k,markers:x,onClick:y.onClick,onHover:y.onHover,seriesGroup:v.series,svg:u.svg,tooltip:T})},e=>{C=e})}export{createLineChart};
|
|
2
2
|
//# sourceMappingURL=line-chart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.js","names":[],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount } 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 } 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) => {\n const { groups, legend, tooltip } = ctx;\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 dims.margin.right =\n config.margin?.right ?? (hasRight ? (config.rightYAxis?.label ? 72 : 50) : resolveMargin(config.margin).right);\n const area = chartArea(dims.width, dims.height, dims.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 if (config.yAxis?.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n config.yAxis.grid,\n area.width,\n 'horizontal',\n resolveTickCount(config.yAxis, area.height, 'left'),\n );\n } else {\n groups.grid.replaceChildren();\n }\n\n if (config.xAxis?.grid) {\n renderGrid(\n groups.grid,\n xScale,\n config.xAxis.grid,\n area.height,\n 'vertical',\n resolveTickCount(config.xAxis, area.width, 'bottom'),\n );\n }\n\n if (config.xAxis) {\n positionAxis(groups.xAxis, config.xAxis.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, config.xAxis, area.width, 'bottom');\n }\n\n if (config.yAxis && (!hasRight || hasLeftData)) {\n const axis = { ...config.yAxis, position: hasRight ? ('left' as const) : (config.yAxis.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 points = computePoints(allData[i], xScale, series.yAxis === 'right' ? rightYScale : yScale);\n\n allPoints.push(points);\n\n renderLine(group, points, {\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: config.transition,\n });\n }\n\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\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 markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.js","names":[],"sources":["../../../src/charts/line/line-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount } 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) => {\n const { groups, legend, tooltip } = ctx;\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.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : (config.yAxis ?? { grid: true });\n\n if (yAxisConfig && yAxisConfig.grid && (!hasRight || hasLeftData)) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n 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 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 baselineY: seriesScale.map(0),\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: config.transition,\n });\n }\n\n legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\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 });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"kwBAcA,SAAgB,gBAAgB,EAAwB,EAA0D,CAChH,IAAI,EAAuD,KACvD,EAA8B,KAC9B,EAAgC,KAChC,EAAa,EAAO,OAExB,OAAO,EACL,EACA,EACC,GAAQ,CACP,GAAM,CAAE,SAAQ,SAAQ,WAAY,EAC9B,EAAO,EAAI,WACX,EAAW,EAAW,KAAM,GAAW,EAAO,QAAU,OAAO,EAC/D,EAAc,EAAW,KAAM,GAAW,EAAO,QAAU,SAAW,EAAO,KAAK,OAAS,CAAC,EAG5F,EAAS,CACb,GAAG,EAAc,EAAO,MAAM,EAC9B,MACE,EAAO,QAAQ,QACd,EAAY,EAAO,YAAY,MAAQ,GAAK,GAAM,EAAc,EAAO,MAAM,CAAC,CAAC,MACpF,EACM,EAAO,EAAU,EAAK,MAAO,EAAK,OAAQ,CAAM,EAChD,EAAU,EAAW,IAAK,GAAW,EAAO,IAAI,EAChD,EAAO,EAAQ,KAAK,CAAC,CAAC,IAAK,GAAU,EAAM,GAAG,EAC9C,EAAQ,EACX,OAAQ,GAAW,EAAO,QAAU,OAAO,CAAC,CAC5C,QAAS,GAAW,EAAO,KAAK,IAAK,GAAU,EAAM,KAAK,CAAC,EACxD,EAAS,EACZ,OAAQ,GAAW,EAAO,QAAU,OAAO,CAAC,CAC5C,QAAS,GAAW,EAAO,KAAK,IAAK,GAAU,EAAM,KAAK,CAAC,EAE9D,GAAI,EAAK,SAAW,EAAG,CACrB,EAAkB,EAAQ,EAAQ,EAAS,CAAS,EACpD,GAAS,gBAAgB,EACzB,GAAW,gBAAgB,EAE3B,MACF,CAEI,EAAO,WAAa,CAAC,IACvB,EAAY,EAAgB,EAAI,UAAW,EAAO,SAAS,GAG7D,IAAM,EAAS,EAAY,EAAM,EAAK,KAAK,EACrC,EAAS,EAAY,EAAO,EAAK,MAAM,EACvC,EAAc,EAAY,EAAQ,EAAK,MAAM,EAG7C,EAAmC,EAAO,QAAU,GAAQ,GAAS,EAAO,OAAS,CAAC,EACtF,EAAmC,EAAO,QAAU,GAAQ,GAAS,EAAO,OAAS,CAAE,KAAM,EAAK,EAiCxG,GA/BI,GAAe,EAAY,OAAS,CAAC,GAAY,GACnD,EACE,EAAO,KACP,EACA,EAAY,KACZ,EAAK,MACL,aACA,EAAiB,EAAa,EAAK,OAAQ,MAAM,CACnD,EAEA,EAAO,KAAK,gBAAgB,EAG1B,GAAe,EAAY,MAC7B,EACE,EAAO,KACP,EACA,EAAY,KACZ,EAAK,OACL,WACA,EAAiB,EAAa,EAAK,MAAO,QAAQ,CACpD,EAGE,GACF,EAAa,EAAO,MAAO,EAAY,UAAY,SAAU,EAAK,MAAO,EAAK,MAAM,EACpF,EAAW,EAAO,MAAO,EAAQ,EAAa,EAAK,MAAO,QAAQ,GAElE,EAAO,MAAM,gBAAgB,EAG3B,IAAgB,CAAC,GAAY,GAAc,CAC7C,IAAM,EAAO,CAAE,GAAG,EAAa,SAAU,EAAY,OAAoB,EAAY,UAAY,MAAQ,EACzG,EAAa,EAAO,MAAO,EAAK,SAAU,EAAK,MAAO,EAAK,MAAM,EACjE,EAAW,EAAO,MAAO,EAAQ,EAAM,EAAK,OAAQ,MAAM,CAC5D,MACE,EAAO,MAAM,gBAAgB,EAG/B,GAAI,EAAU,CACP,IACH,EAAY,EAAiB,IAAK,CAAE,MAAO,oBAAqB,CAAC,EACjE,EAAI,UAAU,YAAY,CAAS,GAErC,IAAM,EAAO,CAAE,GAAG,EAAO,WAAY,SAAU,OAAiB,EAChE,EAAa,EAAW,QAAS,EAAK,MAAO,EAAK,MAAM,EACxD,EAAW,EAAW,EAAa,EAAM,EAAK,OAAQ,OAAO,CAC/D,MACE,GAAW,gBAAgB,EAG7B,KAAO,EAAO,OAAO,SAAS,OAAS,EAAW,QAChD,EAAO,OAAO,YAAY,EAAO,OAAO,SAAU,EAGpD,IAAM,EAAuB,CAAC,EAE9B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,OAAQ,IAAK,CAC1C,IAAM,EAAS,EAAW,GACtB,EAAQ,EAAO,OAAO,SAAS,GAE9B,IACH,EAAQ,EAAiB,IAAK,CAAE,MAAO,mBAAoB,CAAC,EAC5D,EAAO,OAAO,YAAY,CAAK,GAGjC,EAAM,aAAa,iBAAkB,EAAY,EAAQ,CAAC,CAAC,EAE3D,IAAM,EAAc,EAAO,QAAU,QAAU,EAAc,EACvD,EAAS,EAAc,EAAQ,GAAI,EAAQ,CAAW,EAE5D,EAAU,KAAK,CAAM,EAErB,EAAW,EAAO,EAAQ,CACxB,UAAW,EAAY,IAAI,CAAC,EAC5B,MAAO,EAAY,EAAG,EAAO,KAAK,EAClC,MAAO,EAAO,OAAS,SACvB,eAAgB,EAAI,eACpB,MAAO,EAAO,KACd,YAAa,EAAO,aAAe,EACnC,WAAY,EAAO,YAAc,GACjC,YAAa,EAAO,YACpB,WAAY,EAAO,UACrB,CAAC,CACH,CAMA,OAJA,GAAQ,OAAO,EAAW,KAAK,EAAG,KAAO,CAAE,MAAO,EAAY,EAAG,EAAE,KAAK,EAAG,KAAM,EAAE,IAAK,EAAE,CAAC,EAC3F,GAAS,KAAK,EACd,EAAU,EAAkB,EAAI,UAAW,CAAO,EAE3C,EAAwB,CAC7B,UAAW,EAAI,UACf,WAAc,EAAW,KAAK,EAAG,IAAM,EAAY,EAAG,EAAE,KAAK,CAAC,EAC9D,YACA,SAAY,EAAI,WAChB,YAAe,EACf,cAAiB,EACjB,kBAAqB,EACrB,SACA,UACA,QAAS,EAAO,QAChB,QAAS,EAAO,QAChB,YAAa,EAAO,OACpB,IAAK,EAAI,IACT,SACF,CAAC,CACH,EACC,GAAS,CACR,EAAa,CACf,CACF,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("../../_dev.cjs");const e=require("../../svg/element.cjs"),t=require("../../animation/easing.cjs"),n=require("../../animation/motion.cjs"),r=require("../../animation/tween.cjs"),i=require("../../core/datum-style.cjs"),
|
|
1
|
+
require("../../_dev.cjs");const e=require("../../svg/element.cjs"),t=require("../../animation/easing.cjs"),n=require("../../animation/motion.cjs"),r=require("../../animation/tween.cjs"),i=require("../../animation/transition.cjs"),a=require("../../core/datum-style.cjs"),o=require("../../svg/path.cjs");var s=new WeakMap,c=new WeakMap;function buildPath(e,t){return t===`monotone`?o.monotonePath(e):t===`step`?o.stepPath(e):o.linePath(e)}function renderLine(o,l,u){let d=a.hasStyledRuns(u.marks),f=u.marks??[],p=n.resolveMotion(u.transition),m=p.duration,h=t.resolveEasing(p.easing),g=null,_=[],v=[];if(d){_=a.computeStyleRuns(f,l.length);let t=[...o.querySelectorAll(`.prism-line-path`)];for(let e of t.slice(_.length))e.remove();v=_.map((n,r)=>{let i=t[r];if(i)return i;let a=e.createSvgElement(`path`,{class:`prism-line-path`,fill:`none`});return o.appendChild(a),a});for(let[t,n]of _.entries())e.setAttributes(v[t],{opacity:n.opacity,stroke:u.color,"stroke-dasharray":n.dash,"stroke-width":u.strokeWidth??2}),v[t].style.strokeWidth=u.strokeWidth===void 0?``:String(u.strokeWidth)}else{let t=[...o.querySelectorAll(`.prism-line-path`)];g=t[0]??null;for(let e of t.slice(1))e.remove();g||(g=e.createSvgElement(`path`,{class:`prism-line-path`,fill:`none`}),o.appendChild(g)),e.setAttributes(g,{opacity:void 0,stroke:u.color,"stroke-dasharray":void 0,"stroke-width":u.strokeWidth??2}),g.style.strokeWidth=u.strokeWidth===void 0?``:String(u.strokeWidth)}let draw=t=>{if(d)for(let[n,r]of _.entries())e.setAttributes(v[n],{d:buildPath(t.slice(r.start,r.end+1),u.curve)});else e.setAttributes(g,{d:buildPath(t,u.curve)})},y=o.querySelector(`.prism-line-dots`);if(u.showPoints?y||(y=e.createSvgElement(`g`,{class:`prism-line-dots`}),o.appendChild(y)):y&&=(y.remove(),null),m===0){if(draw(l),c.set(o,l),y){for(;y.children.length>l.length;)y.removeChild(y.lastChild);for(let t=0;t<l.length;t++){let n=y.children[t];n||(n=e.createSvgElement(`circle`,{class:`prism-line-dot`}),y.appendChild(n)),e.setAttributes(n,{cx:l[t].x,cy:l[t].y,fill:u.color,opacity:f[t]?.opacity,r:u.pointRadius})}}return}s.get(o)?.();let b=!c.has(o),x=b?l.map(e=>({x:e.x,y:u.baselineY})):[];if(y){for(;y.children.length>l.length;)y.removeChild(y.lastChild);for(let t=y.children.length;t<l.length;t++){let n=e.createSvgElement(`circle`,{class:`prism-line-dot`});e.setAttributes(n,{fill:u.color,opacity:f[t]?.opacity,r:u.pointRadius}),y.appendChild(n)}for(let t=0;t<y.children.length;t++)e.setAttributes(y.children[t],{opacity:f[t]?.opacity})}if(!b){let e=c.get(o)??l;for(let[t,n]of l.entries())x.push(e[t]??e.at(-1)??n)}let paintFrame=t=>{let n=l.map((e,n)=>{let i=x[n]??e;return{x:r.tweenNumber(i.x,e.x,t),y:r.tweenNumber(i.y,e.y,t)}});if(c.set(o,n),draw(n),y)for(let t=0;t<l.length;t++){let r=y.children[t];r&&e.setAttributes(r,{cx:n[t].x,cy:n[t].y})}};paintFrame(0),s.set(o,i.startTween({count:1,duration:m,easing:h,onComplete:()=>{s.delete(o),c.set(o,l)},onFrame:e=>paintFrame(e(0)),signal:u.disposalSignal}))}function computePoints(e,t,n){return e.some(e=>e.key==null)||e.some(e=>typeof e.key==`string`),e.map(e=>({x:t.map(e.key),y:n.map(e.value)}))}exports.computePoints=computePoints,exports.renderLine=renderLine;
|
|
2
2
|
//# sourceMappingURL=line-renderer.cjs.map
|
|
@@ -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 { 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, TransitionConfig } from '../../types';\n\nexport interface LineRenderOptions {\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?: TransitionConfig;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\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, 0);\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 draw(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\n const hasExisting = styled ? runPaths.some((p) => p.hasAttribute('d')) : !!path?.getAttribute('d');\n\n const fromPts: Point[] = [];\n let lastKnown: Point | null = null;\n\n if (dotsGroup) {\n const existingCount = dotsGroup.children.length;\n\n for (let i = 0; i < existingCount; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement;\n const pt = { x: Number(c.getAttribute('cx')), y: Number(c.getAttribute('cy')) };\n\n fromPts.push(pt);\n lastKnown = pt;\n }\n\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 cx: points[i].x,\n cy: points[i].y,\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 for (let i = fromPts.length; i < points.length; i++) {\n fromPts.push(lastKnown ?? points[i]);\n }\n\n let startTime: number | null = null;\n\n function frame(ts: number) {\n if (options.disposalSignal?.aborted) {\n activeAnimations.delete(parent);\n\n return;\n }\n\n if (startTime === null) startTime = ts;\n\n const t = Math.min(1, (ts - startTime) / dur);\n const e = easing(t);\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 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 if (t < 1) {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n } else {\n activeAnimations.delete(parent);\n }\n }\n\n if (!hasExisting) {\n draw(points);\n } else {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\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.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 { 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 bottom in area-local coordinates: the mount animation raises the line from here. */\n baselineY: 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 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\n const hasExisting = drawnPoints.has(parent);\n // A first render has no drawn shape to interpolate between: the mount animation\n // raises the whole line from the plot baseline instead.\n const isMount = !hasExisting;\n\n const fromPts: Point[] = isMount ? points.map((p) => ({ x: p.x, y: options.baselineY })) : [];\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 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\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,7 +1,9 @@
|
|
|
1
1
|
import { type DatumMark } from '../../core/datum-style';
|
|
2
2
|
import type { Point } from '../../svg/path';
|
|
3
|
-
import type { ContinuousDatum, Scale,
|
|
3
|
+
import type { ContinuousDatum, Scale, TransitionOption } from '../../types';
|
|
4
4
|
export interface LineRenderOptions {
|
|
5
|
+
/** Plot-area bottom in area-local coordinates: the mount animation raises the line from here. */
|
|
6
|
+
baselineY: number;
|
|
5
7
|
color: string;
|
|
6
8
|
curve: 'linear' | 'monotone' | 'step';
|
|
7
9
|
/** Aborted when the owning chart is disposed: stops the transition's `requestAnimationFrame` loop from rescheduling. */
|
|
@@ -12,7 +14,7 @@ export interface LineRenderOptions {
|
|
|
12
14
|
showPoints: boolean;
|
|
13
15
|
/** Explicit width beats the `--prism-line-width` theme token. */
|
|
14
16
|
strokeWidth?: number;
|
|
15
|
-
transition?:
|
|
17
|
+
transition?: TransitionOption;
|
|
16
18
|
}
|
|
17
19
|
export declare function renderLine(parent: SVGGElement, points: Point[], options: LineRenderOptions): void;
|
|
18
20
|
export declare function computePoints(data: ContinuousDatum[], xScale: Scale<Date | number>, yScale: Scale<number>): Point[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-renderer.d.ts","sourceRoot":"","sources":["../../../src/charts/line/line-renderer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"line-renderer.d.ts","sourceRoot":"","sources":["../../../src/charts/line/line-renderer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,KAAK,SAAS,EAAgC,MAAM,wBAAwB,CAAC;AAExG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,iGAAiG;IACjG,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IACtC,wHAAwH;IACxH,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,6FAA6F;IAC7F,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAWD,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAuLjG;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,EAAE,CAanH"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"../../_dev.js";import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{resolveEasing as n}from"../../animation/easing.js";import{resolveMotion as r}from"../../animation/motion.js";import{tweenNumber as i}from"../../animation/tween.js";import{computeStyleRuns as
|
|
1
|
+
import"../../_dev.js";import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{resolveEasing as n}from"../../animation/easing.js";import{resolveMotion as r}from"../../animation/motion.js";import{tweenNumber as i}from"../../animation/tween.js";import{startTween as a}from"../../animation/transition.js";import{computeStyleRuns as o,hasStyledRuns as s}from"../../core/datum-style.js";import{linePath as c,monotonePath as l,stepPath as u}from"../../svg/path.js";var d=new WeakMap,f=new WeakMap;function buildPath(e,t){return t===`monotone`?l(e):t===`step`?u(e):c(e)}function renderLine(c,l,u){let p=s(u.marks),m=u.marks??[],h=r(u.transition),g=h.duration,_=n(h.easing),v=null,y=[],b=[];if(p){y=o(m,l.length);let n=[...c.querySelectorAll(`.prism-line-path`)];for(let e of n.slice(y.length))e.remove();b=y.map((t,r)=>{let i=n[r];if(i)return i;let a=e(`path`,{class:`prism-line-path`,fill:`none`});return c.appendChild(a),a});for(let[e,n]of y.entries())t(b[e],{opacity:n.opacity,stroke:u.color,"stroke-dasharray":n.dash,"stroke-width":u.strokeWidth??2}),b[e].style.strokeWidth=u.strokeWidth===void 0?``:String(u.strokeWidth)}else{let n=[...c.querySelectorAll(`.prism-line-path`)];v=n[0]??null;for(let e of n.slice(1))e.remove();v||(v=e(`path`,{class:`prism-line-path`,fill:`none`}),c.appendChild(v)),t(v,{opacity:void 0,stroke:u.color,"stroke-dasharray":void 0,"stroke-width":u.strokeWidth??2}),v.style.strokeWidth=u.strokeWidth===void 0?``:String(u.strokeWidth)}let draw=e=>{if(p)for(let[n,r]of y.entries())t(b[n],{d:buildPath(e.slice(r.start,r.end+1),u.curve)});else t(v,{d:buildPath(e,u.curve)})},x=c.querySelector(`.prism-line-dots`);if(u.showPoints?x||(x=e(`g`,{class:`prism-line-dots`}),c.appendChild(x)):x&&=(x.remove(),null),g===0){if(draw(l),f.set(c,l),x){for(;x.children.length>l.length;)x.removeChild(x.lastChild);for(let n=0;n<l.length;n++){let r=x.children[n];r||(r=e(`circle`,{class:`prism-line-dot`}),x.appendChild(r)),t(r,{cx:l[n].x,cy:l[n].y,fill:u.color,opacity:m[n]?.opacity,r:u.pointRadius})}}return}d.get(c)?.();let S=!f.has(c),C=S?l.map(e=>({x:e.x,y:u.baselineY})):[];if(x){for(;x.children.length>l.length;)x.removeChild(x.lastChild);for(let n=x.children.length;n<l.length;n++){let r=e(`circle`,{class:`prism-line-dot`});t(r,{fill:u.color,opacity:m[n]?.opacity,r:u.pointRadius}),x.appendChild(r)}for(let e=0;e<x.children.length;e++)t(x.children[e],{opacity:m[e]?.opacity})}if(!S){let e=f.get(c)??l;for(let[t,n]of l.entries())C.push(e[t]??e.at(-1)??n)}let paintFrame=e=>{let n=l.map((t,n)=>{let r=C[n]??t;return{x:i(r.x,t.x,e),y:i(r.y,t.y,e)}});if(f.set(c,n),draw(n),x)for(let e=0;e<l.length;e++){let r=x.children[e];r&&t(r,{cx:n[e].x,cy:n[e].y})}};paintFrame(0),d.set(c,a({count:1,duration:g,easing:_,onComplete:()=>{d.delete(c),f.set(c,l)},onFrame:e=>paintFrame(e(0)),signal:u.disposalSignal}))}function computePoints(e,t,n){return e.some(e=>e.key==null)||e.some(e=>typeof e.key==`string`),e.map(e=>({x:t.map(e.key),y:n.map(e.value)}))}export{computePoints,renderLine};
|
|
2
2
|
//# 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 { 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, TransitionConfig } from '../../types';\n\nexport interface LineRenderOptions {\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?: TransitionConfig;\n}\n\nconst activeAnimations = new WeakMap<SVGGElement, () => void>();\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, 0);\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 draw(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\n const hasExisting = styled ? runPaths.some((p) => p.hasAttribute('d')) : !!path?.getAttribute('d');\n\n const fromPts: Point[] = [];\n let lastKnown: Point | null = null;\n\n if (dotsGroup) {\n const existingCount = dotsGroup.children.length;\n\n for (let i = 0; i < existingCount; i++) {\n const c = dotsGroup.children[i] as SVGCircleElement;\n const pt = { x: Number(c.getAttribute('cx')), y: Number(c.getAttribute('cy')) };\n\n fromPts.push(pt);\n lastKnown = pt;\n }\n\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 cx: points[i].x,\n cy: points[i].y,\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 for (let i = fromPts.length; i < points.length; i++) {\n fromPts.push(lastKnown ?? points[i]);\n }\n\n let startTime: number | null = null;\n\n function frame(ts: number) {\n if (options.disposalSignal?.aborted) {\n activeAnimations.delete(parent);\n\n return;\n }\n\n if (startTime === null) startTime = ts;\n\n const t = Math.min(1, (ts - startTime) / dur);\n const e = easing(t);\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 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 if (t < 1) {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\n } else {\n activeAnimations.delete(parent);\n }\n }\n\n if (!hasExisting) {\n draw(points);\n } else {\n const id = requestAnimationFrame(frame);\n\n activeAnimations.set(parent, () => cancelAnimationFrame(id));\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":[],"sources":["../../../src/charts/line/line-renderer.ts"],"sourcesContent":["import { warn } from '../../_dev';\nimport { resolveEasing } from '../../animation/easing';\nimport { resolveMotion } from '../../animation/motion';\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 bottom in area-local coordinates: the mount animation raises the line from here. */\n baselineY: 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 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\n const hasExisting = drawnPoints.has(parent);\n // A first render has no drawn shape to interpolate between: the mount animation\n // raises the whole line from the plot baseline instead.\n const isMount = !hasExisting;\n\n const fromPts: Point[] = isMount ? points.map((p) => ({ x: p.x, y: options.baselineY })) : [];\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 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\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("./pie-renderer.cjs");var
|
|
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;x.contains(m)||(x.appendChild(m),x.appendChild(h),x.appendChild(g));let{height:C,width:w}=n.dimensions,T=u===`semi`,E=w/2,D=T?C*.85:C/2,O=T?Math.min(E,D)-8:Math.min(w,C)/2-8,k=u===`pie`?0:Math.round(O*.55),A=l.innerRadius===void 0?k:l.innerRadius,j=Math.max(A+1,O),M=p,{end:N,start:P}=semiAngles(u);for(_=c.computeArcs(M,E,D,j,A,P,N,d,f,e=>r.seriesColor(e),!1),e.setAttributes(m,{cx:E,cy:D,r:A>0?A:0}),m.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);h.children.length>_.length;)h.removeChild(h.lastChild);g.replaceChildren();let F=a.resolveMotion(l.transition),I=F.duration,L=i.resolveEasing(F.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 R=v.length===0,z=v;y=s.startTween({count:1,duration:I,easing:L,onComplete:()=>renderLabels(M),onFrame:t=>{let n=t(0);if(R){let t=o.tweenNumber(P,N,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}});return}v=_.map((t,r)=>{let i=h.children[r],a=z.at(-1),s=z[r]??{...t,endAngle:a?.endAngle??P,startAngle:a?.endAngle??P},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}),b?.update(_.map(e=>({color:e.color,name:e.slice.label??``}))),S?.hide();let B=_.reduce((e,t)=>e+Math.max(0,t.slice.value),0),V=-1,describe=e=>{let t=B>0?Math.round(Math.max(0,e.slice.value)/B*1e3)/10:0;return`${e.slice.label??`Slice ${e.index+1}`}: ${e.slice.value} (${t}%)`},setActive=e=>{V=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!==V&&activate(t,e):V>=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(V<0?n[e.key]>0?0:t-1:(V+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===` `)&&V>=0&&l.onClick?(e.preventDefault(),l.onClick({index:V,originalEvent:e,slice:_[V].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 { 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 let activeRaf: number | 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 let handle: ChartHandle<PieSliceConfig[]> | undefined;\n\n try {\n handle = 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\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, 0);\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 if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n if (dur > 0) {\n let rafStart: number | null = null;\n\n const frame = (ts: number) => {\n if (rafStart === null) rafStart = ts;\n\n const t = easing(Math.min(1, (ts - rafStart) / dur));\n const revealAngle = tweenNumber(start, end, t);\n\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (!el) continue;\n\n if (revealAngle <= a.startAngle) {\n setAttributes(el, { d: '' });\n } else {\n const visibleEnd = Math.min(a.endAngle, revealAngle);\n\n setAttributes(el, { d: arcPath({ ...a, endAngle: visibleEnd }) });\n }\n }\n\n if (t < 1) {\n activeRaf = requestAnimationFrame(frame);\n } else {\n activeRaf = null;\n renderLabels(slices);\n }\n };\n\n activeRaf = requestAnimationFrame(frame);\n } else {\n for (let j = 0; j < currentArcs.length; j++) {\n const a = currentArcs[j];\n const el = pieGroup.children[j] as SVGPathElement | undefined;\n\n if (el) setAttributes(el, { d: arcPath(a) });\n }\n\n renderLabels(slices);\n }\n\n legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\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): void => {\n const arc = currentArcs[index];\n\n if (!arc) return;\n\n setActive(index);\n config.onHover?.(arc.slice, index);\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, 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);\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(currentArcs[hit].slice, hit);\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(activeIndex < 0 ? (step[e.key] > 0 ? 0 : count - 1) : (activeIndex + step[e.key] + count) % count);\n } else if (e.key === 'Home' || e.key === 'End') {\n e.preventDefault();\n activate(e.key === 'Home' ? 0 : count - 1);\n } else if ((e.key === 'Enter' || e.key === ' ') && activeIndex >= 0 && config.onClick) {\n e.preventDefault();\n config.onClick(currentArcs[activeIndex].slice, activeIndex);\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 return {\n get disposalSignal(): AbortSignal {\n return handle!.disposalSignal;\n },\n\n dispose() {\n if (activeRaf !== null) {\n cancelAnimationFrame(activeRaf);\n activeRaf = null;\n }\n\n handle!.dispose();\n },\n\n get disposed(): boolean {\n return handle!.disposed;\n },\n\n el: handle!.el,\n\n update(next) {\n handle!.update(next);\n },\n\n [Symbol.dispose]() {\n this.dispose();\n },\n };\n } catch (error) {\n handle?.dispose();\n throw error;\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":[],"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\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 legend?.update(currentArcs.map((arc) => ({ color: arc.color, name: arc.slice.label ?? '' })));\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":"0VAYA,IAAM,EAAS,EAAI,KAAK,GAElB,EAAkB,GAGxB,SAAS,UAAU,EAAU,EAAwB,CACnD,IAAM,EAAY,EAAI,YAAc,EAAI,YAClC,GAAa,EAAI,YAAc,EAAI,aAAe,EAClD,GAAa,EAAI,SAAW,EAAI,WAAa,EAAI,EAAI,UAAY,EAEvE,OAAO,GAAa,EAAkB,KAAO,GAAa,EAAA,kBAAkB,EAAO,CAAe,EAAI,CACxG,CAEA,IAAM,EAAa,CAAC,KAAK,GAAK,EACxB,EAAW,KAAK,GAAK,EAE3B,SAAS,WAAW,EAAoE,CACtF,OAAO,IAAY,OAAS,CAAE,IAAK,EAAU,MAAO,CAAW,EAAI,CAAE,IAAK,EAAQ,MAAO,CAAE,CAC7F,CAEA,SAAgB,eAAe,EAAwB,EAAuD,CAC5G,IAAM,EAAU,EAAO,SAAW,MAC5B,EAAY,EAAO,YAAc,IAAY,MAAQ,EAAI,GACzD,EAAe,EAAO,eAAiB,IAAY,MAAQ,EAAI,GACjE,EAAO,EAAO,KAIZ,EAAW,EAAA,iBAAiB,SAAU,CAAE,MAAO,eAAgB,iBAAkB,MAAO,CAAC,EACzF,EAAW,EAAA,iBAAiB,IAAK,CACrC,MAAO,mBACP,kBAAmB,oBACrB,CAAC,EACK,EAAa,EAAA,iBAAiB,IAAK,CAAE,MAAO,mBAAoB,iBAAkB,MAAO,CAAC,EAG5F,EAAqB,CAAC,EAGtB,EAAmB,CAAC,EACpB,EAAmC,KAEvC,SAAS,aAAa,EAAgC,CACpD,EAAW,gBAAgB,EAE3B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,IAAM,EAAM,EAAY,GAClB,EAAQ,EAAO,GAErB,GAAI,CAAC,GAAO,OAAS,CAAC,UAAU,EAAK,EAAM,KAAK,EAAG,SAEnD,GAAM,CAAE,IAAG,KAAM,EAAA,YAAY,CAAG,EAC1B,EAAO,EAAA,iBAAiB,OAAQ,CAAE,MAAO,iBAAkB,CAAC,EAElE,EAAA,cAAc,EAAM,CAClB,oBAAqB,SACrB,KAAM,qCACN,cAAe,sCACf,YAAa,oCACb,cAAe,SACf,IACA,GACF,CAAC,EAED,EAAK,YAAc,EAAM,MACzB,EAAW,YAAY,CAAI,CAC7B,CACF,CAEA,OAAO,EAAA,qBACL,EACA,CACE,KAAM,EAAO,KACb,OAAQ,EAAO,OACf,QAAS,EAAO,OAClB,EACC,GAA4B,CAC3B,GAAM,CAAE,SAAQ,MAAK,WAAY,EAG5B,EAAI,SAAS,CAAQ,IACxB,EAAI,YAAY,CAAQ,EACxB,EAAI,YAAY,CAAQ,EACxB,EAAI,YAAY,CAAU,GAG5B,GAAM,CAAE,OAAQ,EAAG,MAAO,GAAM,EAAI,WAC9B,EAAS,IAAY,OACrB,EAAK,EAAI,EACT,EAAK,EAAS,EAAI,IAAO,EAAI,EAE7B,EAAQ,EAAS,KAAK,IAAI,EAAI,CAAE,EAAI,EAAU,KAAK,IAAI,EAAG,CAAC,EAAI,EAAI,EACnE,EAAe,IAAY,MAAQ,EAAI,KAAK,MAAM,EAAQ,GAAI,EAC9D,EAAQ,EAAO,cAAgB,IAAA,GAAiC,EAArB,EAAO,YAClD,EAAS,KAAK,IAAI,EAAQ,EAAG,CAAK,EAElC,EAAS,EACT,CAAE,MAAK,SAAU,WAAW,CAAO,EAmBzC,IAjBA,EAAc,EAAA,YACZ,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACC,GAAM,EAAA,YAAY,CAAC,EACpB,EACF,EAEA,EAAA,cAAc,EAAU,CAAE,KAAI,KAAI,EAAG,EAAQ,EAAI,EAAQ,CAAE,CAAC,EAC5D,EAAS,aAAa,QAAS,2BAA2B,EAEnD,EAAS,SAAS,OAAS,EAAY,QAAQ,EAAS,YAAY,EAAS,SAAU,EAE9F,EAAW,gBAAgB,EAE3B,IAAM,EAAS,EAAA,cAAc,EAAO,UAAU,EACxC,EAAM,EAAO,SACb,EAAS,EAAA,cAAc,EAAO,MAAM,EAE1C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,IAAM,EAAM,EAAY,GACpB,EAAO,EAAS,SAAS,GAExB,IACH,EAAO,EAAA,iBAAiB,OAAQ,CAAE,MAAO,iBAAkB,CAAC,EAC5D,EAAS,YAAY,CAAI,GAG3B,EAAK,aAAa,OAAQ,EAAI,KAAK,EACnC,EAAK,aAAa,SAAU,MAAM,EAClC,EAAK,MAAM,OAAS,EAAO,SAAW,EAAO,QAAU,UAAY,EACrE,CAEA,IAAc,EAKd,IAAM,EAAU,EAAU,SAAW,EAC/B,EAAW,EAEjB,EAAc,EAAA,WAAW,CACvB,MAAO,EACP,SAAU,EACV,SACA,eAAkB,aAAa,CAAM,EACrC,QAAU,GAAa,CACrB,IAAM,EAAI,EAAS,CAAC,EAEpB,GAAI,EAAS,CACX,IAAM,EAAc,EAAA,YAAY,EAAO,EAAK,CAAC,EAE7C,EAAY,EAAY,KAAK,EAAG,IAAM,CACpC,IAAM,EAAK,EAAS,SAAS,GAE7B,GAAI,CAAC,EAAI,OAAO,EAEhB,GAAI,GAAe,EAAE,WAGnB,OAFA,EAAA,cAAc,EAAI,CAAE,EAAG,EAAG,CAAC,EAEpB,CAAE,GAAG,EAAG,SAAU,EAAE,UAAW,EAGxC,IAAM,EAAa,KAAK,IAAI,EAAE,SAAU,CAAW,EAInD,OAFA,EAAA,cAAc,EAAI,CAAE,EAAG,EAAA,QAAQ,CAAE,GAAG,EAAG,SAAU,CAAW,CAAC,CAAE,CAAC,EAEzD,CAAE,GAAG,EAAG,SAAU,CAAW,CACtC,CAAC,EAED,MACF,CAEA,EAAY,EAAY,KAAK,EAAI,IAAM,CACrC,IAAM,EAAK,EAAS,SAAS,GACvB,EAAY,EAAS,GAAG,EAAE,EAE1B,EAAY,EAAS,IAAM,CAC/B,GAAG,EACH,SAAU,GAAW,UAAY,EACjC,WAAY,GAAW,UAAY,CACrC,EACM,EAAe,CACnB,GAAG,EACH,SAAU,EAAA,YAAY,EAAK,SAAU,EAAG,SAAU,CAAC,EACnD,YAAa,EAAA,YAAY,EAAK,YAAa,EAAG,YAAa,CAAC,EAC5D,YAAa,EAAA,YAAY,EAAK,YAAa,EAAG,YAAa,CAAC,EAC5D,SAAU,EAAA,YAAY,EAAK,SAAU,EAAG,SAAU,CAAC,EACnD,WAAY,EAAA,YAAY,EAAK,WAAY,EAAG,WAAY,CAAC,CAC3D,EAQA,OANK,GAEL,EAAA,cAAc,EAAI,CAChB,EAAG,EAAQ,SAAW,EAAQ,YAAc,KAAO,GAAK,EAAA,QAAQ,CAAO,CACzE,CAAC,EAJe,CAOlB,CAAC,CACH,EACA,OAAQ,EAAI,cACd,CAAC,EAED,GAAQ,OAAO,EAAY,IAAK,IAAS,CAAE,MAAO,EAAI,MAAO,KAAM,EAAI,MAAM,OAAS,EAAG,EAAE,CAAC,EAC5F,GAAS,KAAK,EAEd,IAAM,EAAQ,EAAY,QAAQ,EAAK,IAAQ,EAAM,KAAK,IAAI,EAAG,EAAI,MAAM,KAAK,EAAG,CAAC,EAChF,EAAc,GAEZ,SAAY,GAAqB,CACrC,IAAM,EAAU,EAAQ,EAAI,KAAK,MAAO,KAAK,IAAI,EAAG,EAAI,MAAM,KAAK,EAAI,EAAS,GAAI,EAAI,GAAK,EAE7F,MAAO,GAAG,EAAI,MAAM,OAAS,SAAS,EAAI,MAAQ,IAAI,IAAI,EAAI,MAAM,MAAM,IAAI,EAAQ,GACxF,EAEM,UAAa,GAAwB,CACzC,EAAc,EACd,EAAS,UAAU,OAAO,oBAAqB,GAAS,CAAC,EACzD,IAAK,GAAM,CAAC,EAAG,IAAO,CAAC,GAAG,EAAS,QAAQ,CAAC,CAAC,QAAQ,EACnD,EAAG,UAAU,OAAO,0BAA2B,IAAM,CAAK,CAC9D,EAEM,UAAY,EAAe,IAA+B,CAC9D,IAAM,EAAM,EAAY,GAExB,GAAI,CAAC,EAAK,OAEV,UAAU,CAAK,EACf,EAAO,UAAU,CAAE,QAAO,gBAAe,MAAO,EAAI,KAAM,CAAC,EAE3D,IAAM,EAAO,SAAS,CAAG,EAEzB,GAAI,CAAC,EAAS,CACZ,EAAI,UAAU,SAAS,CAAI,EAE3B,MACF,CAEA,GAAM,CAAE,IAAG,KAAM,EAAA,YAAY,CAAG,EAC1B,EAAU,EAAI,sBAAsB,EACpC,EAAQ,EAAU,sBAAsB,EAE9C,EAAQ,KACN,GAAK,EAAQ,KAAO,EAAM,MAC1B,GAAK,EAAQ,IAAM,EAAM,KACzB,CAAE,IAAK,EAAO,MAAO,EAAI,MAAM,KAAM,EACrC,CAAE,MAAO,EAAI,MAAO,KAAM,CAAC,EAAG,KAAM,EAAI,MAAM,OAAS,EAAG,EAC1D,CACF,CACF,EAEM,eAAyB,CAC7B,UAAU,EAAE,EACZ,GAAS,KAAK,EACd,EAAI,UAAU,MAAM,EACpB,EAAO,UAAU,IAAI,CACvB,EAEM,MAAS,GAA0B,CACvC,IAAM,EAAU,EAAI,sBAAsB,EAE1C,OAAO,WAAW,EAAa,EAAE,QAAU,EAAQ,KAAM,EAAE,QAAU,EAAQ,IAAK,CAAO,CAC3F,EAEM,YAAe,GAAwB,CAC3C,IAAM,EAAM,MAAM,CAAC,EAEf,GAAO,EACL,IAAQ,GAAa,SAAS,EAAK,CAAC,EAC/B,GAAe,GACxB,WAAW,CAEf,EAEM,QAAW,GAAwB,CACvC,GAAI,CAAC,EAAO,QAAS,OAErB,IAAM,EAAM,MAAM,CAAC,EAEf,GAAO,GAAG,EAAO,QAAQ,CAAE,MAAO,EAAK,cAAe,EAAG,MAAO,EAAY,EAAI,CAAC,KAAM,CAAC,CAC9F,EAEM,UAAa,GAA2B,CAC5C,IAAM,EAAQ,EAAY,OAE1B,GAAI,IAAU,EAAG,OAEjB,IAAM,EAA+B,CAAE,UAAW,EAAG,UAAW,GAAI,WAAY,EAAG,QAAS,EAAG,EAE3F,EAAE,OAAO,GACX,EAAE,eAAe,EACjB,SACE,EAAc,EAAK,EAAK,EAAE,KAAO,EAAI,EAAI,EAAQ,GAAM,EAAc,EAAK,EAAE,KAAO,GAAS,EAC5F,CACF,GACS,EAAE,MAAQ,QAAU,EAAE,MAAQ,OACvC,EAAE,eAAe,EACjB,SAAS,EAAE,MAAQ,OAAS,EAAI,EAAQ,EAAG,CAAC,IAClC,EAAE,MAAQ,SAAW,EAAE,MAAQ,MAAQ,GAAe,GAAK,EAAO,SAC5E,EAAE,eAAe,EACjB,EAAO,QAAQ,CAAE,MAAO,EAAa,cAAe,EAAG,MAAO,EAAY,EAAY,CAAC,KAAM,CAAC,GACrF,EAAE,MAAQ,UACnB,WAAW,CAEf,EAEA,MAAO,CAAE,QAAS,UAAW,aAAc,WAAY,WAAY,CACrE,EACC,GAAS,CACR,EAAO,CACT,CACF,CACF,CAEA,SAAS,WAAW,EAAa,EAAY,EAAY,EAA4C,CACnG,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,EAAK,GACX,EAAK,EAAK,EAAI,QACd,EAAK,EAAK,EAAI,QACd,EAAO,KAAK,KAAK,EAAK,EAAK,EAAK,CAAE,EAExC,GAAI,EAAO,EAAI,aAAe,GAAQ,EAAI,YAAa,CACrD,IAAM,EAAW,KAAK,MAAM,EAAI,CAAC,CAAE,EAEnC,GAAI,IAAY,OACV,IAAA,GAAY,EAAI,WAAa,MAAQ,GAAY,EAAI,SAAW,KAAM,OAAO,CAAA,KAC5E,CACL,IAAM,EAAQ,EAAW,EAAI,EAAW,EAAS,EAEjD,GAAI,GAAS,EAAI,WAAa,MAAQ,GAAS,EAAI,SAAW,KAAM,OAAO,CAC7E,CACF,CACF,CAEA,MAAO,EACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/pie/pie-chart.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../src/charts/pie/pie-chart.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAuB/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,GAAG,WAAW,CAAC,cAAc,EAAE,CAAC,CAyS5G"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{estimateTextWidth as n}from"../../svg/text.js";import{createRadialScaffold as r}from"../../core/chart-scaffold.js";import{seriesColor as i}from"../../theme/index.js";import{resolveEasing as a}from"../../animation/easing.js";import{resolveMotion as o}from"../../animation/motion.js";import{tweenNumber as s}from"../../animation/tween.js";import{arcCentroid as
|
|
1
|
+
import{createSvgElement as e,setAttributes as t}from"../../svg/element.js";import{estimateTextWidth as n}from"../../svg/text.js";import{createRadialScaffold as r}from"../../core/chart-scaffold.js";import{seriesColor as i}from"../../theme/index.js";import{resolveEasing as a}from"../../animation/easing.js";import{resolveMotion as o}from"../../animation/motion.js";import{tweenNumber as s}from"../../animation/tween.js";import{startTween as c}from"../../animation/transition.js";import{arcCentroid as l,arcPath as u,computeArcs as d}from"./pie-renderer.js";var f=2*Math.PI,p=12;function labelFits(e,t){let r=e.outerRadius-e.innerRadius,i=(e.outerRadius+e.innerRadius)/2,a=(e.endAngle-e.startAngle-2*e.padAngle)*i;return r>=p*1.4&&a>=n(t,p)+8}var m=-Math.PI/2,h=Math.PI/2;function semiAngles(e){return e===`semi`?{end:h,start:m}:{end:f,start:0}}function createPieChart(n,f){let p=f.variant??`pie`,m=f.padPixels??(p===`pie`?0:8),h=f.cornerRadius??(p===`pie`?0:8),g=f.data,_=e(`circle`,{class:`prism-pie-bg`,"pointer-events":`none`}),v=e(`g`,{class:`prism-pie-slices`,"shape-rendering":`geometricPrecision`}),y=e(`g`,{class:`prism-pie-labels`,"pointer-events":`none`}),b=[],x=[],S=null;function renderLabels(n){y.replaceChildren();for(let r=0;r<b.length;r++){let i=b[r],a=n[r];if(!a?.label||!labelFits(i,a.label))continue;let{x:o,y:s}=l(i),c=e(`text`,{class:`prism-pie-label`});t(c,{"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:o,y:s}),c.textContent=a.label,y.appendChild(c)}}return r(n,{a11y:f.a11y,legend:f.legend,tooltip:f.tooltip},r=>{let{legend:C,svg:w,tooltip:T}=r;w.contains(_)||(w.appendChild(_),w.appendChild(v),w.appendChild(y));let{height:E,width:D}=r.dimensions,O=p===`semi`,k=D/2,A=O?E*.85:E/2,j=O?Math.min(k,A)-8:Math.min(D,E)/2-8,M=p===`pie`?0:Math.round(j*.55),N=f.innerRadius===void 0?M:f.innerRadius,P=Math.max(N+1,j),F=g,{end:I,start:L}=semiAngles(p);for(b=d(F,k,A,P,N,L,I,m,h,e=>i(e),!1),t(_,{cx:k,cy:A,r:N>0?N:0}),_.setAttribute(`style`,`fill:var(--prism-bg,#fff)`);v.children.length>b.length;)v.removeChild(v.lastChild);y.replaceChildren();let R=o(f.transition),z=R.duration,B=a(R.easing);for(let t=0;t<b.length;t++){let n=b[t],r=v.children[t];r||(r=e(`path`,{class:`prism-pie-slice`}),v.appendChild(r)),r.setAttribute(`fill`,n.color),r.setAttribute(`stroke`,`none`),r.style.cursor=f.onClick||f.onHover?`pointer`:``}S?.();let V=x.length===0,H=x;S=c({count:1,duration:z,easing:B,onComplete:()=>renderLabels(F),onFrame:e=>{let n=e(0);if(V){let e=s(L,I,n);x=b.map((n,r)=>{let i=v.children[r];if(!i)return n;if(e<=n.startAngle)return t(i,{d:``}),{...n,endAngle:n.startAngle};let a=Math.min(n.endAngle,e);return t(i,{d:u({...n,endAngle:a})}),{...n,endAngle:a}});return}x=b.map((e,r)=>{let i=v.children[r],a=H.at(-1),o=H[r]??{...e,endAngle:a?.endAngle??L,startAngle:a?.endAngle??L},c={...e,endAngle:s(o.endAngle,e.endAngle,n),innerRadius:s(o.innerRadius,e.innerRadius,n),outerRadius:s(o.outerRadius,e.outerRadius,n),padAngle:s(o.padAngle,e.padAngle,n),startAngle:s(o.startAngle,e.startAngle,n)};return i&&t(i,{d:c.endAngle-c.startAngle<=1e-6?``:u(c)}),c})},signal:r.disposalSignal}),C?.update(b.map(e=>({color:e.color,name:e.slice.label??``}))),T?.hide();let U=b.reduce((e,t)=>e+Math.max(0,t.slice.value),0),W=-1,describe=e=>{let t=U>0?Math.round(Math.max(0,e.slice.value)/U*1e3)/10:0;return`${e.slice.label??`Slice ${e.index+1}`}: ${e.slice.value} (${t}%)`},setActive=e=>{W=e,v.classList.toggle(`prism-pie-focused`,e>=0);for(let[t,n]of[...v.children].entries())n.classList.toggle(`prism-pie-slice--active`,t===e)},activate=(e,t)=>{let i=b[e];if(!i)return;setActive(e),f.onHover?.({index:e,originalEvent:t,slice:i.slice});let a=describe(i);if(!T){r.announcer.announce(a);return}let{x:o,y:s}=l(i),c=w.getBoundingClientRect(),u=n.getBoundingClientRect();T.show(o+(c.left-u.left),s+(c.top-u.top),{key:e,value:i.slice.value},{color:i.color,data:[],name:i.slice.label??``},a)},deactivate=()=>{setActive(-1),T?.hide(),r.announcer.clear(),f.onHover?.(null)},hitAt=e=>{let t=w.getBoundingClientRect();return hitTestArc(b,e.clientX-t.left,e.clientY-t.top,p)},onMouseMove=e=>{let t=hitAt(e);t>=0?t!==W&&activate(t,e):W>=0&&deactivate()},onClick=e=>{if(!f.onClick)return;let t=hitAt(e);t>=0&&f.onClick({index:t,originalEvent:e,slice:b[t].slice})},onKeyDown=e=>{let t=b.length;if(t===0)return;let n={ArrowDown:1,ArrowLeft:-1,ArrowRight:1,ArrowUp:-1};e.key in n?(e.preventDefault(),activate(W<0?n[e.key]>0?0:t-1:(W+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===` `)&&W>=0&&f.onClick?(e.preventDefault(),f.onClick({index:W,originalEvent:e,slice:b[W].slice})):e.key===`Escape`&&deactivate()};return{onClick,onKeyDown,onMouseLeave:deactivate,onMouseMove}},e=>{g=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+f:e;if(t>=a.startAngle-1e-9&&t<=a.endAngle+1e-9)return i}}}return-1}export{createPieChart};
|
|
2
2
|
//# sourceMappingURL=pie-chart.js.map
|