@dou-ui/chart 0.0.0-stage → 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/chart.js +6 -0
- package/dist/chart.js.map +1 -0
- package/dist/chart.vue_vue_type_script_setup_true_lang.js +4245 -0
- package/dist/chart.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/area.js +6 -0
- package/dist/components/area.js.map +1 -0
- package/dist/components/area.vue_vue_type_script_setup_true_lang.js +55 -0
- package/dist/components/area.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/axis.js +6 -0
- package/dist/components/axis.js.map +1 -0
- package/dist/components/axis.vue_vue_type_script_setup_true_lang.js +46 -0
- package/dist/components/axis.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/bar.js +6 -0
- package/dist/components/bar.js.map +1 -0
- package/dist/components/bar.vue_vue_type_script_setup_true_lang.js +46 -0
- package/dist/components/bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/boxplot.js +6 -0
- package/dist/components/boxplot.js.map +1 -0
- package/dist/components/boxplot.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/components/boxplot.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/brush.js +6 -0
- package/dist/components/brush.js.map +1 -0
- package/dist/components/brush.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/components/brush.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/funnel.js +6 -0
- package/dist/components/funnel.js.map +1 -0
- package/dist/components/funnel.vue_vue_type_script_setup_true_lang.js +41 -0
- package/dist/components/funnel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/gauge.js +6 -0
- package/dist/components/gauge.js.map +1 -0
- package/dist/components/gauge.vue_vue_type_script_setup_true_lang.js +91 -0
- package/dist/components/gauge.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/heatmap.js +6 -0
- package/dist/components/heatmap.js.map +1 -0
- package/dist/components/heatmap.vue_vue_type_script_setup_true_lang.js +45 -0
- package/dist/components/heatmap.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/histogram.js +6 -0
- package/dist/components/histogram.js.map +1 -0
- package/dist/components/histogram.vue_vue_type_script_setup_true_lang.js +61 -0
- package/dist/components/histogram.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/line.js +6 -0
- package/dist/components/line.js.map +1 -0
- package/dist/components/line.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/components/line.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/marker.js +6 -0
- package/dist/components/marker.js.map +1 -0
- package/dist/components/marker.vue_vue_type_script_setup_true_lang.js +31 -0
- package/dist/components/marker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/pie.js +6 -0
- package/dist/components/pie.js.map +1 -0
- package/dist/components/pie.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/components/pie.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/radar.js +6 -0
- package/dist/components/radar.js.map +1 -0
- package/dist/components/radar.vue_vue_type_script_setup_true_lang.js +45 -0
- package/dist/components/radar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/range.js +6 -0
- package/dist/components/range.js.map +1 -0
- package/dist/components/range.vue_vue_type_script_setup_true_lang.js +27 -0
- package/dist/components/range.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/scatter.js +6 -0
- package/dist/components/scatter.js.map +1 -0
- package/dist/components/scatter.vue_vue_type_script_setup_true_lang.js +45 -0
- package/dist/components/scatter.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/sunburst.js +6 -0
- package/dist/components/sunburst.js.map +1 -0
- package/dist/components/sunburst.vue_vue_type_script_setup_true_lang.js +36 -0
- package/dist/components/sunburst.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/tooltip.js +6 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/tooltip.vue_vue_type_script_setup_true_lang.js +31 -0
- package/dist/components/tooltip.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/treemap.js +6 -0
- package/dist/components/treemap.js.map +1 -0
- package/dist/components/treemap.vue_vue_type_script_setup_true_lang.js +33 -0
- package/dist/components/treemap.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/waterfall.js +6 -0
- package/dist/components/waterfall.js.map +1 -0
- package/dist/components/waterfall.vue_vue_type_script_setup_true_lang.js +49 -0
- package/dist/components/waterfall.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/zoom.js +6 -0
- package/dist/components/zoom.js.map +1 -0
- package/dist/components/zoom.vue_vue_type_script_setup_true_lang.js +37 -0
- package/dist/components/zoom.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/context.js +30 -0
- package/dist/context.js.map +1 -0
- package/dist/core/bar.js +223 -0
- package/dist/core/bar.js.map +1 -0
- package/dist/core/box.js +150 -0
- package/dist/core/box.js.map +1 -0
- package/dist/core/colors.js +58 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/data.js +257 -0
- package/dist/core/data.js.map +1 -0
- package/dist/core/decimate.js +211 -0
- package/dist/core/decimate.js.map +1 -0
- package/dist/core/format.js +151 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/funnel.js +68 -0
- package/dist/core/funnel.js.map +1 -0
- package/dist/core/grid.js +87 -0
- package/dist/core/grid.js.map +1 -0
- package/dist/core/heatmap.js +187 -0
- package/dist/core/heatmap.js.map +1 -0
- package/dist/core/histogram.js +81 -0
- package/dist/core/histogram.js.map +1 -0
- package/dist/core/hit.js +115 -0
- package/dist/core/hit.js.map +1 -0
- package/dist/core/labels.js +141 -0
- package/dist/core/labels.js.map +1 -0
- package/dist/core/layout.js +1002 -0
- package/dist/core/layout.js.map +1 -0
- package/dist/core/line.js +230 -0
- package/dist/core/line.js.map +1 -0
- package/dist/core/marker.js +205 -0
- package/dist/core/marker.js.map +1 -0
- package/dist/core/model.js +391 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/painter.js +79 -0
- package/dist/core/painter.js.map +1 -0
- package/dist/core/pattern.js +102 -0
- package/dist/core/pattern.js.map +1 -0
- package/dist/core/pie.js +119 -0
- package/dist/core/pie.js.map +1 -0
- package/dist/core/radar.js +83 -0
- package/dist/core/radar.js.map +1 -0
- package/dist/core/scale.js +149 -0
- package/dist/core/scale.js.map +1 -0
- package/dist/core/scatter.js +263 -0
- package/dist/core/scatter.js.map +1 -0
- package/dist/core/svg.js +209 -0
- package/dist/core/svg.js.map +1 -0
- package/dist/core/sync.js +21 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/time.js +217 -0
- package/dist/core/time.js.map +1 -0
- package/dist/core/tree.js +348 -0
- package/dist/core/tree.js.map +1 -0
- package/dist/core/warn.js +11 -0
- package/dist/core/warn.js.map +1 -0
- package/dist/core/waterfall.js +134 -0
- package/dist/core/waterfall.js.map +1 -0
- package/dist/core/window.js +94 -0
- package/dist/core/window.js.map +1 -0
- package/dist/define.js +62 -0
- package/dist/define.js.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/locale.js +170 -0
- package/dist/locale.js.map +1 -0
- package/dist/overlay.js +6 -0
- package/dist/overlay.js.map +1 -0
- package/dist/overlay.vue_vue_type_script_setup_true_lang.js +207 -0
- package/dist/overlay.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/pointer.js +6 -0
- package/dist/pointer.js.map +1 -0
- package/dist/pointer.vue_vue_type_script_setup_true_lang.js +136 -0
- package/dist/pointer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/static.js +6 -0
- package/dist/static.js.map +1 -0
- package/dist/static.vue_vue_type_script_setup_true_lang.js +34 -0
- package/dist/static.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +3 -0
- package/dist/table.js +6 -0
- package/dist/table.js.map +1 -0
- package/dist/table.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/table.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/types/chart.vue.d.ts +24 -0
- package/dist/types/components/area.vue.d.ts +16 -0
- package/dist/types/components/axis.vue.d.ts +8 -0
- package/dist/types/components/bar.vue.d.ts +14 -0
- package/dist/types/components/boxplot.vue.d.ts +14 -0
- package/dist/types/components/brush.vue.d.ts +22 -0
- package/dist/types/components/funnel.vue.d.ts +14 -0
- package/dist/types/components/gauge.vue.d.ts +17 -0
- package/dist/types/components/heatmap.vue.d.ts +14 -0
- package/dist/types/components/histogram.vue.d.ts +14 -0
- package/dist/types/components/line.vue.d.ts +16 -0
- package/dist/types/components/marker.vue.d.ts +6 -0
- package/dist/types/components/pie.vue.d.ts +23 -0
- package/dist/types/components/radar.vue.d.ts +16 -0
- package/dist/types/components/range.vue.d.ts +12 -0
- package/dist/types/components/scatter.vue.d.ts +14 -0
- package/dist/types/components/sunburst.vue.d.ts +17 -0
- package/dist/types/components/tooltip.vue.d.ts +13 -0
- package/dist/types/components/treemap.vue.d.ts +8 -0
- package/dist/types/components/waterfall.vue.d.ts +16 -0
- package/dist/types/components/zoom.vue.d.ts +18 -0
- package/dist/types/context.d.ts +87 -0
- package/dist/types/core/bar.d.ts +38 -0
- package/dist/types/core/box.d.ts +25 -0
- package/dist/types/core/colors.d.ts +16 -0
- package/dist/types/core/data.d.ts +72 -0
- package/dist/types/core/decimate.d.ts +39 -0
- package/dist/types/core/format.d.ts +33 -0
- package/dist/types/core/funnel.d.ts +15 -0
- package/dist/types/core/grid.d.ts +18 -0
- package/dist/types/core/heatmap.d.ts +17 -0
- package/dist/types/core/histogram.d.ts +23 -0
- package/dist/types/core/hit.d.ts +31 -0
- package/dist/types/core/labels.d.ts +45 -0
- package/dist/types/core/layout.d.ts +259 -0
- package/dist/types/core/line.d.ts +36 -0
- package/dist/types/core/marker.d.ts +67 -0
- package/dist/types/core/model.d.ts +86 -0
- package/dist/types/core/painter.d.ts +34 -0
- package/dist/types/core/pattern.d.ts +14 -0
- package/dist/types/core/pie.d.ts +66 -0
- package/dist/types/core/radar.d.ts +12 -0
- package/dist/types/core/scale.d.ts +60 -0
- package/dist/types/core/scatter.d.ts +16 -0
- package/dist/types/core/series.d.ts +228 -0
- package/dist/types/core/svg.d.ts +63 -0
- package/dist/types/core/sync.d.ts +8 -0
- package/dist/types/core/time.d.ts +20 -0
- package/dist/types/core/tree.d.ts +84 -0
- package/dist/types/core/warn.d.ts +4 -0
- package/dist/types/core/waterfall.d.ts +24 -0
- package/dist/types/core/window.d.ts +36 -0
- package/dist/types/define.d.ts +115 -0
- package/dist/types/index.d.ts +363 -0
- package/dist/types/locale.d.ts +100 -0
- package/dist/types/overlay.vue.d.ts +95 -0
- package/dist/types/pointer.vue.d.ts +53 -0
- package/dist/types/static.vue.d.ts +24 -0
- package/dist/types/table.vue.d.ts +19 -0
- package/dist/types/types.d.ts +555 -0
- package/dist/types/zoom-layer.vue.d.ts +41 -0
- package/dist/zoom-layer.js +6 -0
- package/dist/zoom-layer.js.map +1 -0
- package/dist/zoom-layer.vue_vue_type_script_setup_true_lang.js +210 -0
- package/dist/zoom-layer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/package.json +53 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"histogram.js","names":[],"sources":["../../src/core/histogram.ts"],"sourcesContent":["import { barLabels, drawBars, type BarStyle } from './bar'\nimport { warnOnce } from './warn'\nimport { nextNiceStep, niceStep } from './scale'\nimport type { ChartSeriesKind, ChartView } from './series'\n\n/** The most bins a histogram has: more would be thinner than a pixel, and slow. */\nexport const MAX_BINS = 1000\n\n/*\n * A histogram: values counted into bins of equal width, and a bar for each\n * bin across all of it, so the bars stand side by side with only a\n * hairline between them. The bins' edges are round numbers.\n */\n\nexport interface HistogramBin {\n /** Where the bin starts, inclusive. */\n x0: number\n /** Where it ends: exclusive, but for the last bin. */\n x1: number\n /** Its middle, where the bar is placed. */\n x: number\n count: number\n}\n\n/**\n * Counts `values` into bins of width `step`, or of a round width giving\n * about `count` bins (by default, by the number of values: Sturges' rule).\n * Values that aren't numbers are left out.\n */\nexport function histogramBins(\n values: ArrayLike<number>,\n { count, step }: { count?: number; step?: number } = {},\n): HistogramBin[] {\n let min = Infinity\n let max = -Infinity\n let n = 0\n for (let i = 0; i < values.length; i++) {\n const v = values[i]!\n if (!Number.isFinite(v)) continue\n n++\n if (v < min) min = v\n if (v > max) max = v\n }\n if (!n) return []\n if (step !== undefined && !(step > 0))\n warnOnce('histogram-step', `a histogram's \\`step\\` must be above 0; ${step} is left out.`)\n let width =\n step && step > 0\n ? step\n : max > min\n ? niceStep(max - min, Math.min(MAX_BINS, Math.max(1, count ?? Math.ceil(Math.log2(n)) + 1)))\n : 1\n // too many bins to draw (or to hold): the narrowest round width that keeps within the most\n if ((max - Math.floor(min / width) * width) / width > MAX_BINS) {\n warnOnce(\n 'histogram-bins',\n `a histogram's \\`step\\` of ${width} makes more than ${MAX_BINS} bins; they are widened.`,\n )\n width = niceStep(max - min, MAX_BINS / 2)\n while ((max - Math.floor(min / width) * width) / width > MAX_BINS) width = nextNiceStep(width)\n }\n const start = Math.floor(min / width) * width\n // the largest value falls in the last bin, which includes its end\n const bins = Math.max(1, Math.ceil((max - start) / width - 1e-9))\n const out: HistogramBin[] = []\n for (let k = 0; k < bins; k++) {\n // round each edge, so 0.1 steps give 0.3, not 0.30000000000000004\n const x0 = round(start + k * width, width)\n const x1 = round(start + (k + 1) * width, width)\n out.push({ x0, x1, x: (x0 + x1) / 2, count: 0 })\n }\n for (let i = 0; i < values.length; i++) {\n const v = values[i]!\n if (!Number.isFinite(v)) continue\n const k = Math.min(bins - 1, Math.floor((v - start) / width + 1e-9))\n out[k]!.count++\n }\n return out\n}\n\nfunction round(value: number, step: number) {\n const digits = Math.max(0, -Math.floor(Math.log10(step)) + 1)\n return Number(value.toFixed(Math.min(20, digits)))\n}\n\n/** The bars across all of each bin, a hairline apart. */\nconst placement = (view: ChartView) => {\n const gap = view.band > 4 ? 1 : 0\n return { offset: -view.band / 2 + gap / 2, width: view.band - gap }\n}\n\nexport const histogramKind: ChartSeriesKind<BarStyle> = {\n type: 'bar',\n zero: true,\n band: true,\n draw: (painter, series, view) => drawBars(painter, series, view, placement(view)),\n labels: (series, view) => barLabels(series, view, placement(view)),\n xTitle: (series, row, text) => {\n const bin = series.rows as unknown as HistogramBin[]\n const b = bin[row]\n return b ? `${text(b.x0)} – ${text(b.x1)}` : ''\n },\n xStep: (series) => {\n const b = (series.rows as unknown as HistogramBin[])[0]\n return b ? b.x1 - b.x0 : Number.NaN\n },\n}\n"],"mappings":";;;;;AAMA,IAAa,WAAW;;;;;;AAuBxB,SAAgB,cACd,QACA,EAAE,OAAO,SAA4C,CAAC,GACtC;CAChB,IAAI,MAAM;CACV,IAAI,MAAM;CACV,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,IAAI,OAAO;EACjB,IAAI,CAAC,OAAO,SAAS,CAAC,GAAG;EACzB;EACA,IAAI,IAAI,KAAK,MAAM;EACnB,IAAI,IAAI,KAAK,MAAM;CACrB;CACA,IAAI,CAAC,GAAG,OAAO,CAAC;CAChB,IAAI,SAAS,KAAA,KAAa,EAAE,OAAO,IACjC,SAAS,kBAAkB,2CAA2C,KAAK,cAAc;CAC3F,IAAI,QACF,QAAQ,OAAO,IACX,OACA,MAAM,MACJ,SAAS,MAAM,KAAK,KAAK,IAAI,UAAU,KAAK,IAAI,GAAG,SAAS,KAAK,KAAK,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IACzF;CAER,KAAK,MAAM,KAAK,MAAM,MAAM,KAAK,IAAI,SAAS,QAAA,KAAkB;EAC9D,SACE,kBACA,6BAA6B,MAAM,mBAAmB,SAAS,yBACjE;EACA,QAAQ,SAAS,MAAM,KAAK,WAAW,CAAC;EACxC,QAAQ,MAAM,KAAK,MAAM,MAAM,KAAK,IAAI,SAAS,QAAQ,UAAU,QAAQ,aAAa,KAAK;CAC/F;CACA,MAAM,QAAQ,KAAK,MAAM,MAAM,KAAK,IAAI;CAExC,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,SAAS,QAAQ,IAAI,CAAC;CAChE,MAAM,MAAsB,CAAC;CAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK;EAE7B,MAAM,KAAK,MAAM,QAAQ,IAAI,OAAO,KAAK;EACzC,MAAM,KAAK,MAAM,SAAS,IAAI,KAAK,OAAO,KAAK;EAC/C,IAAI,KAAK;GAAE;GAAI;GAAI,IAAI,KAAK,MAAM;GAAG,OAAO;EAAE,CAAC;CACjD;CACA,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,IAAI,OAAO;EACjB,IAAI,CAAC,OAAO,SAAS,CAAC,GAAG;EACzB,MAAM,IAAI,KAAK,IAAI,OAAO,GAAG,KAAK,OAAO,IAAI,SAAS,QAAQ,IAAI,CAAC;EACnE,IAAI,EAAE,CAAE;CACV;CACA,OAAO;AACT;AAEA,SAAS,MAAM,OAAe,MAAc;CAC1C,MAAM,SAAS,KAAK,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC;CAC5D,OAAO,OAAO,MAAM,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC;AACnD;;AAGA,IAAM,aAAa,SAAoB;CACrC,MAAM,MAAM,KAAK,OAAO,IAAI,IAAI;CAChC,OAAO;EAAE,QAAQ,CAAC,KAAK,OAAO,IAAI,MAAM;EAAG,OAAO,KAAK,OAAO;CAAI;AACpE;AAEA,IAAa,gBAA2C;CACtD,MAAM;CACN,MAAM;CACN,MAAM;CACN,OAAO,SAAS,QAAQ,SAAS,SAAS,SAAS,QAAQ,MAAM,UAAU,IAAI,CAAC;CAChF,SAAS,QAAQ,SAAS,UAAU,QAAQ,MAAM,UAAU,IAAI,CAAC;CACjE,SAAS,QAAQ,KAAK,SAAS;EAE7B,MAAM,IADM,OAAO,KACL;EACd,OAAO,IAAI,GAAG,KAAK,EAAE,EAAE,EAAE,KAAK,KAAK,EAAE,EAAE,MAAM;CAC/C;CACA,QAAQ,WAAW;EACjB,MAAM,IAAK,OAAO,KAAmC;EACrD,OAAO,IAAI,EAAE,KAAK,EAAE,KAAK;CAC3B;AACF"}
|
package/dist/core/hit.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/core/hit.ts
|
|
2
|
+
var orders = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/** The indices of `values` from the smallest to the largest, `NaN` left out. Cached per array. */
|
|
4
|
+
function sortedOrder(values) {
|
|
5
|
+
let order = orders.get(values);
|
|
6
|
+
if (!order) {
|
|
7
|
+
let n = 0;
|
|
8
|
+
for (let i = 0; i < values.length; i++) if (values[i] === values[i]) n++;
|
|
9
|
+
order = new Int32Array(n);
|
|
10
|
+
for (let i = 0, j = 0; i < values.length; i++) if (values[i] === values[i]) order[j++] = i;
|
|
11
|
+
let sorted = true;
|
|
12
|
+
for (let j = 1; j < n && sorted; j++) if (values[order[j]] < values[order[j - 1]]) sorted = false;
|
|
13
|
+
if (!sorted) order.sort((a, b) => values[a] - values[b]);
|
|
14
|
+
orders.set(values, order);
|
|
15
|
+
}
|
|
16
|
+
return order;
|
|
17
|
+
}
|
|
18
|
+
var identity = /* @__PURE__ */ new Int32Array(0);
|
|
19
|
+
/**
|
|
20
|
+
* Notes that `values` go up with no gaps, so their order is just
|
|
21
|
+
* 0, 1, 2…: shared, so it costs nothing to make.
|
|
22
|
+
*/
|
|
23
|
+
function inOrder(values) {
|
|
24
|
+
const n = values.length;
|
|
25
|
+
if (identity.length < n) {
|
|
26
|
+
identity = new Int32Array(Math.max(n, identity.length * 2));
|
|
27
|
+
for (let i = 0; i < identity.length; i++) identity[i] = i;
|
|
28
|
+
}
|
|
29
|
+
orders.set(values, identity.subarray(0, n));
|
|
30
|
+
}
|
|
31
|
+
/** The position in `order` of the first value not below `value`. */
|
|
32
|
+
function lowerBound(values, order, value) {
|
|
33
|
+
let lo = 0;
|
|
34
|
+
let hi = order.length;
|
|
35
|
+
while (lo < hi) {
|
|
36
|
+
const mid = lo + hi >> 1;
|
|
37
|
+
if (values[order[mid]] < value) lo = mid + 1;
|
|
38
|
+
else hi = mid;
|
|
39
|
+
}
|
|
40
|
+
return lo;
|
|
41
|
+
}
|
|
42
|
+
/** How far `value` is from the nearest other value of `values`; `Infinity` when there is none. */
|
|
43
|
+
function neighborGap(values, value) {
|
|
44
|
+
const order = sortedOrder(values);
|
|
45
|
+
const at = lowerBound(values, order, value);
|
|
46
|
+
let gap = Number.POSITIVE_INFINITY;
|
|
47
|
+
if (at > 0) gap = value - values[order[at - 1]];
|
|
48
|
+
let next = at;
|
|
49
|
+
while (next < order.length && values[order[next]] <= value) next++;
|
|
50
|
+
if (next < order.length) gap = Math.min(gap, values[order[next]] - value);
|
|
51
|
+
return gap;
|
|
52
|
+
}
|
|
53
|
+
/** The row of `values` whose value is exactly `value`, or -1. */
|
|
54
|
+
function rowAt(values, value) {
|
|
55
|
+
const order = sortedOrder(values);
|
|
56
|
+
const at = lowerBound(values, order, value);
|
|
57
|
+
return at < order.length && values[order[at]] === value ? order[at] : -1;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Of all the x values of `columns`, the one nearest to `pixel` along the
|
|
61
|
+
* x scale; `null` when there are none. Category axes snap to the nearest
|
|
62
|
+
* category.
|
|
63
|
+
*/
|
|
64
|
+
function nearestX(columns, scale, pixel) {
|
|
65
|
+
const target = scale.invert(pixel);
|
|
66
|
+
let best = null;
|
|
67
|
+
let distance = Infinity;
|
|
68
|
+
for (const values of columns) {
|
|
69
|
+
const order = sortedOrder(values);
|
|
70
|
+
if (!order.length) continue;
|
|
71
|
+
const at = lowerBound(values, order, target);
|
|
72
|
+
for (const k of [at - 1, at]) {
|
|
73
|
+
if (k < 0 || k >= order.length) continue;
|
|
74
|
+
const value = values[order[k]];
|
|
75
|
+
const d = Math.abs(scale.map(value) - pixel);
|
|
76
|
+
if (d < distance) [best, distance] = [value, d];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
|
81
|
+
/** The x values of `columns` together, from the smallest, each once. */
|
|
82
|
+
function allX(columns) {
|
|
83
|
+
const seen = /* @__PURE__ */ new Set();
|
|
84
|
+
for (const values of columns) for (const value of values) if (value === value) seen.add(value);
|
|
85
|
+
return [...seen].sort((a, b) => a - b);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The point nearest to `(px, py)` among `n` points placed by `point`,
|
|
89
|
+
* if one is within `reach(i)` px of it. Points of equal distance go to the
|
|
90
|
+
* one drawn last, which is on top.
|
|
91
|
+
*/
|
|
92
|
+
function nearestPoint(n, point, px, py, reach) {
|
|
93
|
+
let index = -1;
|
|
94
|
+
let distance = Infinity;
|
|
95
|
+
for (let i = 0; i < n; i++) {
|
|
96
|
+
const at = point(i);
|
|
97
|
+
if (!at) continue;
|
|
98
|
+
const dx = at[0] - px;
|
|
99
|
+
const dy = at[1] - py;
|
|
100
|
+
const d = Math.sqrt(dx * dx + dy * dy);
|
|
101
|
+
if (d <= reach(i) && d <= distance) [index, distance] = [i, d];
|
|
102
|
+
}
|
|
103
|
+
return index < 0 ? null : {
|
|
104
|
+
index,
|
|
105
|
+
distance
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Angles clockwise from 12 o'clock, as pies use them. */
|
|
109
|
+
function angleAt(cx, cy, px, py) {
|
|
110
|
+
const angle = Math.atan2(px - cx, cy - py);
|
|
111
|
+
return angle < 0 ? angle + Math.PI * 2 : angle;
|
|
112
|
+
}
|
|
113
|
+
export { allX, angleAt, inOrder, nearestPoint, nearestX, neighborGap, rowAt, sortedOrder };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=hit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hit.js","names":[],"sources":["../../src/core/hit.ts"],"sourcesContent":["/*\n * Finding what is under the pointer: the x nearest to it (for a tooltip of\n * every series at one x), or the point nearest to it (for one point).\n */\nimport type { Scale } from './scale'\n\nconst orders = new WeakMap<Float64Array, Int32Array>()\n\n/** The indices of `values` from the smallest to the largest, `NaN` left out. Cached per array. */\nexport function sortedOrder(values: Float64Array): Int32Array {\n let order = orders.get(values)\n if (!order) {\n let n = 0\n for (let i = 0; i < values.length; i++) if (values[i] === values[i]) n++\n order = new Int32Array(n)\n for (let i = 0, j = 0; i < values.length; i++) if (values[i] === values[i]) order[j++] = i\n let sorted = true\n for (let j = 1; j < n && sorted; j++)\n if (values[order[j]!]! < values[order[j - 1]!]!) sorted = false\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts its own array\n if (!sorted) order.sort((a, b) => values[a]! - values[b]!)\n orders.set(values, order)\n }\n return order\n}\n\nlet identity = new Int32Array(0)\n/**\n * Notes that `values` go up with no gaps, so their order is just\n * 0, 1, 2…: shared, so it costs nothing to make.\n */\nexport function inOrder(values: Float64Array) {\n const n = values.length\n if (identity.length < n) {\n identity = new Int32Array(Math.max(n, identity.length * 2))\n for (let i = 0; i < identity.length; i++) identity[i] = i\n }\n orders.set(values, identity.subarray(0, n))\n}\n\n/** The position in `order` of the first value not below `value`. */\nfunction lowerBound(values: Float64Array, order: Int32Array, value: number): number {\n let lo = 0\n let hi = order.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (values[order[mid]!]! < value) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\n/** How far `value` is from the nearest other value of `values`; `Infinity` when there is none. */\nexport function neighborGap(values: Float64Array, value: number): number {\n const order = sortedOrder(values)\n const at = lowerBound(values, order, value)\n let gap = Number.POSITIVE_INFINITY\n if (at > 0) gap = value - values[order[at - 1]!]!\n let next = at\n while (next < order.length && values[order[next]!]! <= value) next++\n if (next < order.length) gap = Math.min(gap, values[order[next]!]! - value)\n return gap\n}\n\n/** The row of `values` whose value is exactly `value`, or -1. */\nexport function rowAt(values: Float64Array, value: number): number {\n const order = sortedOrder(values)\n const at = lowerBound(values, order, value)\n return at < order.length && values[order[at]!] === value ? order[at]! : -1\n}\n\n/**\n * Of all the x values of `columns`, the one nearest to `pixel` along the\n * x scale; `null` when there are none. Category axes snap to the nearest\n * category.\n */\nexport function nearestX(columns: Float64Array[], scale: Scale, pixel: number): number | null {\n const target = scale.invert(pixel)\n let best: number | null = null\n let distance = Infinity\n for (const values of columns) {\n const order = sortedOrder(values)\n if (!order.length) continue\n const at = lowerBound(values, order, target)\n for (const k of [at - 1, at]) {\n if (k < 0 || k >= order.length) continue\n const value = values[order[k]!]!\n const d = Math.abs(scale.map(value) - pixel)\n if (d < distance) [best, distance] = [value, d]\n }\n }\n return best\n}\n\n/** The x values of `columns` together, from the smallest, each once. */\nexport function allX(columns: Float64Array[]): number[] {\n const seen = new Set<number>()\n for (const values of columns) for (const value of values) if (value === value) seen.add(value)\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts its own array\n return [...seen].sort((a, b) => a - b)\n}\n\n/**\n * The point nearest to `(px, py)` among `n` points placed by `point`,\n * if one is within `reach(i)` px of it. Points of equal distance go to the\n * one drawn last, which is on top.\n */\nexport function nearestPoint(\n n: number,\n point: (i: number) => [number, number] | null,\n px: number,\n py: number,\n reach: (i: number) => number,\n): { index: number; distance: number } | null {\n let index = -1\n let distance = Infinity\n for (let i = 0; i < n; i++) {\n const at = point(i)\n if (!at) continue\n const dx = at[0] - px\n const dy = at[1] - py\n const d = Math.sqrt(dx * dx + dy * dy)\n if (d <= reach(i) && d <= distance) [index, distance] = [i, d]\n }\n return index < 0 ? null : { index, distance }\n}\n\n/** Angles clockwise from 12 o'clock, as pies use them. */\nexport function angleAt(cx: number, cy: number, px: number, py: number): number {\n const angle = Math.atan2(px - cx, cy - py)\n return angle < 0 ? angle + Math.PI * 2 : angle\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** Room between a label and its point, or the edge of its bar. */
|
|
2
|
+
var GAP = 4;
|
|
3
|
+
var overlaps = (a, b) => a[0] < b[2] && b[0] < a[2] && a[1] < b[3] && b[1] < a[3];
|
|
4
|
+
/**
|
|
5
|
+
* Places labels in the order given; one that covers a label placed before
|
|
6
|
+
* it (or one of `taken`), or doesn't fit in `bounds` (or in its bar), is
|
|
7
|
+
* left out.
|
|
8
|
+
*/
|
|
9
|
+
function placeDataLabels(inputs, bounds, measure, taken = []) {
|
|
10
|
+
const out = [];
|
|
11
|
+
const right = bounds.x + bounds.width;
|
|
12
|
+
const bottom = bounds.y + bounds.height;
|
|
13
|
+
for (const input of inputs) {
|
|
14
|
+
const { anchor, text } = input;
|
|
15
|
+
const width = measure(text);
|
|
16
|
+
const [x, y] = anchor.at;
|
|
17
|
+
const gap = GAP + (input.offset ?? 0);
|
|
18
|
+
let box;
|
|
19
|
+
let align;
|
|
20
|
+
switch (anchor.side) {
|
|
21
|
+
case "top":
|
|
22
|
+
box = [
|
|
23
|
+
x - width / 2,
|
|
24
|
+
y - gap - 16,
|
|
25
|
+
x + width / 2,
|
|
26
|
+
y - gap
|
|
27
|
+
];
|
|
28
|
+
align = "middle";
|
|
29
|
+
break;
|
|
30
|
+
case "bottom":
|
|
31
|
+
box = [
|
|
32
|
+
x - width / 2,
|
|
33
|
+
y + gap,
|
|
34
|
+
x + width / 2,
|
|
35
|
+
y + gap + 16
|
|
36
|
+
];
|
|
37
|
+
align = "middle";
|
|
38
|
+
break;
|
|
39
|
+
case "right":
|
|
40
|
+
box = [
|
|
41
|
+
x + gap,
|
|
42
|
+
y - 8,
|
|
43
|
+
x + gap + width,
|
|
44
|
+
y + 8
|
|
45
|
+
];
|
|
46
|
+
align = "start";
|
|
47
|
+
break;
|
|
48
|
+
case "left":
|
|
49
|
+
box = [
|
|
50
|
+
x - gap - width,
|
|
51
|
+
y - 8,
|
|
52
|
+
x - gap,
|
|
53
|
+
y + 8
|
|
54
|
+
];
|
|
55
|
+
align = "end";
|
|
56
|
+
break;
|
|
57
|
+
default: {
|
|
58
|
+
box = [
|
|
59
|
+
x - width / 2,
|
|
60
|
+
y - 8,
|
|
61
|
+
x + width / 2,
|
|
62
|
+
y + 8
|
|
63
|
+
];
|
|
64
|
+
align = "middle";
|
|
65
|
+
const shape = anchor.box;
|
|
66
|
+
if (shape && (width + 8 > shape.width + .5 || 20 > shape.height + .5)) continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const room = anchor.room;
|
|
70
|
+
if (room !== void 0) {
|
|
71
|
+
if ((anchor.side === "top" || anchor.side === "bottom" ? width : 16) > room + .5) continue;
|
|
72
|
+
}
|
|
73
|
+
if (box[0] < bounds.x - .5 || box[2] > right + .5) continue;
|
|
74
|
+
if (box[1] < bounds.y - .5 || box[3] > bottom + .5) continue;
|
|
75
|
+
if (taken.some((other) => overlaps(box, other))) continue;
|
|
76
|
+
taken.push(box);
|
|
77
|
+
out.push({
|
|
78
|
+
key: input.key,
|
|
79
|
+
series: input.series,
|
|
80
|
+
text,
|
|
81
|
+
left: align === "start" ? box[0] : align === "end" ? box[2] : x,
|
|
82
|
+
top: box[1],
|
|
83
|
+
align,
|
|
84
|
+
on: anchor.side === "center" ? anchor.box?.color : void 0
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Moves boxes of `height` centered at `centers` apart along one line so
|
|
91
|
+
* none overlaps the next, keeping each as near its own center as it can
|
|
92
|
+
* and all within `[from, to]`. Gives the new centers, in the same order.
|
|
93
|
+
*/
|
|
94
|
+
function spread(centers, height, from, to) {
|
|
95
|
+
const order = centers.map((_, i) => i);
|
|
96
|
+
order.sort((a, b) => centers[a] - centers[b]);
|
|
97
|
+
const placed = order.map((i) => centers[i]);
|
|
98
|
+
const half = height / 2;
|
|
99
|
+
for (let k = 0; k < placed.length; k++) {
|
|
100
|
+
const least = k === 0 ? from + half : placed[k - 1] + height;
|
|
101
|
+
if (placed[k] < least) placed[k] = least;
|
|
102
|
+
}
|
|
103
|
+
for (let k = placed.length - 1; k >= 0; k--) {
|
|
104
|
+
const most = k === placed.length - 1 ? to - half : placed[k + 1] - height;
|
|
105
|
+
if (placed[k] > most) placed[k] = most;
|
|
106
|
+
}
|
|
107
|
+
const out = Array.from({ length: centers.length });
|
|
108
|
+
order.forEach((i, k) => out[i] = placed[k]);
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** Relative luminance of an `rgb()` / `rgba()` color (as the browser gives computed colors), 0 to 1. */
|
|
112
|
+
function luminance(color) {
|
|
113
|
+
const m = /rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/.exec(color);
|
|
114
|
+
if (!m) {
|
|
115
|
+
const hex = /^#([\da-f]{6})$/i.exec(color);
|
|
116
|
+
if (!hex) return null;
|
|
117
|
+
const n = Number.parseInt(hex[1], 16);
|
|
118
|
+
return relative([
|
|
119
|
+
n >> 16 & 255,
|
|
120
|
+
n >> 8 & 255,
|
|
121
|
+
n & 255
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
124
|
+
return relative([
|
|
125
|
+
Number(m[1]),
|
|
126
|
+
Number(m[2]),
|
|
127
|
+
Number(m[3])
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
function relative(rgb) {
|
|
131
|
+
const [r, g, b] = rgb.map((c) => {
|
|
132
|
+
const v = c / 255;
|
|
133
|
+
return v <= .03928 ? v / 12.92 : ((v + .055) / 1.055) ** 2.4;
|
|
134
|
+
});
|
|
135
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
136
|
+
}
|
|
137
|
+
/** Contrast ratio between two luminances. */
|
|
138
|
+
var contrast = (a, b) => (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
|
|
139
|
+
export { contrast, luminance, placeDataLabels, spread };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","names":[],"sources":["../../src/core/labels.ts"],"sourcesContent":["import type { Rect } from './painter'\nimport type { ChartLabelAnchor } from './series'\n\n/*\n * Data labels: text by a point or in a bar. The series say where each\n * label may go; here the text is placed beside that point, and labels\n * that would cover one placed before them, or run off the room they\n * have, are left out. Lines' labels at their end are moved apart instead,\n * so each line keeps its name.\n */\n\n/** Height of a label's box, as tick labels. */\nexport const DATA_LABEL = 16\n/** Room between a label and its point, or the edge of its bar. */\nconst GAP = 4\n/** Room around a label's text inside a bar. */\nconst PAD = 4\n\nexport interface DataLabelInput {\n key: string\n /** The series' index. */\n series: number\n text: string\n anchor: ChartLabelAnchor\n /** Room from the point, past a dot or a line. */\n offset?: number\n}\n\nexport interface PlacedDataLabel {\n key: string\n series: number\n text: string\n /** The box's top left, in px from the chart's top left. */\n left: number\n top: number\n /** Which end of the text `left` is. */\n align: 'start' | 'middle' | 'end'\n /** In a bar: the color of the bar, for text that reads on it. */\n on?: string\n}\n\ntype Box = [left: number, top: number, right: number, bottom: number]\n\nconst overlaps = (a: Box, b: Box) => a[0] < b[2] && b[0] < a[2] && a[1] < b[3] && b[1] < a[3]\n\n/**\n * Places labels in the order given; one that covers a label placed before\n * it (or one of `taken`), or doesn't fit in `bounds` (or in its bar), is\n * left out.\n */\nexport function placeDataLabels(\n inputs: DataLabelInput[],\n bounds: Rect,\n measure: (text: string) => number,\n /** Labels already there that these must not cover (the ends of lines, say). */\n taken: Box[] = [],\n): PlacedDataLabel[] {\n const out: PlacedDataLabel[] = []\n const right = bounds.x + bounds.width\n const bottom = bounds.y + bounds.height\n for (const input of inputs) {\n const { anchor, text } = input\n const width = measure(text)\n const [x, y] = anchor.at\n const gap = GAP + (input.offset ?? 0)\n let box: Box\n let align: PlacedDataLabel['align']\n switch (anchor.side) {\n case 'top':\n box = [x - width / 2, y - gap - DATA_LABEL, x + width / 2, y - gap]\n align = 'middle'\n break\n case 'bottom':\n box = [x - width / 2, y + gap, x + width / 2, y + gap + DATA_LABEL]\n align = 'middle'\n break\n case 'right':\n box = [x + gap, y - DATA_LABEL / 2, x + gap + width, y + DATA_LABEL / 2]\n align = 'start'\n break\n case 'left':\n box = [x - gap - width, y - DATA_LABEL / 2, x - gap, y + DATA_LABEL / 2]\n align = 'end'\n break\n default: {\n box = [x - width / 2, y - DATA_LABEL / 2, x + width / 2, y + DATA_LABEL / 2]\n align = 'middle'\n const shape = anchor.box\n // inside a bar: with room around it, or not at all\n if (shape && (width + PAD * 2 > shape.width + 0.5 || DATA_LABEL + PAD > shape.height + 0.5))\n continue\n }\n }\n const room = anchor.room\n if (room !== undefined) {\n const across = anchor.side === 'top' || anchor.side === 'bottom' ? width : DATA_LABEL\n if (across > room + 0.5) continue\n }\n if (box[0] < bounds.x - 0.5 || box[2] > right + 0.5) continue\n if (box[1] < bounds.y - 0.5 || box[3] > bottom + 0.5) continue\n if (taken.some((other) => overlaps(box, other))) continue\n taken.push(box)\n out.push({\n key: input.key,\n series: input.series,\n text,\n left: align === 'start' ? box[0] : align === 'end' ? box[2] : x,\n top: box[1],\n align,\n on: anchor.side === 'center' ? anchor.box?.color : undefined,\n })\n }\n return out\n}\n\n/**\n * Moves boxes of `height` centered at `centers` apart along one line so\n * none overlaps the next, keeping each as near its own center as it can\n * and all within `[from, to]`. Gives the new centers, in the same order.\n */\nexport function spread(centers: number[], height: number, from: number, to: number): number[] {\n const order = centers.map((_, i) => i)\n order.sort((a, b) => centers[a]! - centers[b]!)\n const placed = order.map((i) => centers[i]!)\n const half = height / 2\n // down, keeping each clear of the one above\n for (let k = 0; k < placed.length; k++) {\n const least = k === 0 ? from + half : placed[k - 1]! + height\n if (placed[k]! < least) placed[k] = least\n }\n // then up from the end, where the last ran past it\n for (let k = placed.length - 1; k >= 0; k--) {\n const most = k === placed.length - 1 ? to - half : placed[k + 1]! - height\n if (placed[k]! > most) placed[k] = most\n }\n const out: number[] = Array.from({ length: centers.length })\n order.forEach((i, k) => (out[i] = placed[k]!))\n return out\n}\n\n/** Relative luminance of an `rgb()` / `rgba()` color (as the browser gives computed colors), 0 to 1. */\nexport function luminance(color: string): number | null {\n const m = /rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)/.exec(color)\n if (!m) {\n const hex = /^#([\\da-f]{6})$/i.exec(color)\n if (!hex) return null\n const n = Number.parseInt(hex[1]!, 16)\n return relative([(n >> 16) & 255, (n >> 8) & 255, n & 255])\n }\n return relative([Number(m[1]), Number(m[2]), Number(m[3])])\n}\n\nfunction relative(rgb: number[]): number {\n const [r, g, b] = rgb.map((c) => {\n const v = c / 255\n return v <= 0.039_28 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4\n })\n return 0.2126 * r! + 0.7152 * g! + 0.0722 * b!\n}\n\n/** Contrast ratio between two luminances. */\nexport const contrast = (a: number, b: number) => (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05)\n"],"mappings":"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"}
|