@vielzeug/prism 26.10.15 → 26.10.17
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/LICENSE +21 -0
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +6 -1
- package/dist/_dev.js.map +1 -1
- package/dist/_tappers.cjs.map +1 -1
- package/dist/_tappers.js +25 -1
- package/dist/_tappers.js.map +1 -1
- package/dist/animation/easing.cjs.map +1 -1
- package/dist/animation/easing.js +15 -1
- package/dist/animation/easing.js.map +1 -1
- package/dist/animation/motion.cjs.map +1 -1
- package/dist/animation/motion.js +15 -1
- package/dist/animation/motion.js.map +1 -1
- package/dist/animation/reveal.cjs.map +1 -1
- package/dist/animation/reveal.js +97 -1
- package/dist/animation/reveal.js.map +1 -1
- package/dist/animation/transition.cjs.map +1 -1
- package/dist/animation/transition.js +39 -1
- package/dist/animation/transition.js.map +1 -1
- package/dist/animation/tween.cjs.map +1 -1
- package/dist/animation/tween.js +7 -1
- package/dist/animation/tween.js.map +1 -1
- package/dist/axes/axis.cjs.map +1 -1
- package/dist/axes/axis.js +76 -1
- package/dist/axes/axis.js.map +1 -1
- package/dist/axes/grid.cjs.map +1 -1
- package/dist/axes/grid.js +29 -1
- package/dist/axes/grid.js.map +1 -1
- package/dist/axes/scale-utils.cjs.map +1 -1
- package/dist/axes/scale-utils.js +10 -1
- package/dist/axes/scale-utils.js.map +1 -1
- package/dist/charts/area/area-chart.cjs.map +1 -1
- package/dist/charts/area/area-chart.js +71 -1
- package/dist/charts/area/area-chart.js.map +1 -1
- package/dist/charts/area/area-renderer.cjs.map +1 -1
- package/dist/charts/area/area-renderer.js +128 -1
- package/dist/charts/area/area-renderer.js.map +1 -1
- package/dist/charts/bar/bar-chart.cjs.map +1 -1
- package/dist/charts/bar/bar-chart.js +228 -1
- package/dist/charts/bar/bar-chart.js.map +1 -1
- package/dist/charts/bar/bar-hit-test.cjs.map +1 -1
- package/dist/charts/bar/bar-hit-test.js +25 -1
- package/dist/charts/bar/bar-hit-test.js.map +1 -1
- package/dist/charts/bar/bar-renderer.cjs.map +1 -1
- package/dist/charts/bar/bar-renderer.js +139 -1
- package/dist/charts/bar/bar-renderer.js.map +1 -1
- package/dist/charts/line/line-chart.cjs.map +1 -1
- package/dist/charts/line/line-chart.js +93 -1
- package/dist/charts/line/line-chart.js.map +1 -1
- package/dist/charts/line/line-renderer.cjs.map +1 -1
- package/dist/charts/line/line-renderer.js +143 -1
- package/dist/charts/line/line-renderer.js.map +1 -1
- package/dist/charts/pie/pie-chart.cjs +1 -1
- package/dist/charts/pie/pie-chart.cjs.map +1 -1
- package/dist/charts/pie/pie-chart.js +207 -1
- package/dist/charts/pie/pie-chart.js.map +1 -1
- package/dist/charts/pie/pie-renderer.cjs.map +1 -1
- package/dist/charts/pie/pie-renderer.js +68 -1
- package/dist/charts/pie/pie-renderer.js.map +1 -1
- package/dist/charts/radar/radar-chart.cjs +1 -1
- package/dist/charts/radar/radar-chart.cjs.map +1 -1
- package/dist/charts/radar/radar-chart.js +281 -1
- package/dist/charts/radar/radar-chart.js.map +1 -1
- package/dist/charts/radar/radar-geometry.cjs.map +1 -1
- package/dist/charts/radar/radar-geometry.js +69 -1
- package/dist/charts/radar/radar-geometry.js.map +1 -1
- package/dist/charts/scatter/scatter-chart.cjs.map +1 -1
- package/dist/charts/scatter/scatter-chart.js +69 -1
- package/dist/charts/scatter/scatter-chart.js.map +1 -1
- package/dist/charts/scatter/scatter-renderer.cjs.map +1 -1
- package/dist/charts/scatter/scatter-renderer.js +57 -1
- package/dist/charts/scatter/scatter-renderer.js.map +1 -1
- package/dist/charts/sparkline/sparkline.cjs +1 -1
- package/dist/charts/sparkline/sparkline.cjs.map +1 -1
- package/dist/charts/sparkline/sparkline.js +251 -1
- package/dist/charts/sparkline/sparkline.js.map +1 -1
- package/dist/core/cartesian-model.cjs +1 -1
- package/dist/core/cartesian-model.cjs.map +1 -1
- package/dist/core/cartesian-model.js +26 -1
- package/dist/core/cartesian-model.js.map +1 -1
- package/dist/core/cartesian-scales.cjs.map +1 -1
- package/dist/core/cartesian-scales.js +38 -1
- package/dist/core/cartesian-scales.js.map +1 -1
- package/dist/core/chart-base.cjs.map +1 -1
- package/dist/core/chart-base.js +62 -1
- package/dist/core/chart-base.js.map +1 -1
- package/dist/core/chart-scaffold.cjs.map +1 -1
- package/dist/core/chart-scaffold.js +103 -1
- package/dist/core/chart-scaffold.js.map +1 -1
- package/dist/core/datum-style.cjs +1 -1
- package/dist/core/datum-style.cjs.map +1 -1
- package/dist/core/datum-style.js +22 -1
- package/dist/core/datum-style.js.map +1 -1
- package/dist/core/ids.cjs.map +1 -1
- package/dist/core/ids.js +8 -1
- package/dist/core/ids.js.map +1 -1
- package/dist/core/layout.cjs.map +1 -1
- package/dist/core/layout.js +22 -1
- package/dist/core/layout.js.map +1 -1
- package/dist/core/polar.cjs.map +1 -1
- package/dist/core/polar.js +13 -1
- package/dist/core/polar.js.map +1 -1
- package/dist/core/responsive.cjs.map +1 -1
- package/dist/core/responsive.js +20 -1
- package/dist/core/responsive.js.map +1 -1
- package/dist/core/series-id.cjs.map +1 -1
- package/dist/core/series-id.js +7 -1
- package/dist/core/series-id.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +9 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +13 -1
- package/dist/interaction/announcer.cjs.map +1 -1
- package/dist/interaction/announcer.js +25 -1
- package/dist/interaction/announcer.js.map +1 -1
- package/dist/interaction/crosshair.cjs.map +1 -1
- package/dist/interaction/crosshair.js +37 -1
- package/dist/interaction/crosshair.js.map +1 -1
- package/dist/interaction/events.cjs.map +1 -1
- package/dist/interaction/events.js +11 -1
- package/dist/interaction/events.js.map +1 -1
- package/dist/interaction/legend.cjs.map +1 -1
- package/dist/interaction/legend.js +31 -1
- package/dist/interaction/legend.js.map +1 -1
- package/dist/interaction/scatter-interaction.cjs.map +1 -1
- package/dist/interaction/scatter-interaction.js +105 -1
- package/dist/interaction/scatter-interaction.js.map +1 -1
- package/dist/interaction/series-interaction.cjs.map +1 -1
- package/dist/interaction/series-interaction.js +163 -1
- package/dist/interaction/series-interaction.js.map +1 -1
- package/dist/interaction/tooltip.cjs +1 -1
- package/dist/interaction/tooltip.cjs.map +1 -1
- package/dist/interaction/tooltip.js +87 -1
- package/dist/interaction/tooltip.js.map +1 -1
- package/dist/prism.cjs +1 -1
- package/dist/prism.cjs.map +1 -1
- package/dist/prism.iife.js +1 -1
- package/dist/prism.iife.js.map +1 -1
- package/dist/prism.js +2930 -1
- package/dist/prism.js.map +1 -1
- package/dist/scales/band.cjs.map +1 -1
- package/dist/scales/band.js +39 -1
- package/dist/scales/band.js.map +1 -1
- package/dist/scales/linear.cjs.map +1 -1
- package/dist/scales/linear.js +43 -1
- package/dist/scales/linear.js.map +1 -1
- package/dist/scales/time.cjs.map +1 -1
- package/dist/scales/time.js +61 -1
- package/dist/scales/time.js.map +1 -1
- package/dist/svg/element.cjs +1 -1
- package/dist/svg/element.cjs.map +1 -1
- package/dist/svg/element.js +16 -1
- package/dist/svg/element.js.map +1 -1
- package/dist/svg/path.cjs.map +1 -1
- package/dist/svg/path.js +48 -1
- package/dist/svg/path.js.map +1 -1
- package/dist/svg/text.cjs.map +1 -1
- package/dist/svg/text.js +13 -1
- package/dist/svg/text.js.map +1 -1
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.js +37 -1
- package/dist/theme/index.js.map +1 -1
- package/package.json +6 -5
package/dist/axes/axis.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axis.cjs","names":[],"sources":["../../src/axes/axis.ts"],"sourcesContent":["import { devOnly, warn } from '../_dev';\nimport { createSvgElement, removeChildren, setAttributes } from '../svg/element';\nimport { createTextElement, estimateTextWidth } from '../svg/text';\nimport type { AxisConfig, AxisPosition } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\n/** Default `--prism-font-size-label` in px, used to estimate category label size. */\nconst LABEL_FONT_SIZE = 11;\nconst LABEL_GAP = 8;\n\nconst COMPACT = new Intl.NumberFormat(undefined, { maximumSignificantDigits: 3, notation: 'compact' });\n\n/**\n * Dates localize; magnitudes of 1e5 and above render in compact notation (\"123K\",\n * \"1.23M\") so a long number cannot crop against the default 50 px value-axis margin.\n * With three significant digits every compact label is at most as wide as \"99999\",\n * the widest plain label below the threshold. Opt out with `tickFormat: String`.\n */\nconst defaultTickFormat = (v: Date | number | string): string => {\n if (v instanceof Date) return v.toLocaleDateString(undefined, { month: 'short', year: 'numeric' });\n if (typeof v === 'number' && Math.abs(v) >= 1e5) return COMPACT.format(v);\n\n return String(v);\n};\n\n/**\n * The single tick source for an axis and its gridlines: explicit `tickValues` when set,\n * scale-generated ticks otherwise. Keeping grid on this same array is what stops\n * gridlines from drifting off the rendered ticks.\n */\nexport function resolveTicks(scale: AnyScale, config: AxisConfig, tickCount: number): (Date | number | string)[] {\n return config.tickValues ? [...config.tickValues] : scale.ticks(tickCount);\n}\n\n/** Development-only check that explicit tickValues match the scale they render on. */\nfunction warnOffScaleTicks(scale: AnyScale, tickValues: ReadonlyArray<Date | number | string>): void {\n devOnly(() => {\n if ('bandwidth' in scale) {\n for (const tick of tickValues) {\n if (!scale.domain.includes(tick as string)) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is not a category in the band scale's domain.`);\n }\n }\n\n return;\n }\n\n const toMs = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n const [a, b] = scale.domain;\n const lo = Math.min(toMs(a), toMs(b));\n const hi = Math.max(toMs(a), toMs(b));\n\n for (const tick of tickValues) {\n const value = tick instanceof Date ? tick.getTime() : Number(tick);\n\n if (Number.isNaN(value) || value < lo || value > hi) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is outside the axis domain and renders off-canvas.`);\n }\n }\n });\n}\n\n/**\n * Resolves the tick count an axis will render for a given scale/length: charts pass it to\n * `resolveTicks` for both the axis and its gridlines so the two stay aligned.\n * `defaultPosition` must match the one passed to the corresponding `renderAxis` call\n * ('bottom' for xAxis, 'left' for yAxis).\n */\nexport function positionAxis(parent: SVGGElement, position: AxisPosition, width: number, height: number): void {\n const transform =\n position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;\n\n if (transform) parent.setAttribute('transform', transform);\n else parent.removeAttribute('transform');\n}\n\nexport function resolveTickCount(config: AxisConfig, length: number, defaultPosition: AxisPosition): number {\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const defaultTickCount = isHorizontal ? Math.max(2, Math.floor(length / 80)) : Math.max(2, Math.floor(length / 50));\n\n return config.tickCount ?? defaultTickCount;\n}\n\n/** How many category labels fit along the axis without their estimated boxes overlapping. */\nfunction categoryTickCount(\n domain: readonly string[],\n format: (value: string) => string,\n length: number,\n isHorizontal: boolean,\n): number {\n if (domain.length === 0) return 0;\n\n const size = isHorizontal\n ? Math.max(...domain.map((value) => estimateTextWidth(format(value), LABEL_FONT_SIZE)))\n : LABEL_FONT_SIZE * 1.3;\n\n return Math.max(1, Math.min(domain.length, Math.floor(length / (size + LABEL_GAP))));\n}\n\n/**\n * `defaultPosition` is applied when `config.position` is unset: pass `'bottom'` for an\n * xAxis call and `'left'` for a yAxis call so an unconfigured axis renders on its\n * conventional side instead of always defaulting to a horizontal bottom axis.\n */\nexport function renderAxis(\n parent: SVGGElement,\n scale: AnyScale,\n config: AxisConfig,\n length: number,\n defaultPosition: AxisPosition = 'bottom',\n): void {\n removeChildren(parent);\n\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const isInverted = position === 'top' || position === 'left';\n const tickSize = 6;\n const tickDirection = isInverted ? -1 : 1;\n\n const axisLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-line',\n x1: isHorizontal ? 0 : 0,\n x2: isHorizontal ? length : 0,\n y1: isHorizontal ? 0 : 0,\n y2: isHorizontal ? 0 : length,\n });\n\n parent.appendChild(axisLine);\n\n const format = config.tickFormat ?? defaultTickFormat;\n const tickCount =\n config.tickCount === undefined && 'bandwidth' in scale\n ? categoryTickCount(scale.domain, format, length, isHorizontal)\n : resolveTickCount(config, length, defaultPosition);\n const ticks = resolveTicks(scale, config, tickCount);\n\n if (config.tickValues) warnOffScaleTicks(scale, config.tickValues);\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const tickLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-tick',\n x1: isHorizontal ? pos : 0,\n x2: isHorizontal ? pos : tickSize * tickDirection,\n y1: isHorizontal ? 0 : pos,\n y2: isHorizontal ? tickSize * tickDirection : pos,\n });\n\n parent.appendChild(tickLine);\n\n const label = createTextElement(format(tick), {\n 'aria-hidden': 'true',\n class: 'prism-axis-label',\n 'dominant-baseline': isHorizontal ? (isInverted ? 'auto' : 'hanging') : 'middle',\n 'text-anchor': isHorizontal ? 'middle' : isInverted ? 'end' : 'start',\n x: isHorizontal ? pos : tickSize * tickDirection * 1.5,\n y: isHorizontal ? tickSize * tickDirection * 1.5 : pos,\n });\n\n parent.appendChild(label);\n }\n\n if (config.label) {\n const labelEl = createTextElement(config.label, {\n class: 'prism-axis-title',\n 'dominant-baseline': 'middle',\n 'text-anchor': 'middle',\n });\n\n if (isHorizontal) {\n setAttributes(labelEl, { x: length / 2, y: tickSize * tickDirection * 6 });\n } else {\n setAttributes(labelEl, {\n transform: `translate(${tickSize * tickDirection * 7}, ${length / 2}) rotate(-90)`,\n });\n }\n\n parent.appendChild(labelEl);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"axis.cjs","names":["estimateTextWidth","createSvgElement","mapTick","createTextElement","require_element","require_text","require_scale_utils","LABEL_FONT_SIZE","LABEL_GAP","COMPACT","v","config","scale","tickCount","transform","position","height","width","parent","defaultPosition","defaultTickCount","length","domain","size","isHorizontal","format","value","isInverted","tickDirection","axisLine","ticks","tick","pos","tickLine","label","labelEl"],"sources":["../../src/axes/axis.ts"],"sourcesContent":["import { devOnly, warn } from '../_dev';\nimport { createSvgElement, removeChildren, setAttributes } from '../svg/element';\nimport { createTextElement, estimateTextWidth } from '../svg/text';\nimport type { AxisConfig, AxisPosition } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\n/** Default `--prism-font-size-label` in px, used to estimate category label size. */\nconst LABEL_FONT_SIZE = 11;\nconst LABEL_GAP = 8;\n\nconst COMPACT = new Intl.NumberFormat(undefined, { maximumSignificantDigits: 3, notation: 'compact' });\n\n/**\n * Dates localize; magnitudes of 1e5 and above render in compact notation (\"123K\",\n * \"1.23M\") so a long number cannot crop against the default 50 px value-axis margin.\n * With three significant digits every compact label is at most as wide as \"99999\",\n * the widest plain label below the threshold. Opt out with `tickFormat: String`.\n */\nconst defaultTickFormat = (v: Date | number | string): string => {\n if (v instanceof Date) return v.toLocaleDateString(undefined, { month: 'short', year: 'numeric' });\n if (typeof v === 'number' && Math.abs(v) >= 1e5) return COMPACT.format(v);\n\n return String(v);\n};\n\n/**\n * The single tick source for an axis and its gridlines: explicit `tickValues` when set,\n * scale-generated ticks otherwise. Keeping grid on this same array is what stops\n * gridlines from drifting off the rendered ticks.\n */\nexport function resolveTicks(scale: AnyScale, config: AxisConfig, tickCount: number): (Date | number | string)[] {\n return config.tickValues ? [...config.tickValues] : scale.ticks(tickCount);\n}\n\n/** Development-only check that explicit tickValues match the scale they render on. */\nfunction warnOffScaleTicks(scale: AnyScale, tickValues: ReadonlyArray<Date | number | string>): void {\n devOnly(() => {\n if ('bandwidth' in scale) {\n for (const tick of tickValues) {\n if (!scale.domain.includes(tick as string)) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is not a category in the band scale's domain.`);\n }\n }\n\n return;\n }\n\n const toMs = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n const [a, b] = scale.domain;\n const lo = Math.min(toMs(a), toMs(b));\n const hi = Math.max(toMs(a), toMs(b));\n\n for (const tick of tickValues) {\n const value = tick instanceof Date ? tick.getTime() : Number(tick);\n\n if (Number.isNaN(value) || value < lo || value > hi) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is outside the axis domain and renders off-canvas.`);\n }\n }\n });\n}\n\n/**\n * Resolves the tick count an axis will render for a given scale/length: charts pass it to\n * `resolveTicks` for both the axis and its gridlines so the two stay aligned.\n * `defaultPosition` must match the one passed to the corresponding `renderAxis` call\n * ('bottom' for xAxis, 'left' for yAxis).\n */\nexport function positionAxis(parent: SVGGElement, position: AxisPosition, width: number, height: number): void {\n const transform =\n position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;\n\n if (transform) parent.setAttribute('transform', transform);\n else parent.removeAttribute('transform');\n}\n\nexport function resolveTickCount(config: AxisConfig, length: number, defaultPosition: AxisPosition): number {\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const defaultTickCount = isHorizontal ? Math.max(2, Math.floor(length / 80)) : Math.max(2, Math.floor(length / 50));\n\n return config.tickCount ?? defaultTickCount;\n}\n\n/** How many category labels fit along the axis without their estimated boxes overlapping. */\nfunction categoryTickCount(\n domain: readonly string[],\n format: (value: string) => string,\n length: number,\n isHorizontal: boolean,\n): number {\n if (domain.length === 0) return 0;\n\n const size = isHorizontal\n ? Math.max(...domain.map((value) => estimateTextWidth(format(value), LABEL_FONT_SIZE)))\n : LABEL_FONT_SIZE * 1.3;\n\n return Math.max(1, Math.min(domain.length, Math.floor(length / (size + LABEL_GAP))));\n}\n\n/**\n * `defaultPosition` is applied when `config.position` is unset: pass `'bottom'` for an\n * xAxis call and `'left'` for a yAxis call so an unconfigured axis renders on its\n * conventional side instead of always defaulting to a horizontal bottom axis.\n */\nexport function renderAxis(\n parent: SVGGElement,\n scale: AnyScale,\n config: AxisConfig,\n length: number,\n defaultPosition: AxisPosition = 'bottom',\n): void {\n removeChildren(parent);\n\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const isInverted = position === 'top' || position === 'left';\n const tickSize = 6;\n const tickDirection = isInverted ? -1 : 1;\n\n const axisLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-line',\n x1: isHorizontal ? 0 : 0,\n x2: isHorizontal ? length : 0,\n y1: isHorizontal ? 0 : 0,\n y2: isHorizontal ? 0 : length,\n });\n\n parent.appendChild(axisLine);\n\n const format = config.tickFormat ?? defaultTickFormat;\n const tickCount =\n config.tickCount === undefined && 'bandwidth' in scale\n ? categoryTickCount(scale.domain, format, length, isHorizontal)\n : resolveTickCount(config, length, defaultPosition);\n const ticks = resolveTicks(scale, config, tickCount);\n\n if (config.tickValues) warnOffScaleTicks(scale, config.tickValues);\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const tickLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-tick',\n x1: isHorizontal ? pos : 0,\n x2: isHorizontal ? pos : tickSize * tickDirection,\n y1: isHorizontal ? 0 : pos,\n y2: isHorizontal ? tickSize * tickDirection : pos,\n });\n\n parent.appendChild(tickLine);\n\n const label = createTextElement(format(tick), {\n 'aria-hidden': 'true',\n class: 'prism-axis-label',\n 'dominant-baseline': isHorizontal ? (isInverted ? 'auto' : 'hanging') : 'middle',\n 'text-anchor': isHorizontal ? 'middle' : isInverted ? 'end' : 'start',\n x: isHorizontal ? pos : tickSize * tickDirection * 1.5,\n y: isHorizontal ? tickSize * tickDirection * 1.5 : pos,\n });\n\n parent.appendChild(label);\n }\n\n if (config.label) {\n const labelEl = createTextElement(config.label, {\n class: 'prism-axis-title',\n 'dominant-baseline': 'middle',\n 'text-anchor': 'middle',\n });\n\n if (isHorizontal) {\n setAttributes(labelEl, { x: length / 2, y: tickSize * tickDirection * 6 });\n } else {\n setAttributes(labelEl, {\n transform: `translate(${tickSize * tickDirection * 7}, ${length / 2}) rotate(-90)`,\n });\n }\n\n parent.appendChild(labelEl);\n }\n}\n"],"mappings":"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"}
|
package/dist/axes/axis.js
CHANGED
|
@@ -1,2 +1,77 @@
|
|
|
1
|
-
import"../_dev.js";
|
|
1
|
+
import "../_dev.js";
|
|
2
|
+
import { createSvgElement as e, removeChildren as t, setAttributes as n } from "../svg/element.js";
|
|
3
|
+
import { createTextElement as r, estimateTextWidth as i } from "../svg/text.js";
|
|
4
|
+
import { mapTick as a } from "./scale-utils.js";
|
|
5
|
+
//#region src/axes/axis.ts
|
|
6
|
+
var o = 11, s = 8, c = new Intl.NumberFormat(void 0, {
|
|
7
|
+
maximumSignificantDigits: 3,
|
|
8
|
+
notation: "compact"
|
|
9
|
+
}), defaultTickFormat = (e) => e instanceof Date ? e.toLocaleDateString(void 0, {
|
|
10
|
+
month: "short",
|
|
11
|
+
year: "numeric"
|
|
12
|
+
}) : typeof e == "number" && Math.abs(e) >= 1e5 ? c.format(e) : String(e);
|
|
13
|
+
function resolveTicks(e, t, n) {
|
|
14
|
+
return t.tickValues ? [...t.tickValues] : e.ticks(n);
|
|
15
|
+
}
|
|
16
|
+
function positionAxis(e, t, n, r) {
|
|
17
|
+
let i = t === "bottom" ? `translate(0,${r})` : t === "right" ? `translate(${n},0)` : void 0;
|
|
18
|
+
i ? e.setAttribute("transform", i) : e.removeAttribute("transform");
|
|
19
|
+
}
|
|
20
|
+
function resolveTickCount(e, t, n) {
|
|
21
|
+
let r = e.position ?? n, i = r === "bottom" || r === "top" ? Math.max(2, Math.floor(t / 80)) : Math.max(2, Math.floor(t / 50));
|
|
22
|
+
return e.tickCount ?? i;
|
|
23
|
+
}
|
|
24
|
+
function categoryTickCount(e, t, n, r) {
|
|
25
|
+
if (e.length === 0) return 0;
|
|
26
|
+
let a = r ? Math.max(...e.map((e) => i(t(e), o))) : o * 1.3;
|
|
27
|
+
return Math.max(1, Math.min(e.length, Math.floor(n / (a + s))));
|
|
28
|
+
}
|
|
29
|
+
function renderAxis(i, o, s, c, l = "bottom") {
|
|
30
|
+
t(i);
|
|
31
|
+
let u = s.position ?? l, d = u === "bottom" || u === "top", f = u === "top" || u === "left", p = f ? -1 : 1, m = e("line", {
|
|
32
|
+
"aria-hidden": "true",
|
|
33
|
+
class: "prism-axis-line",
|
|
34
|
+
x1: 0,
|
|
35
|
+
x2: d ? c : 0,
|
|
36
|
+
y1: 0,
|
|
37
|
+
y2: d ? 0 : c
|
|
38
|
+
});
|
|
39
|
+
i.appendChild(m);
|
|
40
|
+
let h = s.tickFormat ?? defaultTickFormat, g = resolveTicks(o, s, s.tickCount === void 0 && "bandwidth" in o ? categoryTickCount(o.domain, h, c, d) : resolveTickCount(s, c, l));
|
|
41
|
+
s.tickValues && s.tickValues;
|
|
42
|
+
for (let t of g) {
|
|
43
|
+
let n = a(o, t), s = e("line", {
|
|
44
|
+
"aria-hidden": "true",
|
|
45
|
+
class: "prism-axis-tick",
|
|
46
|
+
x1: d ? n : 0,
|
|
47
|
+
x2: d ? n : 6 * p,
|
|
48
|
+
y1: d ? 0 : n,
|
|
49
|
+
y2: d ? 6 * p : n
|
|
50
|
+
});
|
|
51
|
+
i.appendChild(s);
|
|
52
|
+
let c = r(h(t), {
|
|
53
|
+
"aria-hidden": "true",
|
|
54
|
+
class: "prism-axis-label",
|
|
55
|
+
"dominant-baseline": d ? f ? "auto" : "hanging" : "middle",
|
|
56
|
+
"text-anchor": d ? "middle" : f ? "end" : "start",
|
|
57
|
+
x: d ? n : 6 * p * 1.5,
|
|
58
|
+
y: d ? 6 * p * 1.5 : n
|
|
59
|
+
});
|
|
60
|
+
i.appendChild(c);
|
|
61
|
+
}
|
|
62
|
+
if (s.label) {
|
|
63
|
+
let e = r(s.label, {
|
|
64
|
+
class: "prism-axis-title",
|
|
65
|
+
"dominant-baseline": "middle",
|
|
66
|
+
"text-anchor": "middle"
|
|
67
|
+
});
|
|
68
|
+
d ? n(e, {
|
|
69
|
+
x: c / 2,
|
|
70
|
+
y: 6 * p * 6
|
|
71
|
+
}) : n(e, { transform: `translate(${6 * p * 7}, ${c / 2}) rotate(-90)` }), i.appendChild(e);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { positionAxis, renderAxis, resolveTickCount, resolveTicks };
|
|
76
|
+
|
|
2
77
|
//# sourceMappingURL=axis.js.map
|
package/dist/axes/axis.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"axis.js","names":[],"sources":["../../src/axes/axis.ts"],"sourcesContent":["import { devOnly, warn } from '../_dev';\nimport { createSvgElement, removeChildren, setAttributes } from '../svg/element';\nimport { createTextElement, estimateTextWidth } from '../svg/text';\nimport type { AxisConfig, AxisPosition } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\n/** Default `--prism-font-size-label` in px, used to estimate category label size. */\nconst LABEL_FONT_SIZE = 11;\nconst LABEL_GAP = 8;\n\nconst COMPACT = new Intl.NumberFormat(undefined, { maximumSignificantDigits: 3, notation: 'compact' });\n\n/**\n * Dates localize; magnitudes of 1e5 and above render in compact notation (\"123K\",\n * \"1.23M\") so a long number cannot crop against the default 50 px value-axis margin.\n * With three significant digits every compact label is at most as wide as \"99999\",\n * the widest plain label below the threshold. Opt out with `tickFormat: String`.\n */\nconst defaultTickFormat = (v: Date | number | string): string => {\n if (v instanceof Date) return v.toLocaleDateString(undefined, { month: 'short', year: 'numeric' });\n if (typeof v === 'number' && Math.abs(v) >= 1e5) return COMPACT.format(v);\n\n return String(v);\n};\n\n/**\n * The single tick source for an axis and its gridlines: explicit `tickValues` when set,\n * scale-generated ticks otherwise. Keeping grid on this same array is what stops\n * gridlines from drifting off the rendered ticks.\n */\nexport function resolveTicks(scale: AnyScale, config: AxisConfig, tickCount: number): (Date | number | string)[] {\n return config.tickValues ? [...config.tickValues] : scale.ticks(tickCount);\n}\n\n/** Development-only check that explicit tickValues match the scale they render on. */\nfunction warnOffScaleTicks(scale: AnyScale, tickValues: ReadonlyArray<Date | number | string>): void {\n devOnly(() => {\n if ('bandwidth' in scale) {\n for (const tick of tickValues) {\n if (!scale.domain.includes(tick as string)) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is not a category in the band scale's domain.`);\n }\n }\n\n return;\n }\n\n const toMs = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n const [a, b] = scale.domain;\n const lo = Math.min(toMs(a), toMs(b));\n const hi = Math.max(toMs(a), toMs(b));\n\n for (const tick of tickValues) {\n const value = tick instanceof Date ? tick.getTime() : Number(tick);\n\n if (Number.isNaN(value) || value < lo || value > hi) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is outside the axis domain and renders off-canvas.`);\n }\n }\n });\n}\n\n/**\n * Resolves the tick count an axis will render for a given scale/length: charts pass it to\n * `resolveTicks` for both the axis and its gridlines so the two stay aligned.\n * `defaultPosition` must match the one passed to the corresponding `renderAxis` call\n * ('bottom' for xAxis, 'left' for yAxis).\n */\nexport function positionAxis(parent: SVGGElement, position: AxisPosition, width: number, height: number): void {\n const transform =\n position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;\n\n if (transform) parent.setAttribute('transform', transform);\n else parent.removeAttribute('transform');\n}\n\nexport function resolveTickCount(config: AxisConfig, length: number, defaultPosition: AxisPosition): number {\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const defaultTickCount = isHorizontal ? Math.max(2, Math.floor(length / 80)) : Math.max(2, Math.floor(length / 50));\n\n return config.tickCount ?? defaultTickCount;\n}\n\n/** How many category labels fit along the axis without their estimated boxes overlapping. */\nfunction categoryTickCount(\n domain: readonly string[],\n format: (value: string) => string,\n length: number,\n isHorizontal: boolean,\n): number {\n if (domain.length === 0) return 0;\n\n const size = isHorizontal\n ? Math.max(...domain.map((value) => estimateTextWidth(format(value), LABEL_FONT_SIZE)))\n : LABEL_FONT_SIZE * 1.3;\n\n return Math.max(1, Math.min(domain.length, Math.floor(length / (size + LABEL_GAP))));\n}\n\n/**\n * `defaultPosition` is applied when `config.position` is unset: pass `'bottom'` for an\n * xAxis call and `'left'` for a yAxis call so an unconfigured axis renders on its\n * conventional side instead of always defaulting to a horizontal bottom axis.\n */\nexport function renderAxis(\n parent: SVGGElement,\n scale: AnyScale,\n config: AxisConfig,\n length: number,\n defaultPosition: AxisPosition = 'bottom',\n): void {\n removeChildren(parent);\n\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const isInverted = position === 'top' || position === 'left';\n const tickSize = 6;\n const tickDirection = isInverted ? -1 : 1;\n\n const axisLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-line',\n x1: isHorizontal ? 0 : 0,\n x2: isHorizontal ? length : 0,\n y1: isHorizontal ? 0 : 0,\n y2: isHorizontal ? 0 : length,\n });\n\n parent.appendChild(axisLine);\n\n const format = config.tickFormat ?? defaultTickFormat;\n const tickCount =\n config.tickCount === undefined && 'bandwidth' in scale\n ? categoryTickCount(scale.domain, format, length, isHorizontal)\n : resolveTickCount(config, length, defaultPosition);\n const ticks = resolveTicks(scale, config, tickCount);\n\n if (config.tickValues) warnOffScaleTicks(scale, config.tickValues);\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const tickLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-tick',\n x1: isHorizontal ? pos : 0,\n x2: isHorizontal ? pos : tickSize * tickDirection,\n y1: isHorizontal ? 0 : pos,\n y2: isHorizontal ? tickSize * tickDirection : pos,\n });\n\n parent.appendChild(tickLine);\n\n const label = createTextElement(format(tick), {\n 'aria-hidden': 'true',\n class: 'prism-axis-label',\n 'dominant-baseline': isHorizontal ? (isInverted ? 'auto' : 'hanging') : 'middle',\n 'text-anchor': isHorizontal ? 'middle' : isInverted ? 'end' : 'start',\n x: isHorizontal ? pos : tickSize * tickDirection * 1.5,\n y: isHorizontal ? tickSize * tickDirection * 1.5 : pos,\n });\n\n parent.appendChild(label);\n }\n\n if (config.label) {\n const labelEl = createTextElement(config.label, {\n class: 'prism-axis-title',\n 'dominant-baseline': 'middle',\n 'text-anchor': 'middle',\n });\n\n if (isHorizontal) {\n setAttributes(labelEl, { x: length / 2, y: tickSize * tickDirection * 6 });\n } else {\n setAttributes(labelEl, {\n transform: `translate(${tickSize * tickDirection * 7}, ${length / 2}) rotate(-90)`,\n });\n }\n\n parent.appendChild(labelEl);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"axis.js","names":["LABEL_FONT_SIZE","LABEL_GAP","COMPACT","v","config","scale","tickCount","transform","position","height","width","parent","defaultPosition","defaultTickCount","length","domain","size","isHorizontal","estimateTextWidth","format","value","isInverted","tickDirection","axisLine","createSvgElement","ticks","tick","pos","mapTick","tickLine","label","createTextElement","labelEl","setAttributes"],"sources":["../../src/axes/axis.ts"],"sourcesContent":["import { devOnly, warn } from '../_dev';\nimport { createSvgElement, removeChildren, setAttributes } from '../svg/element';\nimport { createTextElement, estimateTextWidth } from '../svg/text';\nimport type { AxisConfig, AxisPosition } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\n/** Default `--prism-font-size-label` in px, used to estimate category label size. */\nconst LABEL_FONT_SIZE = 11;\nconst LABEL_GAP = 8;\n\nconst COMPACT = new Intl.NumberFormat(undefined, { maximumSignificantDigits: 3, notation: 'compact' });\n\n/**\n * Dates localize; magnitudes of 1e5 and above render in compact notation (\"123K\",\n * \"1.23M\") so a long number cannot crop against the default 50 px value-axis margin.\n * With three significant digits every compact label is at most as wide as \"99999\",\n * the widest plain label below the threshold. Opt out with `tickFormat: String`.\n */\nconst defaultTickFormat = (v: Date | number | string): string => {\n if (v instanceof Date) return v.toLocaleDateString(undefined, { month: 'short', year: 'numeric' });\n if (typeof v === 'number' && Math.abs(v) >= 1e5) return COMPACT.format(v);\n\n return String(v);\n};\n\n/**\n * The single tick source for an axis and its gridlines: explicit `tickValues` when set,\n * scale-generated ticks otherwise. Keeping grid on this same array is what stops\n * gridlines from drifting off the rendered ticks.\n */\nexport function resolveTicks(scale: AnyScale, config: AxisConfig, tickCount: number): (Date | number | string)[] {\n return config.tickValues ? [...config.tickValues] : scale.ticks(tickCount);\n}\n\n/** Development-only check that explicit tickValues match the scale they render on. */\nfunction warnOffScaleTicks(scale: AnyScale, tickValues: ReadonlyArray<Date | number | string>): void {\n devOnly(() => {\n if ('bandwidth' in scale) {\n for (const tick of tickValues) {\n if (!scale.domain.includes(tick as string)) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is not a category in the band scale's domain.`);\n }\n }\n\n return;\n }\n\n const toMs = (v: Date | number): number => (v instanceof Date ? v.getTime() : v);\n const [a, b] = scale.domain;\n const lo = Math.min(toMs(a), toMs(b));\n const hi = Math.max(toMs(a), toMs(b));\n\n for (const tick of tickValues) {\n const value = tick instanceof Date ? tick.getTime() : Number(tick);\n\n if (Number.isNaN(value) || value < lo || value > hi) {\n warn(`renderAxis: tickValue \"${String(tick)}\" is outside the axis domain and renders off-canvas.`);\n }\n }\n });\n}\n\n/**\n * Resolves the tick count an axis will render for a given scale/length: charts pass it to\n * `resolveTicks` for both the axis and its gridlines so the two stay aligned.\n * `defaultPosition` must match the one passed to the corresponding `renderAxis` call\n * ('bottom' for xAxis, 'left' for yAxis).\n */\nexport function positionAxis(parent: SVGGElement, position: AxisPosition, width: number, height: number): void {\n const transform =\n position === 'bottom' ? `translate(0,${height})` : position === 'right' ? `translate(${width},0)` : undefined;\n\n if (transform) parent.setAttribute('transform', transform);\n else parent.removeAttribute('transform');\n}\n\nexport function resolveTickCount(config: AxisConfig, length: number, defaultPosition: AxisPosition): number {\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const defaultTickCount = isHorizontal ? Math.max(2, Math.floor(length / 80)) : Math.max(2, Math.floor(length / 50));\n\n return config.tickCount ?? defaultTickCount;\n}\n\n/** How many category labels fit along the axis without their estimated boxes overlapping. */\nfunction categoryTickCount(\n domain: readonly string[],\n format: (value: string) => string,\n length: number,\n isHorizontal: boolean,\n): number {\n if (domain.length === 0) return 0;\n\n const size = isHorizontal\n ? Math.max(...domain.map((value) => estimateTextWidth(format(value), LABEL_FONT_SIZE)))\n : LABEL_FONT_SIZE * 1.3;\n\n return Math.max(1, Math.min(domain.length, Math.floor(length / (size + LABEL_GAP))));\n}\n\n/**\n * `defaultPosition` is applied when `config.position` is unset: pass `'bottom'` for an\n * xAxis call and `'left'` for a yAxis call so an unconfigured axis renders on its\n * conventional side instead of always defaulting to a horizontal bottom axis.\n */\nexport function renderAxis(\n parent: SVGGElement,\n scale: AnyScale,\n config: AxisConfig,\n length: number,\n defaultPosition: AxisPosition = 'bottom',\n): void {\n removeChildren(parent);\n\n const position = config.position ?? defaultPosition;\n const isHorizontal = position === 'bottom' || position === 'top';\n const isInverted = position === 'top' || position === 'left';\n const tickSize = 6;\n const tickDirection = isInverted ? -1 : 1;\n\n const axisLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-line',\n x1: isHorizontal ? 0 : 0,\n x2: isHorizontal ? length : 0,\n y1: isHorizontal ? 0 : 0,\n y2: isHorizontal ? 0 : length,\n });\n\n parent.appendChild(axisLine);\n\n const format = config.tickFormat ?? defaultTickFormat;\n const tickCount =\n config.tickCount === undefined && 'bandwidth' in scale\n ? categoryTickCount(scale.domain, format, length, isHorizontal)\n : resolveTickCount(config, length, defaultPosition);\n const ticks = resolveTicks(scale, config, tickCount);\n\n if (config.tickValues) warnOffScaleTicks(scale, config.tickValues);\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const tickLine = createSvgElement('line', {\n 'aria-hidden': 'true',\n class: 'prism-axis-tick',\n x1: isHorizontal ? pos : 0,\n x2: isHorizontal ? pos : tickSize * tickDirection,\n y1: isHorizontal ? 0 : pos,\n y2: isHorizontal ? tickSize * tickDirection : pos,\n });\n\n parent.appendChild(tickLine);\n\n const label = createTextElement(format(tick), {\n 'aria-hidden': 'true',\n class: 'prism-axis-label',\n 'dominant-baseline': isHorizontal ? (isInverted ? 'auto' : 'hanging') : 'middle',\n 'text-anchor': isHorizontal ? 'middle' : isInverted ? 'end' : 'start',\n x: isHorizontal ? pos : tickSize * tickDirection * 1.5,\n y: isHorizontal ? tickSize * tickDirection * 1.5 : pos,\n });\n\n parent.appendChild(label);\n }\n\n if (config.label) {\n const labelEl = createTextElement(config.label, {\n class: 'prism-axis-title',\n 'dominant-baseline': 'middle',\n 'text-anchor': 'middle',\n });\n\n if (isHorizontal) {\n setAttributes(labelEl, { x: length / 2, y: tickSize * tickDirection * 6 });\n } else {\n setAttributes(labelEl, {\n transform: `translate(${tickSize * tickDirection * 7}, ${length / 2}) rotate(-90)`,\n });\n }\n\n parent.appendChild(labelEl);\n }\n}\n"],"mappings":"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"}
|
package/dist/axes/grid.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.cjs","names":[],"sources":["../../src/axes/grid.ts"],"sourcesContent":["import { createSvgElement, removeChildren } from '../svg/element';\nimport type { GridConfig } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\nexport function renderGrid(\n parent: SVGGElement,\n scale: AnyScale,\n config: GridConfig | true,\n crossLength: number,\n direction: 'horizontal' | 'vertical',\n ticks: readonly (Date | number | string)[],\n): void {\n removeChildren(parent);\n\n const color = (config !== true && config.color) || undefined;\n const dash = (config !== true && config.dash) || undefined;\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const attrs: Record<string, number | string | undefined> = {\n class: 'prism-grid-line',\n stroke: color ?? 'var(--prism-grid-color)',\n 'stroke-dasharray': dash,\n 'stroke-opacity': 'var(--prism-grid-opacity)',\n };\n\n if (direction === 'vertical') {\n Object.assign(attrs, { x1: pos, x2: pos, y1: 0, y2: crossLength });\n } else {\n Object.assign(attrs, { x1: 0, x2: crossLength, y1: pos, y2: pos });\n }\n\n parent.appendChild(createSvgElement('line', attrs));\n }\n}\n"],"mappings":"qEAIA,SAAgB,WACd,EACA,EACA,EACA,EACA,EACA,EACM,
|
|
1
|
+
{"version":3,"file":"grid.cjs","names":["mapTick","createSvgElement","require_element","require_scale_utils","parent","color","config","dash","tick","ticks","pos","scale","attrs","direction","crossLength"],"sources":["../../src/axes/grid.ts"],"sourcesContent":["import { createSvgElement, removeChildren } from '../svg/element';\nimport type { GridConfig } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\nexport function renderGrid(\n parent: SVGGElement,\n scale: AnyScale,\n config: GridConfig | true,\n crossLength: number,\n direction: 'horizontal' | 'vertical',\n ticks: readonly (Date | number | string)[],\n): void {\n removeChildren(parent);\n\n const color = (config !== true && config.color) || undefined;\n const dash = (config !== true && config.dash) || undefined;\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const attrs: Record<string, number | string | undefined> = {\n class: 'prism-grid-line',\n stroke: color ?? 'var(--prism-grid-color)',\n 'stroke-dasharray': dash,\n 'stroke-opacity': 'var(--prism-grid-opacity)',\n };\n\n if (direction === 'vertical') {\n Object.assign(attrs, { x1: pos, x2: pos, y1: 0, y2: crossLength });\n } else {\n Object.assign(attrs, { x1: 0, x2: crossLength, y1: pos, y2: pos });\n }\n\n parent.appendChild(createSvgElement('line', attrs));\n }\n}\n"],"mappings":"A,qEAIA,SAAgB,WACd,EACA,EACA,EACA,EACA,EACA,EACM,CACNE,EAAA,eAAeE,CAAM,EAErB,IAAMC,EAASC,IAAW,IAAQA,EAAO,OAAU,IAAA,GAC7CC,EAAQD,IAAW,IAAQA,EAAO,MAAS,IAAA,GAEjD,IAAK,IAAME,KAAQC,EAAO,CACxB,IAAMC,EAAMV,EAAAA,QAAQW,EAAOH,CAAI,EACzBI,EAAqD,CACzD,MAAO,kBACP,OAAQP,GAAS,0BACjB,mBAAoBE,EACpB,iBAAkB,2BACpB,EAEIM,IAAc,WAChB,OAAO,OAAOD,EAAO,CAAE,GAAIF,EAAK,GAAIA,EAAK,GAAI,EAAG,GAAII,CAAY,CAAC,EAEjE,OAAO,OAAOF,EAAO,CAAE,GAAI,EAAG,GAAIE,EAAa,GAAIJ,EAAK,GAAIA,CAAI,CAAC,EAGnEN,EAAO,YAAYH,EAAAA,iBAAiB,OAAQW,CAAK,CAAC,CACpD,CACF,C"}
|
package/dist/axes/grid.js
CHANGED
|
@@ -1,2 +1,30 @@
|
|
|
1
|
-
import{createSvgElement as e,removeChildren as t}from"../svg/element.js";
|
|
1
|
+
import { createSvgElement as e, removeChildren as t } from "../svg/element.js";
|
|
2
|
+
import { mapTick as n } from "./scale-utils.js";
|
|
3
|
+
//#region src/axes/grid.ts
|
|
4
|
+
function renderGrid(r, i, a, o, s, c) {
|
|
5
|
+
t(r);
|
|
6
|
+
let l = a !== !0 && a.color || void 0, u = a !== !0 && a.dash || void 0;
|
|
7
|
+
for (let t of c) {
|
|
8
|
+
let a = n(i, t), c = {
|
|
9
|
+
class: "prism-grid-line",
|
|
10
|
+
stroke: l ?? "var(--prism-grid-color)",
|
|
11
|
+
"stroke-dasharray": u,
|
|
12
|
+
"stroke-opacity": "var(--prism-grid-opacity)"
|
|
13
|
+
};
|
|
14
|
+
s === "vertical" ? Object.assign(c, {
|
|
15
|
+
x1: a,
|
|
16
|
+
x2: a,
|
|
17
|
+
y1: 0,
|
|
18
|
+
y2: o
|
|
19
|
+
}) : Object.assign(c, {
|
|
20
|
+
x1: 0,
|
|
21
|
+
x2: o,
|
|
22
|
+
y1: a,
|
|
23
|
+
y2: a
|
|
24
|
+
}), r.appendChild(e("line", c));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { renderGrid };
|
|
29
|
+
|
|
2
30
|
//# sourceMappingURL=grid.js.map
|
package/dist/axes/grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.js","names":[],"sources":["../../src/axes/grid.ts"],"sourcesContent":["import { createSvgElement, removeChildren } from '../svg/element';\nimport type { GridConfig } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\nexport function renderGrid(\n parent: SVGGElement,\n scale: AnyScale,\n config: GridConfig | true,\n crossLength: number,\n direction: 'horizontal' | 'vertical',\n ticks: readonly (Date | number | string)[],\n): void {\n removeChildren(parent);\n\n const color = (config !== true && config.color) || undefined;\n const dash = (config !== true && config.dash) || undefined;\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const attrs: Record<string, number | string | undefined> = {\n class: 'prism-grid-line',\n stroke: color ?? 'var(--prism-grid-color)',\n 'stroke-dasharray': dash,\n 'stroke-opacity': 'var(--prism-grid-opacity)',\n };\n\n if (direction === 'vertical') {\n Object.assign(attrs, { x1: pos, x2: pos, y1: 0, y2: crossLength });\n } else {\n Object.assign(attrs, { x1: 0, x2: crossLength, y1: pos, y2: pos });\n }\n\n parent.appendChild(createSvgElement('line', attrs));\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"grid.js","names":["parent","color","config","dash","tick","ticks","pos","mapTick","scale","attrs","direction","crossLength","createSvgElement"],"sources":["../../src/axes/grid.ts"],"sourcesContent":["import { createSvgElement, removeChildren } from '../svg/element';\nimport type { GridConfig } from '../types';\nimport { type AnyScale, mapTick } from './scale-utils';\n\nexport function renderGrid(\n parent: SVGGElement,\n scale: AnyScale,\n config: GridConfig | true,\n crossLength: number,\n direction: 'horizontal' | 'vertical',\n ticks: readonly (Date | number | string)[],\n): void {\n removeChildren(parent);\n\n const color = (config !== true && config.color) || undefined;\n const dash = (config !== true && config.dash) || undefined;\n\n for (const tick of ticks) {\n const pos = mapTick(scale, tick);\n const attrs: Record<string, number | string | undefined> = {\n class: 'prism-grid-line',\n stroke: color ?? 'var(--prism-grid-color)',\n 'stroke-dasharray': dash,\n 'stroke-opacity': 'var(--prism-grid-opacity)',\n };\n\n if (direction === 'vertical') {\n Object.assign(attrs, { x1: pos, x2: pos, y1: 0, y2: crossLength });\n } else {\n Object.assign(attrs, { x1: 0, x2: crossLength, y1: pos, y2: pos });\n }\n\n parent.appendChild(createSvgElement('line', attrs));\n }\n}\n"],"mappings":";;;AAIA,SAAgB,WACd,GACA,GACA,GACA,GACA,GACA,GACM;CACN,EAAeA,CAAM;CAErB,IAAMC,IAASC,MAAW,MAAQA,EAAO,SAAU,KAAA,GAC7CC,IAAQD,MAAW,MAAQA,EAAO,QAAS,KAAA;CAEjD,KAAK,IAAME,KAAQC,GAAO;EACxB,IAAMC,IAAMC,EAAQC,GAAOJ,CAAI,GACzBK,IAAqD;GACzD,OAAO;GACP,QAAQR,KAAS;GACjB,oBAAoBE;GACpB,kBAAkB;EACpB;EAQA,AANIO,MAAc,aAChB,OAAO,OAAOD,GAAO;GAAE,IAAIH;GAAK,IAAIA;GAAK,IAAI;GAAG,IAAIK;EAAY,CAAC,IAEjE,OAAO,OAAOF,GAAO;GAAE,IAAI;GAAG,IAAIE;GAAa,IAAIL;GAAK,IAAIA;EAAI,CAAC,GAGnEN,EAAO,YAAYY,EAAiB,QAAQH,CAAK,CAAC;CACpD;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scale-utils.cjs","names":[],"sources":["../../src/axes/scale-utils.ts"],"sourcesContent":["import type { BandScale, Scale } from '../types';\n\nexport type AnyScale = BandScale | Scale<Date> | Scale<number>;\n\nfunction isBandScale(scale: AnyScale): scale is BandScale {\n return typeof (scale as BandScale).bandwidth === 'function';\n}\n\n/**\n * Maps a tick value through any of prism's three scale kinds, centering band-scale\n * ticks on their band (bandScale.map() returns a band's left edge by design).\n *\n * Overloaded so a caller's `tick` type must match the scale kind it's paired with :\n * `AxisConfig`/`GridConfig` accept any scale kind, so the runtime discrimination\n * inside the implementation is unavoidable, but the overload set keeps that a single\n * isolated cast here instead of an unchecked `Date | number | string` accepted at\n * every call site.\n */\nexport function mapTick(scale: BandScale, tick: string): number;\nexport function mapTick(scale: Scale<Date>, tick: Date): number;\nexport function mapTick(scale: Scale<number>, tick: number): number;\n// Fallback overload for callers (axis.ts/grid.ts) holding an already-erased `AnyScale`\n// union: the type-correlated overloads above are what protect a caller with a\n// narrower, known scale type from mismatching it with the wrong tick type.\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number;\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number {\n if (isBandScale(scale)) return scale.map(tick as string) + scale.bandwidth() / 2;\n\n return (scale as Scale<Date | number>).map(tick as Date | number);\n}\n"],"mappings":"AAIA,SAAS,YAAY,EAAqC,CACxD,OAAO,
|
|
1
|
+
{"version":3,"file":"scale-utils.cjs","names":["scale","tick"],"sources":["../../src/axes/scale-utils.ts"],"sourcesContent":["import type { BandScale, Scale } from '../types';\n\nexport type AnyScale = BandScale | Scale<Date> | Scale<number>;\n\nfunction isBandScale(scale: AnyScale): scale is BandScale {\n return typeof (scale as BandScale).bandwidth === 'function';\n}\n\n/**\n * Maps a tick value through any of prism's three scale kinds, centering band-scale\n * ticks on their band (bandScale.map() returns a band's left edge by design).\n *\n * Overloaded so a caller's `tick` type must match the scale kind it's paired with :\n * `AxisConfig`/`GridConfig` accept any scale kind, so the runtime discrimination\n * inside the implementation is unavoidable, but the overload set keeps that a single\n * isolated cast here instead of an unchecked `Date | number | string` accepted at\n * every call site.\n */\nexport function mapTick(scale: BandScale, tick: string): number;\nexport function mapTick(scale: Scale<Date>, tick: Date): number;\nexport function mapTick(scale: Scale<number>, tick: number): number;\n// Fallback overload for callers (axis.ts/grid.ts) holding an already-erased `AnyScale`\n// union: the type-correlated overloads above are what protect a caller with a\n// narrower, known scale type from mismatching it with the wrong tick type.\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number;\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number {\n if (isBandScale(scale)) return scale.map(tick as string) + scale.bandwidth() / 2;\n\n return (scale as Scale<Date | number>).map(tick as Date | number);\n}\n"],"mappings":"AAIA,SAAS,YAAY,EAAqC,CACxD,OAAO,OAAQA,EAAoB,WAAc,UACnD,CAmBA,SAAgB,QAAQ,EAAiB,EAAsC,CAG7E,OAFI,YAAYA,CAAK,EAAUA,EAAM,IAAIC,CAAc,EAAID,EAAM,UAAU,EAAI,EAEvEA,EAA+B,IAAIC,CAAqB,CAClE,C"}
|
package/dist/axes/scale-utils.js
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/axes/scale-utils.ts
|
|
2
|
+
function isBandScale(e) {
|
|
3
|
+
return typeof e.bandwidth == "function";
|
|
4
|
+
}
|
|
5
|
+
function mapTick(e, t) {
|
|
6
|
+
return isBandScale(e) ? e.map(t) + e.bandwidth() / 2 : e.map(t);
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { mapTick };
|
|
10
|
+
|
|
2
11
|
//# sourceMappingURL=scale-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scale-utils.js","names":[],"sources":["../../src/axes/scale-utils.ts"],"sourcesContent":["import type { BandScale, Scale } from '../types';\n\nexport type AnyScale = BandScale | Scale<Date> | Scale<number>;\n\nfunction isBandScale(scale: AnyScale): scale is BandScale {\n return typeof (scale as BandScale).bandwidth === 'function';\n}\n\n/**\n * Maps a tick value through any of prism's three scale kinds, centering band-scale\n * ticks on their band (bandScale.map() returns a band's left edge by design).\n *\n * Overloaded so a caller's `tick` type must match the scale kind it's paired with :\n * `AxisConfig`/`GridConfig` accept any scale kind, so the runtime discrimination\n * inside the implementation is unavoidable, but the overload set keeps that a single\n * isolated cast here instead of an unchecked `Date | number | string` accepted at\n * every call site.\n */\nexport function mapTick(scale: BandScale, tick: string): number;\nexport function mapTick(scale: Scale<Date>, tick: Date): number;\nexport function mapTick(scale: Scale<number>, tick: number): number;\n// Fallback overload for callers (axis.ts/grid.ts) holding an already-erased `AnyScale`\n// union: the type-correlated overloads above are what protect a caller with a\n// narrower, known scale type from mismatching it with the wrong tick type.\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number;\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number {\n if (isBandScale(scale)) return scale.map(tick as string) + scale.bandwidth() / 2;\n\n return (scale as Scale<Date | number>).map(tick as Date | number);\n}\n"],"mappings":"AAIA,SAAS,YAAY,
|
|
1
|
+
{"version":3,"file":"scale-utils.js","names":["scale","tick"],"sources":["../../src/axes/scale-utils.ts"],"sourcesContent":["import type { BandScale, Scale } from '../types';\n\nexport type AnyScale = BandScale | Scale<Date> | Scale<number>;\n\nfunction isBandScale(scale: AnyScale): scale is BandScale {\n return typeof (scale as BandScale).bandwidth === 'function';\n}\n\n/**\n * Maps a tick value through any of prism's three scale kinds, centering band-scale\n * ticks on their band (bandScale.map() returns a band's left edge by design).\n *\n * Overloaded so a caller's `tick` type must match the scale kind it's paired with :\n * `AxisConfig`/`GridConfig` accept any scale kind, so the runtime discrimination\n * inside the implementation is unavoidable, but the overload set keeps that a single\n * isolated cast here instead of an unchecked `Date | number | string` accepted at\n * every call site.\n */\nexport function mapTick(scale: BandScale, tick: string): number;\nexport function mapTick(scale: Scale<Date>, tick: Date): number;\nexport function mapTick(scale: Scale<number>, tick: number): number;\n// Fallback overload for callers (axis.ts/grid.ts) holding an already-erased `AnyScale`\n// union: the type-correlated overloads above are what protect a caller with a\n// narrower, known scale type from mismatching it with the wrong tick type.\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number;\nexport function mapTick(scale: AnyScale, tick: Date | number | string): number {\n if (isBandScale(scale)) return scale.map(tick as string) + scale.bandwidth() / 2;\n\n return (scale as Scale<Date | number>).map(tick as Date | number);\n}\n"],"mappings":";AAIA,SAAS,YAAY,GAAqC;CACxD,OAAO,OAAQA,EAAoB,aAAc;AACnD;AAmBA,SAAgB,QAAQ,GAAiB,GAAsC;CAG7E,OAFI,YAAYA,CAAK,IAAUA,EAAM,IAAIC,CAAc,IAAID,EAAM,UAAU,IAAI,IAEvEA,EAA+B,IAAIC,CAAqB;AAClE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"area-chart.cjs","names":[],"sources":["../../../src/charts/area/area-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea } 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 { AreaChartConfig, AreaSeriesConfig, ChartHandle, XAxisConfig, YAxisConfig } from '../../types';\nimport { computeAreaPoints, renderArea } from './area-renderer';\n\nexport function createAreaChart(container: HTMLElement, config: AreaChartConfig): ChartHandle<AreaSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: 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 legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\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 allY = allData.flat().map((d) => d.value);\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.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(allY, area.height);\n const baselineY = yScale.map(0);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig) {\n positionAxis(groups.yAxis, yAxisConfig.position ?? 'left', area.width, area.height);\n renderAxis(groups.yAxis, yScale, yAxisConfig, area.height, 'left');\n } else {\n groups.yAxis.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-area-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const points = computeAreaPoints(allData[i], xScale, yScale);\n\n allPoints.push(points);\n\n renderArea(group, points, baselineY, {\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n fill: series.fill ?? 'gradient',\n fillOpacity: series.fillOpacity,\n marks: series.data,\n showLine: series.showLine !== false,\n transition: config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin: ctx.dimensions.margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"mbAcA,SAAgB,gBAAgB,EAAwB,EAA0D,CAChH,
|
|
1
|
+
{"version":3,"file":"area-chart.cjs","names":["createChartScaffold","seriesColor","chartArea","createCrosshair","buildXScale","buildYScale","resolveTicks","resolveTickCount","createSvgElement","seriesDomId","computeAreaPoints","ensureMarkerGroup","createSeriesInteraction","require_element","require_axis","require_grid","require_cartesian_scales","require_layout","require_chart_scaffold","require_series_id","require_crosshair","require_series_interaction","require_index","require_area_renderer","crosshair","markers","seriesList","config","container","ctx","legend","i","s","dims","area","allData","series","allX","datum","allY","d","groups","tooltip","xScale","yScale","baselineY","xAxisConfig","yAxisConfig","allPoints","group","points","data"],"sources":["../../../src/charts/area/area-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea } 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 { AreaChartConfig, AreaSeriesConfig, ChartHandle, XAxisConfig, YAxisConfig } from '../../types';\nimport { computeAreaPoints, renderArea } from './area-renderer';\n\nexport function createAreaChart(container: HTMLElement, config: AreaChartConfig): ChartHandle<AreaSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: 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 legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\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 allY = allData.flat().map((d) => d.value);\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.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(allY, area.height);\n const baselineY = yScale.map(0);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig) {\n positionAxis(groups.yAxis, yAxisConfig.position ?? 'left', area.width, area.height);\n renderAxis(groups.yAxis, yScale, yAxisConfig, area.height, 'left');\n } else {\n groups.yAxis.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-area-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const points = computeAreaPoints(allData[i], xScale, yScale);\n\n allPoints.push(points);\n\n renderArea(group, points, baselineY, {\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n fill: series.fill ?? 'gradient',\n fillOpacity: series.fillOpacity,\n marks: series.data,\n showLine: series.showLine !== false,\n transition: config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin: ctx.dimensions.margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,72 @@
|
|
|
1
|
-
import{createSvgElement as e
|
|
1
|
+
import { createSvgElement as e } from "../../svg/element.js";
|
|
2
|
+
import { positionAxis as t, renderAxis as n, resolveTickCount as r, resolveTicks as i } from "../../axes/axis.js";
|
|
3
|
+
import { renderGrid as a } from "../../axes/grid.js";
|
|
4
|
+
import { buildXScale as o, buildYScale as s } from "../../core/cartesian-scales.js";
|
|
5
|
+
import { chartArea as c } from "../../core/layout.js";
|
|
6
|
+
import { clearCartesianDom as l, createChartScaffold as u } from "../../core/chart-scaffold.js";
|
|
7
|
+
import { seriesDomId as d } from "../../core/series-id.js";
|
|
8
|
+
import { createCrosshair as f } from "../../interaction/crosshair.js";
|
|
9
|
+
import { createSeriesInteraction as p, ensureMarkerGroup as m } from "../../interaction/series-interaction.js";
|
|
10
|
+
import { seriesColor as h } from "../../theme/index.js";
|
|
11
|
+
import { computeAreaPoints as g, renderArea as _ } from "./area-renderer.js";
|
|
12
|
+
//#region src/charts/area/area-chart.ts
|
|
13
|
+
function createAreaChart(v, y) {
|
|
14
|
+
let b = null, x = null, S = y.series;
|
|
15
|
+
return u(v, y, (u) => {
|
|
16
|
+
let { groups: v, legend: C, tooltip: w } = u;
|
|
17
|
+
C?.update(S.map((e, t) => ({
|
|
18
|
+
color: h(t, e.color),
|
|
19
|
+
name: e.name
|
|
20
|
+
})));
|
|
21
|
+
let T = u.dimensions, E = c(T.width, T.height, T.margin), D = S.map((e) => e.data), O = D.flat().map((e) => e.key), k = D.flat().map((e) => e.value);
|
|
22
|
+
if (O.length === 0) {
|
|
23
|
+
l(v, C, w, b), x?.replaceChildren();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
y.crosshair && !b && (b = f(u.chartArea, y.crosshair));
|
|
27
|
+
let A = o(O, E.width), j = s(k, E.height), M = j.map(0), N = y.xAxis === !1 ? !1 : y.xAxis ?? {}, P = y.yAxis !== !1 && {
|
|
28
|
+
grid: !0,
|
|
29
|
+
...y.yAxis
|
|
30
|
+
};
|
|
31
|
+
for (P && P.grid && a(v.grid, j, P.grid, E.width, "horizontal", i(j, P, r(P, E.height, "left"))), N && N.grid && a(v.grid, A, N.grid, E.height, "vertical", i(A, N, r(N, E.width, "bottom"))), N ? (t(v.xAxis, N.position ?? "bottom", E.width, E.height), n(v.xAxis, A, N, E.width, "bottom")) : v.xAxis.replaceChildren(), P ? (t(v.yAxis, P.position ?? "left", E.width, E.height), n(v.yAxis, j, P, E.height, "left")) : v.yAxis.replaceChildren(); v.series.children.length > S.length;) v.series.removeChild(v.series.lastChild);
|
|
32
|
+
let F = [];
|
|
33
|
+
for (let t = 0; t < S.length; t++) {
|
|
34
|
+
let n = S[t], r = v.series.children[t];
|
|
35
|
+
r || (r = e("g", { class: "prism-area-series" }), v.series.appendChild(r)), r.setAttribute("data-series-id", d(n, t));
|
|
36
|
+
let i = g(D[t], A, j);
|
|
37
|
+
F.push(i), _(r, i, M, {
|
|
38
|
+
color: h(t, n.color),
|
|
39
|
+
curve: n.curve ?? "linear",
|
|
40
|
+
disposalSignal: u.disposalSignal,
|
|
41
|
+
fill: n.fill ?? "gradient",
|
|
42
|
+
fillOpacity: n.fillOpacity,
|
|
43
|
+
marks: n.data,
|
|
44
|
+
showLine: n.showLine !== !1,
|
|
45
|
+
transition: y.transition
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return w?.hide(), x = m(u.chartArea, x), p({
|
|
49
|
+
announcer: u.announcer,
|
|
50
|
+
colors: () => S.map((e, t) => h(t, e.color)),
|
|
51
|
+
crosshair: b,
|
|
52
|
+
dims: () => u.dimensions,
|
|
53
|
+
getData: () => D,
|
|
54
|
+
getPoints: () => F,
|
|
55
|
+
getSeriesList: () => S,
|
|
56
|
+
margin: u.dimensions.margin,
|
|
57
|
+
markers: x,
|
|
58
|
+
onClick: y.onClick,
|
|
59
|
+
onHover: y.onHover,
|
|
60
|
+
seriesGroup: v.series,
|
|
61
|
+
svg: u.svg,
|
|
62
|
+
tooltip: w,
|
|
63
|
+
tooltipFormat: typeof y.tooltip == "object" ? y.tooltip : void 0
|
|
64
|
+
});
|
|
65
|
+
}, (e) => {
|
|
66
|
+
S = e;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { createAreaChart };
|
|
71
|
+
|
|
2
72
|
//# sourceMappingURL=area-chart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"area-chart.js","names":[],"sources":["../../../src/charts/area/area-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea } 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 { AreaChartConfig, AreaSeriesConfig, ChartHandle, XAxisConfig, YAxisConfig } from '../../types';\nimport { computeAreaPoints, renderArea } from './area-renderer';\n\nexport function createAreaChart(container: HTMLElement, config: AreaChartConfig): ChartHandle<AreaSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: 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 legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\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 allY = allData.flat().map((d) => d.value);\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.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(allY, area.height);\n const baselineY = yScale.map(0);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig) {\n positionAxis(groups.yAxis, yAxisConfig.position ?? 'left', area.width, area.height);\n renderAxis(groups.yAxis, yScale, yAxisConfig, area.height, 'left');\n } else {\n groups.yAxis.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-area-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const points = computeAreaPoints(allData[i], xScale, yScale);\n\n allPoints.push(points);\n\n renderArea(group, points, baselineY, {\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n fill: series.fill ?? 'gradient',\n fillOpacity: series.fillOpacity,\n marks: series.data,\n showLine: series.showLine !== false,\n transition: config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin: ctx.dimensions.margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"area-chart.js","names":["crosshair","markers","seriesList","config","createChartScaffold","container","ctx","seriesColor","i","s","dims","area","chartArea","allData","series","allX","datum","allY","d","clearCartesianDom","groups","legend","tooltip","createCrosshair","xScale","buildXScale","yScale","buildYScale","baselineY","xAxisConfig","yAxisConfig","renderGrid","resolveTicks","resolveTickCount","positionAxis","renderAxis","allPoints","group","createSvgElement","seriesDomId","points","computeAreaPoints","renderArea","ensureMarkerGroup","createSeriesInteraction","data"],"sources":["../../../src/charts/area/area-chart.ts"],"sourcesContent":["import { positionAxis, renderAxis, resolveTickCount, resolveTicks } from '../../axes/axis';\nimport { renderGrid } from '../../axes/grid';\nimport { buildXScale, buildYScale } from '../../core/cartesian-scales';\nimport { clearCartesianDom, createChartScaffold } from '../../core/chart-scaffold';\nimport { chartArea } 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 { AreaChartConfig, AreaSeriesConfig, ChartHandle, XAxisConfig, YAxisConfig } from '../../types';\nimport { computeAreaPoints, renderArea } from './area-renderer';\n\nexport function createAreaChart(container: HTMLElement, config: AreaChartConfig): ChartHandle<AreaSeriesConfig[]> {\n let crosshair: ReturnType<typeof createCrosshair> | null = null;\n let markers: 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 legend?.update(seriesList.map((s, i) => ({ color: seriesColor(i, s.color), name: s.name })));\n const dims = ctx.dimensions;\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 allY = allData.flat().map((d) => d.value);\n\n if (allX.length === 0) {\n clearCartesianDom(groups, legend, tooltip, crosshair);\n markers?.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(allY, area.height);\n const baselineY = yScale.map(0);\n\n // Axes render by default (value axis with gridlines); `false` opts out. The value\n // axis merges over its default so a partial config (e.g. only `tickFormat`) keeps\n // the default gridlines.\n const xAxisConfig: XAxisConfig | false = config.xAxis === false ? false : (config.xAxis ?? {});\n const yAxisConfig: YAxisConfig | false = config.yAxis === false ? false : { grid: true, ...config.yAxis };\n\n if (yAxisConfig && yAxisConfig.grid) {\n renderGrid(\n groups.grid,\n yScale,\n yAxisConfig.grid,\n area.width,\n 'horizontal',\n resolveTicks(yScale, yAxisConfig, resolveTickCount(yAxisConfig, area.height, 'left')),\n );\n }\n\n if (xAxisConfig && xAxisConfig.grid) {\n renderGrid(\n groups.grid,\n xScale,\n xAxisConfig.grid,\n area.height,\n 'vertical',\n resolveTicks(xScale, xAxisConfig, resolveTickCount(xAxisConfig, area.width, 'bottom')),\n );\n }\n\n if (xAxisConfig) {\n positionAxis(groups.xAxis, xAxisConfig.position ?? 'bottom', area.width, area.height);\n renderAxis(groups.xAxis, xScale, xAxisConfig, area.width, 'bottom');\n } else {\n groups.xAxis.replaceChildren();\n }\n\n if (yAxisConfig) {\n positionAxis(groups.yAxis, yAxisConfig.position ?? 'left', area.width, area.height);\n renderAxis(groups.yAxis, yScale, yAxisConfig, area.height, 'left');\n } else {\n groups.yAxis.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-area-series' });\n groups.series.appendChild(group);\n }\n\n group.setAttribute('data-series-id', seriesDomId(series, i));\n\n const points = computeAreaPoints(allData[i], xScale, yScale);\n\n allPoints.push(points);\n\n renderArea(group, points, baselineY, {\n color: seriesColor(i, series.color),\n curve: series.curve ?? 'linear',\n disposalSignal: ctx.disposalSignal,\n fill: series.fill ?? 'gradient',\n fillOpacity: series.fillOpacity,\n marks: series.data,\n showLine: series.showLine !== false,\n transition: config.transition,\n });\n }\n\n tooltip?.hide();\n markers = ensureMarkerGroup(ctx.chartArea, markers);\n\n return createSeriesInteraction({\n announcer: ctx.announcer,\n colors: () => seriesList.map((s, i) => seriesColor(i, s.color)),\n crosshair,\n dims: () => ctx.dimensions,\n getData: () => allData,\n getPoints: () => allPoints,\n getSeriesList: () => seriesList,\n margin: ctx.dimensions.margin,\n markers,\n onClick: config.onClick,\n onHover: config.onHover,\n seriesGroup: groups.series,\n svg: ctx.svg,\n tooltip,\n tooltipFormat: typeof config.tooltip === 'object' ? config.tooltip : undefined,\n });\n },\n (data) => {\n seriesList = data;\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"area-renderer.cjs","names":[],"sources":["../../../src/charts/area/area-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 { uniqueId } from '../../core/ids';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface AreaRenderOptions {\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 fill: 'gradient' | 'solid';\n /** Explicit opacity beats the `--prism-area-opacity` theme token. */\n fillOpacity?: number;\n /** Per-datum presentation parallel to `points`; styled runs split the top line into subpaths. */\n marks?: readonly DatumMark[];\n showLine: boolean;\n transition?: TransitionOption;\n}\n\nconst activeAreaAnimations = new WeakMap<SVGGElement, () => void>();\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildLinePath(pts: Point[], curve: AreaRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\n/** A vertical gradient fading to transparent at the baseline, or a flat fill. */\nfunction applyAreaFill(parent: SVGGElement, fill: SVGPathElement, options: AreaRenderOptions): void {\n let gradient = parent.querySelector<SVGLinearGradientElement>('linearGradient');\n\n if (options.fill === 'gradient') {\n if (!gradient) {\n const defs = createSvgElement('defs');\n\n gradient = createSvgElement('linearGradient', { id: uniqueId('prism-area-fill'), x1: 0, x2: 0, y1: 0, y2: 1 });\n gradient.append(\n createSvgElement('stop', { class: 'prism-area-stop-top', offset: 0 }),\n createSvgElement('stop', { class: 'prism-area-stop-bottom', offset: 1 }),\n );\n defs.appendChild(gradient);\n parent.insertBefore(defs, parent.firstChild);\n }\n\n for (const stop of gradient.querySelectorAll('stop')) {\n stop.setAttribute('stop-color', options.color);\n stop.style.stopColor = options.color;\n }\n\n setAttributes(fill, { fill: `url(#${gradient.id})` });\n } else {\n gradient?.parentElement?.remove();\n setAttributes(fill, { fill: options.color });\n }\n\n setAttributes(fill, { class: `prism-area-fill prism-area-fill--${options.fill}`, stroke: 'none' });\n fill.style.fillOpacity = options.fillOpacity === undefined ? '' : String(options.fillOpacity);\n}\n\nexport function renderArea(parent: SVGGElement, points: Point[], baselineY: number, options: AreaRenderOptions): void {\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let fill = parent.querySelector<SVGPathElement>('.prism-area-fill');\n\n if (!fill) {\n fill = createSvgElement('path', { class: 'prism-area-fill' });\n parent.appendChild(fill);\n }\n\n applyAreaFill(parent, fill, options);\n\n let line: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let lines: SVGPathElement[] = [];\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n\n if (options.showLine) {\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-area-line')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n lines = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-area-line', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(lines[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': 2,\n });\n }\n\n line = null;\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-area-line')];\n\n for (const stale of existing.slice(1)) stale.remove();\n\n line = existing[0] ?? null;\n\n if (!line) {\n line = createSvgElement('path', { class: 'prism-area-line', fill: 'none' });\n parent.appendChild(line);\n }\n\n setAttributes(line, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': 2,\n });\n }\n } else {\n for (const stale of parent.querySelectorAll('.prism-area-line')) stale.remove();\n }\n\n const drawLine = (pts: Point[]): void => {\n if (!options.showLine) return;\n\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(lines[r], { d: buildLinePath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else if (line) {\n setAttributes(line, { d: buildLinePath(pts, options.curve) });\n }\n };\n\n if (dur === 0) {\n const bottomPoints = points.map((p) => ({ x: p.x, y: baselineY }));\n\n setAttributes(fill, { d: areaPath(points, bottomPoints, options.curve) });\n\n drawLine(points);\n drawnPoints.set(parent, points);\n\n return;\n }\n\n activeAreaAnimations.get(parent)?.();\n\n const hasExisting = drawnPoints.has(parent);\n // A first render has no drawn shape to interpolate from: the mount animation\n // grows the area out of its baseline instead.\n const rawFrom: Point[] = hasExisting\n ? (drawnPoints.get(parent) ?? points)\n : points.map((p) => ({ x: p.x, y: baselineY }));\n const fromPoints: Point[] = points.map((_, i) => rawFrom[i] ?? rawFrom[rawFrom.length - 1] ?? points[i]);\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => ({\n x: tweenNumber(fromPoints[i].x, to.x, e),\n y: tweenNumber(fromPoints[i].y, to.y, e),\n }));\n const interpolatedBottom = interpolated.map((p) => ({ x: p.x, y: baselineY }));\n\n drawnPoints.set(parent, interpolated);\n setAttributes(fill!, { d: areaPath(interpolated, interpolatedBottom, options.curve) });\n drawLine(interpolated);\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 activeAreaAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAreaAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computeAreaPoints(\n data: ContinuousDatum[],\n xScale: Scale<Date | number>,\n yScale: Scale<number>,\n): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computeAreaPoints: 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('computeAreaPoints: 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":"area-renderer.cjs","names":["monotonePath","stepPath","linePath","createSvgElement","uniqueId","resolveMotion","resolveEasing","hasStyledRuns","computeStyleRuns","areaPath","tweenNumber","startTween","require_element","require_easing","require_motion","require_tween","require_transition","require_datum_style","require_ids","require_path","activeAreaAnimations","drawnPoints","curve","pts","gradient","parent","options","defs","stop","fill","motion","dur","easing","line","runs","lines","styled","marks","points","existing","extra","reuse","created","r","run","stale","bottomPoints","p","baselineY","rawFrom","fromPoints","i","interpolated","to","e","interpolatedBottom","progress","data","d","xScale","yScale"],"sources":["../../../src/charts/area/area-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 { uniqueId } from '../../core/ids';\nimport { createSvgElement, setAttributes } from '../../svg/element';\nimport type { Point } from '../../svg/path';\nimport { areaPath, linePath, monotonePath, stepPath } from '../../svg/path';\nimport type { ContinuousDatum, Scale, TransitionOption } from '../../types';\n\nexport interface AreaRenderOptions {\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 fill: 'gradient' | 'solid';\n /** Explicit opacity beats the `--prism-area-opacity` theme token. */\n fillOpacity?: number;\n /** Per-datum presentation parallel to `points`; styled runs split the top line into subpaths. */\n marks?: readonly DatumMark[];\n showLine: boolean;\n transition?: TransitionOption;\n}\n\nconst activeAreaAnimations = new WeakMap<SVGGElement, () => void>();\nconst drawnPoints = new WeakMap<SVGGElement, Point[]>();\n\nfunction buildLinePath(pts: Point[], curve: AreaRenderOptions['curve']): string {\n return curve === 'monotone' ? monotonePath(pts) : curve === 'step' ? stepPath(pts) : linePath(pts);\n}\n\n/** A vertical gradient fading to transparent at the baseline, or a flat fill. */\nfunction applyAreaFill(parent: SVGGElement, fill: SVGPathElement, options: AreaRenderOptions): void {\n let gradient = parent.querySelector<SVGLinearGradientElement>('linearGradient');\n\n if (options.fill === 'gradient') {\n if (!gradient) {\n const defs = createSvgElement('defs');\n\n gradient = createSvgElement('linearGradient', { id: uniqueId('prism-area-fill'), x1: 0, x2: 0, y1: 0, y2: 1 });\n gradient.append(\n createSvgElement('stop', { class: 'prism-area-stop-top', offset: 0 }),\n createSvgElement('stop', { class: 'prism-area-stop-bottom', offset: 1 }),\n );\n defs.appendChild(gradient);\n parent.insertBefore(defs, parent.firstChild);\n }\n\n for (const stop of gradient.querySelectorAll('stop')) {\n stop.setAttribute('stop-color', options.color);\n stop.style.stopColor = options.color;\n }\n\n setAttributes(fill, { fill: `url(#${gradient.id})` });\n } else {\n gradient?.parentElement?.remove();\n setAttributes(fill, { fill: options.color });\n }\n\n setAttributes(fill, { class: `prism-area-fill prism-area-fill--${options.fill}`, stroke: 'none' });\n fill.style.fillOpacity = options.fillOpacity === undefined ? '' : String(options.fillOpacity);\n}\n\nexport function renderArea(parent: SVGGElement, points: Point[], baselineY: number, options: AreaRenderOptions): void {\n const motion = resolveMotion(options.transition);\n const dur = motion.duration;\n const easing = resolveEasing(motion.easing);\n\n let fill = parent.querySelector<SVGPathElement>('.prism-area-fill');\n\n if (!fill) {\n fill = createSvgElement('path', { class: 'prism-area-fill' });\n parent.appendChild(fill);\n }\n\n applyAreaFill(parent, fill, options);\n\n let line: SVGPathElement | null = null;\n let runs: readonly StyleRun[] = [];\n let lines: SVGPathElement[] = [];\n const styled = hasStyledRuns(options.marks);\n const marks = options.marks ?? [];\n\n if (options.showLine) {\n if (styled) {\n runs = computeStyleRuns(marks, points.length);\n\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-area-line')];\n\n for (const extra of existing.slice(runs.length)) extra.remove();\n\n lines = runs.map((_, r) => {\n const reuse = existing[r];\n\n if (reuse) return reuse;\n\n const created = createSvgElement('path', { class: 'prism-area-line', fill: 'none' });\n\n parent.appendChild(created);\n\n return created;\n });\n\n for (const [r, run] of runs.entries()) {\n setAttributes(lines[r], {\n opacity: run.opacity,\n stroke: options.color,\n 'stroke-dasharray': run.dash,\n 'stroke-width': 2,\n });\n }\n\n line = null;\n } else {\n const existing = [...parent.querySelectorAll<SVGPathElement>('.prism-area-line')];\n\n for (const stale of existing.slice(1)) stale.remove();\n\n line = existing[0] ?? null;\n\n if (!line) {\n line = createSvgElement('path', { class: 'prism-area-line', fill: 'none' });\n parent.appendChild(line);\n }\n\n setAttributes(line, {\n opacity: undefined,\n stroke: options.color,\n 'stroke-dasharray': undefined,\n 'stroke-width': 2,\n });\n }\n } else {\n for (const stale of parent.querySelectorAll('.prism-area-line')) stale.remove();\n }\n\n const drawLine = (pts: Point[]): void => {\n if (!options.showLine) return;\n\n if (styled) {\n for (const [r, run] of runs.entries()) {\n setAttributes(lines[r], { d: buildLinePath(pts.slice(run.start, run.end + 1), options.curve) });\n }\n } else if (line) {\n setAttributes(line, { d: buildLinePath(pts, options.curve) });\n }\n };\n\n if (dur === 0) {\n const bottomPoints = points.map((p) => ({ x: p.x, y: baselineY }));\n\n setAttributes(fill, { d: areaPath(points, bottomPoints, options.curve) });\n\n drawLine(points);\n drawnPoints.set(parent, points);\n\n return;\n }\n\n activeAreaAnimations.get(parent)?.();\n\n const hasExisting = drawnPoints.has(parent);\n // A first render has no drawn shape to interpolate from: the mount animation\n // grows the area out of its baseline instead.\n const rawFrom: Point[] = hasExisting\n ? (drawnPoints.get(parent) ?? points)\n : points.map((p) => ({ x: p.x, y: baselineY }));\n const fromPoints: Point[] = points.map((_, i) => rawFrom[i] ?? rawFrom[rawFrom.length - 1] ?? points[i]);\n\n const paintFrame = (e: number): void => {\n const interpolated: Point[] = points.map((to, i) => ({\n x: tweenNumber(fromPoints[i].x, to.x, e),\n y: tweenNumber(fromPoints[i].y, to.y, e),\n }));\n const interpolatedBottom = interpolated.map((p) => ({ x: p.x, y: baselineY }));\n\n drawnPoints.set(parent, interpolated);\n setAttributes(fill!, { d: areaPath(interpolated, interpolatedBottom, options.curve) });\n drawLine(interpolated);\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 activeAreaAnimations.set(\n parent,\n startTween({\n count: 1,\n duration: dur,\n easing,\n onComplete: () => {\n activeAreaAnimations.delete(parent);\n drawnPoints.set(parent, points);\n },\n onFrame: (progress) => paintFrame(progress(0)),\n signal: options.disposalSignal,\n }),\n );\n}\n\nexport function computeAreaPoints(\n data: ContinuousDatum[],\n xScale: Scale<Date | number>,\n yScale: Scale<number>,\n): Point[] {\n if (data.some((d) => d.key == null)) {\n warn(\n 'computeAreaPoints: 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('computeAreaPoints: 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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"}
|