├── .gitignore
├── README.md
├── config.json
├── dist
├── apps
│ ├── BarChart.css
│ ├── BarChart.js
│ ├── BarChart.js.map
│ ├── Chart.css
│ ├── Chart.js
│ ├── Chart.js.map
│ ├── ColumnChart.css
│ ├── ColumnChart.js
│ ├── ColumnChart.js.map
│ ├── DotPlotChart.css
│ ├── DotPlotChart.js
│ ├── DotPlotChart.js.map
│ ├── LineChart.css
│ ├── LineChart.js
│ ├── LineChart.js.map
│ ├── ScatterChart.css
│ ├── ScatterChart.js
│ └── ScatterChart.js.map
├── favicon.png
├── global.css
└── index.html
├── index.mjs
├── package-lock.json
├── package.json
├── rollup.config.build.js
├── rollup.config.dev.js
├── rollup.config.module.js
└── src
├── App.svelte
├── apps
├── BarChart.js
├── Chart.js
├── ColumnChart.js
├── DotPlotChart.js
├── LineChart.js
└── ScatterChart.js
├── charts
├── BarChart.svelte
├── Chart.svelte
├── ColumnChart.svelte
├── DotPlotChart.svelte
├── LineChart.svelte
├── MarkerChart.svelte
├── ScatterChart.svelte
└── shared
│ ├── Annotations.svelte
│ ├── Area.svelte
│ ├── ArrowheadDef.svelte
│ ├── Arrows.svelte
│ ├── AxisRadial.svelte
│ ├── AxisX.html.svelte
│ ├── AxisX.svelte
│ ├── AxisY.html.svelte
│ ├── AxisY.svelte
│ ├── Bar.svelte
│ ├── Beeswarm.html.svelte
│ ├── Beeswarm.svelte
│ ├── BeeswarmForce.html.svelte
│ ├── BeeswarmForce.svelte
│ ├── Brush.svelte
│ ├── CalendarMonth.svelte
│ ├── CirclePack.html.svelte
│ ├── CirclePackForce.svelte
│ ├── Column.svelte
│ ├── ColumnLinear.svelte
│ ├── DotPlot.html.svelte
│ ├── DotPlot.svelte
│ ├── Export.svelte
│ ├── Footer.svelte
│ ├── ForceDirectedGraph.svelte
│ ├── Key.svelte
│ ├── Labels-html.svelte
│ ├── Labels.svelte
│ ├── Legend.svelte
│ ├── Line.svelte
│ ├── Map.canvas.svelte
│ ├── Map.svg.svelte
│ ├── MapPoints.svelte
│ ├── MultiLine.svelte
│ ├── QuadTree.percent-range.svelte
│ ├── QuadTree.svelte
│ ├── Radar.svelte
│ ├── Sankey.svelte
│ ├── Scatter.canvas.svelte
│ ├── Scatter.html.svelte
│ ├── Scatter.svg.svelte
│ ├── Scatter.webgl.svelte
│ ├── SetCoords.svelte
│ ├── SharedTooltip.percent-range.svelte
│ ├── SharedTooltip.svelte
│ ├── SmallMultipleWrapper.percent-range.svelte
│ ├── SmallMultipleWrapper.svelte
│ ├── Stack.svelte
│ ├── Subtitle.svelte
│ ├── SyncedBrushWrapper.percent-range.svelte
│ ├── SyncedBrushWrapper.svelte
│ ├── Table.svelte
│ ├── Title.svelte
│ ├── Tooltip.svelte
│ ├── Voronoi.svelte
│ └── ss
│ ├── AreaStacked.svelte
│ ├── BarStacked.svelte
│ ├── ColumnStacked.svelte
│ └── LineStacked.svelte
├── data
├── data-scatter.js
├── data.js
└── us-states.topojson.json
├── js
├── accurate-beeswarm.js
├── spread-labels.js
├── utils.js
└── wrap.js
└── main.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /dist/build/
3 |
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @onsvisual/svelte-charts
2 |
3 | [](https://www.npmjs.com/package/@onsvisual/svelte-charts)
4 |
5 | Reusable chart templates for Svelte projects.
6 |
7 | Usage examples for these charts can be found on the [ONS svelte-components Storybook pages](https://onsvisual.github.io/svelte-components/):
8 |
9 | - [BarChart](https://onsvisual.github.io/svelte-components/?path=/docs/data-visualisation-barchart--docs)
10 | - [ColumnChart](https://onsvisual.github.io/svelte-components/?path=/docs/data-visualisation-columnchart--docs)
11 | - [DotPlotChart](https://onsvisual.github.io/svelte-components/?path=/docs/data-visualisation-dotplotchart--docs)
12 | - [LineChart](https://onsvisual.github.io/svelte-components/?path=/docs/data-visualisation-linechart--docs)
13 | - [ScatterChart](https://onsvisual.github.io/svelte-components/?path=/docs/data-visualisation-scatterchart--docs) (includes beeswarm)
14 |
15 | Further examples with interactions can be found in the **/src/App.svelte** file in this repo, which can be [previewed live here](https://onsvisual.github.io/svelte-charts/).
16 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "hydrate": false
3 | }
4 |
--------------------------------------------------------------------------------
/dist/apps/BarChart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.bar-group.svelte-1kkdyuo polygon.svelte-1kkdyuo,.line-group.svelte-1kkdyuo polygon.svelte-1kkdyuo{shape-rendering:crispEdges}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}
--------------------------------------------------------------------------------
/dist/apps/Chart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}.bar-group.svelte-1kkdyuo polygon.svelte-1kkdyuo,.line-group.svelte-1kkdyuo polygon.svelte-1kkdyuo{shape-rendering:crispEdges}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.column-group.svelte-maq6yn polygon.svelte-maq6yn,.line-group.svelte-maq6yn polygon.svelte-maq6yn{shape-rendering:crispEdges}.voronoi-cell.svelte-169satm{fill:none;stroke:none;pointer-events:all}.chart-label.svelte-dqkttw{font-size:0.8em}path.svelte-rh3b33{fill:none;stroke-linejoin:round;stroke-linecap:round}.path-hover.svelte-rh3b33{stroke:rgba(255,255,255,0);stroke-width:7}.path-line.svelte-rh3b33,.path-overlay.svelte-rh3b33{pointer-events:none}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}
--------------------------------------------------------------------------------
/dist/apps/ColumnChart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}.column-group.svelte-maq6yn polygon.svelte-maq6yn,.line-group.svelte-maq6yn polygon.svelte-maq6yn{shape-rendering:crispEdges}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}
--------------------------------------------------------------------------------
/dist/apps/DotPlotChart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}
--------------------------------------------------------------------------------
/dist/apps/LineChart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}path.svelte-rh3b33{fill:none;stroke-linejoin:round;stroke-linecap:round}.path-hover.svelte-rh3b33{stroke:rgba(255,255,255,0);stroke-width:7}.path-line.svelte-rh3b33,.path-overlay.svelte-rh3b33{pointer-events:none}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-label.svelte-dqkttw{font-size:0.8em}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}
--------------------------------------------------------------------------------
/dist/apps/ScatterChart.css:
--------------------------------------------------------------------------------
1 | .chart-container.svelte-1fy6g2i{width:100%}.visuallyhidden.svelte-1fy6g2i{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.tick.svelte-1b8cddl.svelte-1b8cddl{font-size:.8em}.tick.svelte-1b8cddl .tick-mark.svelte-1b8cddl,.tick.tick-0.svelte-1b8cddl line.svelte-1b8cddl{stroke-dasharray:0}.tick.svelte-1b8cddl line.svelte-1b8cddl{shape-rendering:crispEdges}.dashed.svelte-1b8cddl.svelte-1b8cddl{stroke-dasharray:2}.axis.snapTicks.svelte-1b8cddl .tick:last-child text.svelte-1b8cddl{transform:translateX(3px)}.axis.snapTicks.svelte-1b8cddl .tick.tick-0 text.svelte-1b8cddl{transform:translateX(-3px)}ul.legend.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{margin:0;padding:0}ul.legend.svelte-nqsavd li.svelte-nqsavd.svelte-nqsavd{display:inline;font-size:.8em}ul.legend.svelte-nqsavd li.svelte-nqsavd+li.svelte-nqsavd{margin-left:8px}.bullet.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{display:inline-block;vertical-align:middle;transform:translateY(-1px)}.round.svelte-nqsavd.svelte-nqsavd.svelte-nqsavd{border-radius:50%}.chart-title.svelte-pvs6ms{font-size:1.1em;font-weight:bold;margin-bottom:10px}.tick.svelte-f7wn4m.svelte-f7wn4m{font-size:.8em}.dashed.svelte-f7wn4m.svelte-f7wn4m{stroke-dasharray:2}.tick.tick-0.svelte-f7wn4m line.svelte-f7wn4m{stroke-dasharray:0}.chart-subtitle.svelte-1clt1zg{margin-top:-6px;margin-bottom:10px}.voronoi-cell.svelte-169satm{fill:none;stroke:none;pointer-events:all}.chart-footer.svelte-16332wo{font-size:.8em;color:grey;margin-top:5px}.chart-label.svelte-dqkttw{font-size:0.8em}.chart-export.svelte-1no2d6c{margin-top:10px;font-size:.8em}button.svelte-1no2d6c{color:#206095;text-decoration:underline;text-underline-position:under;background:none;border:none;padding:0 0 1px}button.svelte-1no2d6c:hover{cursor:pointer;color:#003c57;text-decoration-thickness:2px}button.svelte-1no2d6c:focus{color:#222;background-color:#fbc900;text-decoration-thickness:3px}.layercake-container.svelte-vhzpsp,.layercake-container.svelte-vhzpsp *{box-sizing:border-box}.layercake-container.svelte-vhzpsp{width:100%;height:100%}div.svelte-1bu60uu,slot.svelte-1bu60uu{position:absolute;top:0;left:0}svg.svelte-u84d8d{position:absolute;top:0;left:0;overflow:visible}svg.svelte-6sm8ei{position:absolute;width:100%;height:100%;overflow:visible}svg.svelte-6sm8ei *{vector-effect:non-scaling-stroke}
--------------------------------------------------------------------------------
/dist/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ONSvisual/svelte-charts/9c609ba71f9668acd76e70b78c9d7b87ef6d6d3b/dist/favicon.png
--------------------------------------------------------------------------------
/dist/global.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | color: #333;
9 | margin: 0;
10 | padding: 8px;
11 | box-sizing: border-box;
12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
13 | }
14 |
15 | a {
16 | color: rgb(0,100,200);
17 | text-decoration: none;
18 | }
19 |
20 | a:hover {
21 | text-decoration: underline;
22 | }
23 |
24 | a:visited {
25 | color: rgb(0,80,160);
26 | }
27 |
28 | label {
29 | display: block;
30 | }
31 |
32 | input, button, select, textarea {
33 | font-family: inherit;
34 | font-size: inherit;
35 | padding: 0.4em;
36 | margin: 0 0 0.5em 0;
37 | box-sizing: border-box;
38 | border: 1px solid #ccc;
39 | border-radius: 2px;
40 | }
41 |
42 | input:disabled {
43 | color: #ccc;
44 | }
45 |
46 | button {
47 | color: #333;
48 | background-color: #f4f4f4;
49 | outline: none;
50 | }
51 |
52 | button:disabled {
53 | color: #999;
54 | }
55 |
56 | button:not(:disabled):active {
57 | background-color: #ddd;
58 | }
59 |
60 | button:focus {
61 | border-color: #666;
62 | }
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ONS Svelte Charts Library
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/index.mjs:
--------------------------------------------------------------------------------
1 | // CHARTS
2 | export { default as Chart } from './src/charts/Chart.svelte';
3 | export { default as LineChart } from './src/charts/LineChart.svelte';
4 | export { default as BarChart } from './src/charts/BarChart.svelte';
5 | export { default as ColumnChart } from './src/charts/ColumnChart.svelte';
6 | export { default as ScatterChart } from './src/charts/ScatterChart.svelte';
7 | export { default as DotPlotChart } from './src/charts/DotPlotChart.svelte';
8 |
9 | // SHARED COMPONENTS
10 | // export { default as Annotations } from './src/charts/shared/Annotations.svelte';
11 | export { default as Area } from './src/charts/shared/Area.svelte';
12 | // export { default as ArrowheadDef } from './src/charts/shared/ArrowheadDef.svelte';
13 | // export { default as Arrows } from './src/charts/shared/Arrows.svelte';
14 | // export { default as AxisRadial } from './src/charts/shared/AxisRadial.svelte';
15 | export { default as AxisX } from './src/charts/shared/AxisX.svelte';
16 | // export { default as AxisX_html } from './src/charts/shared/AxisX.html.svelte';
17 | export { default as AxisY } from './src/charts/shared/AxisY.svelte';
18 | // export { default as AxisY_html } from './src/charts/shared/AxisY.html.svelte';
19 | export { default as Bar } from './src/charts/shared/Bar.svelte';
20 | // export { default as Beeswarm } from './src/charts/shared/Beeswarm.svelte';
21 | // export { default as Beeswarm_html } from './src/charts/shared/Beeswarm.html.svelte';
22 | // export { default as BeeswarmForce } from './src/charts/shared/BeeswarmForce.svelte';
23 | // export { default as BeeswarmForce_html } from './src/charts/shared/BeeswarmForce.html.svelte';
24 | // export { default as Brush } from './src/charts/shared/Brush.svelte';
25 | // export { default as CalendarMonth } from './src/charts/shared/CalendarMonth.svelte';
26 | // export { default as CirclePack_html } from './src/charts/shared/CirclePack.html.svelte';
27 | // export { default as CirclePackForce } from './src/charts/shared/CirclePackForce.svelte';
28 | export { default as DotPlot } from './src/charts/shared/DotPlot.svelte';
29 | // export { default as DotPlot_html } from './src/charts/shared/DotPlot.html.svelte';
30 | export { default as Column } from './src/charts/shared/Column.svelte';
31 | // export { default as ColumnLinear } from './src/charts/shared/ColumnLinear.svelte';
32 | export { default as Footer } from './src/charts/shared/Footer.svelte';
33 | // export { default as ForceDirectedGraph } from './src/charts/shared/ForceDirectedGraph.svelte';
34 | // export { default as Key } from './src/charts/shared/Key.svelte';
35 | // export { default as Labels } from './src/charts/shared/Labels.svelte';
36 | export { default as Legend } from './src/charts/shared/Legend.svelte';
37 | export { default as Line } from './src/charts/shared/Line.svelte';
38 | // export { default as Map_canvas } from './src/charts/shared/Map.canvas.svelte';
39 | // export { default as Map_svg } from './src/charts/shared/Map.svg.svelte';
40 | // export { default as MapPoints } from './src/charts/shared/MapPoints.svelte';
41 | // export { default as MultiLine } from './src/charts/shared/MultiLine.svelte';
42 | // export { default as QuadTree } from './src/charts/shared/QuadTree.svelte';
43 | // export { default as QuadTree_perc } from './src/charts/shared/QuadTree.percent_range.svelte';
44 | // export { default as Radar } from './src/charts/shared/Radar.svelte';
45 | // export { default as Sankey } from './src/charts/shared/Sankey.svelte';
46 | export { default as Scatter } from './src/charts/shared/Scatter.svg.svelte';
47 | // export { default as Scatter_canvas } from './src/charts/shared/Scatter.canvas.svelte';
48 | // export { default as Scatter_html } from './src/charts/shared/Scatter.html.svelte';
49 | // export { default as Scatter_gl } from './src/charts/shared/Scatter.webgl.svelte';
50 | // export { default as SharedTooltip } from './src/charts/shared/SharedTooltip.svelte';
51 | // export { default as SharedTooltip_perc } from './src/charts/shared/SharedTooltip.percent-range.svelte';
52 | // export { default as SmallMultipleWrapper } from './src/charts/shared/SmallMultipleWrapper.svelte';
53 | // export { default as SmallMultipleWrapper_perc } from './src/charts/shared/SmallMultipleWrapper.percent-range.svelte';
54 | // export { default as SyncedBrushWrapper } from './src/charts/shared/SyncedBrushWrapper.svelte';
55 | // export { default as SyncedBrushWrapper_perc } from './src/charts/shared/SyncedBrushWrapper.percent-range.svelte';
56 | // export { default as Tooltip } from './src/charts/shared/Tooltip.svelte';
57 | export { default as Title } from './src/charts/shared/Title.svelte';
58 | export { default as Voronoi } from './src/charts/shared/Voronoi.svelte';
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@onsvisual/svelte-charts",
3 | "version": "0.3.19",
4 | "description": "Reusable chart templates for Svelte projects.",
5 | "homepage": "http://onsvisual.github.io/svelte-charts",
6 | "module": "index.mjs",
7 | "svelte": "index.mjs",
8 | "files": [
9 | "index.mjs",
10 | "src",
11 | "dist"
12 | ],
13 | "scripts": {
14 | "build": "rollup -c rollup.config.build.js",
15 | "dev": "rollup -c rollup.config.dev.js -w",
16 | "start": "sirv dist",
17 | "test": "echo \"No test specified\"",
18 | "deploy": "gh-pages -d dist"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+ssh://git@github.com/onsvisual/svelte-charts.git"
23 | },
24 | "keywords": [
25 | "svelte",
26 | "charts",
27 | "layercake",
28 | "dataviz",
29 | "svg"
30 | ],
31 | "author": "Ahmad Barclay",
32 | "license": "MIT",
33 | "bugs": {
34 | "url": "https://github.com/onsvisual/svelte-charts/issues"
35 | },
36 | "devDependencies": {
37 | "@rollup/plugin-commonjs": "^11.0.0",
38 | "@rollup/plugin-dsv": "^2.0.0",
39 | "@rollup/plugin-json": "^4.1.0",
40 | "@rollup/plugin-node-resolve": "^15.0.1",
41 | "debounce": "^1.2.1",
42 | "gh-pages": "^6.2.0",
43 | "rollup": "^2.38.5",
44 | "rollup-plugin-css-only": "^3.1.0",
45 | "rollup-plugin-execute": "^1.1.1",
46 | "rollup-plugin-livereload": "^2.0.0",
47 | "rollup-plugin-svelte": "^7.1.0",
48 | "rollup-plugin-terser": "^7.0.2",
49 | "sirv-cli": "^1.0.0"
50 | },
51 | "peerDependencies": {
52 | "d3-delaunay": "^6.0.2",
53 | "d3-dsv": "latest",
54 | "d3-quadtree": "latest",
55 | "d3-scale": "^4.0.2",
56 | "d3-time-format": "^4.1.0",
57 | "html2canvas": "^1.3.3",
58 | "layercake": "^7.6.1",
59 | "regl": "latest",
60 | "regl-tween": "latest",
61 | "svelte": "3 - 4"
62 | },
63 | "main": "index.mjs",
64 | "directories": {
65 | "test": "test"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/rollup.config.build.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import commonjs from '@rollup/plugin-commonjs';
4 | import dsv from '@rollup/plugin-dsv';
5 | import { terser } from 'rollup-plugin-terser';
6 | import json from "@rollup/plugin-json";
7 | import css from 'rollup-plugin-css-only';
8 |
9 | // List of modules to compile (must match .js filenames in src, eg. LineChart.js => LineChart)
10 | const modules = ['Chart', 'LineChart', 'BarChart', 'ColumnChart', 'ScatterChart', 'DotPlotChart'];
11 |
12 | export default [
13 | ...modules.map(module => {
14 | return {
15 | input: `src/apps/${module}.js`,
16 | output: {
17 | sourcemap: true,
18 | format: 'iife',
19 | name: `${module}`,
20 | file: `dist/apps/${module}.js`
21 | },
22 | plugins: [
23 | svelte({
24 | compilerOptions: {
25 | dev: false,
26 | hydratable: false
27 | }
28 | }),
29 | css({ output: `${module}.css` }),
30 |
31 | // If you have external dependencies installed from
32 | // npm, you'll most likely need these plugins. In
33 | // some cases you'll need additional configuration -
34 | // consult the documentation for details:
35 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
36 | resolve({
37 | browser: true,
38 | dedupe: ['svelte']
39 | }),
40 | commonjs(),
41 |
42 | terser()
43 | ],
44 | watch: {
45 | clearScreen: false
46 | }
47 | }
48 | }),
49 | {
50 | input: 'src/main.js',
51 | output: {
52 | sourcemap: true,
53 | format: 'iife',
54 | name: 'app',
55 | file: 'dist/build/bundle.js'
56 | },
57 | plugins: [
58 | // Allow for importing csv files as modules
59 | dsv(),
60 | // And importing json files
61 | json(),
62 |
63 | svelte({
64 | compilerOptions: {
65 | dev: false,
66 | hydratable: false
67 | }
68 | }),
69 | // we'll extract any component CSS out into
70 | // a separate file - better for performance
71 | css({ output: 'bundle.css' }),
72 |
73 | // If you have external dependencies installed from
74 | // npm, you'll most likely need these plugins. In
75 | // some cases you'll need additional configuration —
76 | // consult the documentation for details:
77 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
78 | resolve({
79 | browser: true,
80 | dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
81 | }),
82 | commonjs(),
83 |
84 | terser()
85 |
86 | ],
87 | watch: {
88 | clearScreen: false
89 | }
90 | }
91 | ];
--------------------------------------------------------------------------------
/rollup.config.dev.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import commonjs from '@rollup/plugin-commonjs';
4 | import dsv from '@rollup/plugin-dsv';
5 | import livereload from 'rollup-plugin-livereload';
6 | import execute from "rollup-plugin-execute";
7 | import json from "@rollup/plugin-json";
8 | import css from 'rollup-plugin-css-only';
9 |
10 | export default {
11 | input: 'src/main.js',
12 | output: {
13 | sourcemap: true,
14 | format: 'iife',
15 | name: 'app',
16 | file: 'dist/build/bundle.js'
17 | },
18 | plugins: [
19 | // Allow for importing csv files as modules
20 | dsv(),
21 | // And importing json files
22 | json(),
23 |
24 | svelte({
25 | // enable run-time checks when not in production
26 | compilerOptions: {
27 | dev: true,
28 | hydratable: false
29 | }
30 | }),
31 | // we'll extract any component CSS out into
32 | // a separate file - better for performance
33 | css({ output: 'bundle.css' }),
34 |
35 | // If you have external dependencies installed from
36 | // npm, you'll most likely need these plugins. In
37 | // some cases you'll need additional configuration —
38 | // consult the documentation for details:
39 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
40 | resolve({
41 | browser: true,
42 | dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
43 | }),
44 | commonjs(),
45 |
46 | // In dev mode, call `npm run start` once
47 | // the bundle has been generated
48 | serve(),
49 |
50 | // Watch the `public` directory and refresh the
51 | // browser on changes when not in production
52 | livereload('dist'),
53 | ],
54 | watch: {
55 | clearScreen: false
56 | }
57 | };
58 |
59 | function serve() {
60 | let started = false;
61 |
62 | return {
63 | writeBundle() {
64 | if (!started) {
65 | started = true;
66 |
67 | require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
68 | stdio: ['ignore', 'inherit', 'inherit'],
69 | shell: true
70 | });
71 | }
72 | }
73 | };
74 | }
75 |
--------------------------------------------------------------------------------
/rollup.config.module.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import pkg from './package.json';
4 |
5 | const name = pkg.name
6 | .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
7 | .replace(/^\w/, m => m.toUpperCase())
8 | .replace(/-\w/g, m => m[1].toUpperCase());
9 |
10 | export default {
11 | input: './index.mjs',
12 | output: [
13 | { file: pkg.module, 'format': 'es' },
14 | { file: pkg.main, 'format': 'umd', name }
15 | ],
16 | plugins: [
17 | svelte(),
18 | resolve()
19 | ]
20 | };
--------------------------------------------------------------------------------
/src/App.svelte:
--------------------------------------------------------------------------------
1 |
47 |
48 |
64 |
65 |
66 |
67 |
68 |
d.group == barchart1.selected)}
70 | xKey="value" yKey="year"
71 | title="Single variable bar chart"
72 | footer="Source: Fictitious data about fruit, 2020."
73 | {hover} {hovered} on:hover={doHover}
74 | {select} {selected} on:select={doSelect}
75 | {animation}>
76 |
77 | {#each barchart1.options as option}
78 | {option}
79 | {/each}
80 |
81 |
82 |
83 |
84 |
92 |
93 | {#each barchart2.options as option}
94 | {option}
95 | {/each}
96 |
97 |
98 |
99 |
100 | d.year == 2020)} xKey="value" yKey="group" zKey="group" title="Coloured bar chart with export options" output={{csv: true, png: true}}/>
101 |
102 |
103 |
d.group == barchart1.selected)}
105 | xKey="year" yKey="value"
106 | title="Single variable column chart"
107 | {hover} {hovered} on:hover={doHover}
108 | {select} {selected} on:select={doSelect}
109 | {animation}>
110 |
111 | {#each barchart1.options as option}
112 | {option}
113 | {/each}
114 |
115 |
116 |
117 |
118 |
126 |
127 | {#each barchart2.options as option}
128 | {option}
129 | {/each}
130 |
131 |
132 |
133 |
134 | d.year == 2020)} xKey="group" yKey="value" zKey="group" title="Coloured column chart with export options" output={{csv: true, png: true}}/>
135 |
136 |
137 |
d.group == barchart1.selected)} xKey="year" yKey="value" area={true} areaOpacity={0.3} title="Line chart with area" animation={animation} >
138 |
139 | {#each barchart1.options as option}
140 | {option}
141 | {/each}
142 |
143 |
144 |
145 |
160 |
161 |
172 |
173 |
174 |
175 | ({
177 | year: new Date(`${d.year}`),
178 | value: d.value,
179 | group: d.group
180 | }))}
181 | xKey="year" yKey="value" zKey="group"
182 | color="grey" lineWidth={1}
183 | area={false}
184 | xScale="time"
185 | xFormatTickString='%b %y'
186 | title="Line chart with time data"
187 | padding={{ top: 0, bottom: 28, left: 35, right: 60 }}
188 | {animation} labels
189 | {hover} {select}
190 | snapTicks={false}/>
191 |
192 |
193 |
194 |
202 |
203 |
217 |
218 |
225 |
226 |
227 | {#if false}
228 |
229 |
230 |
231 | {/if}
232 |
233 |
234 |
235 |
236 |
237 |
Current features
238 |
In all use cases, each top-level chart component (eg. bar chart, scatter chart) is able to take a series of parameters (data, colours, title, etc) to initialise and customise it.
239 |
As far as possible these parameters are consistent across chart types, and generally there are sensible default values for all parameters (eg. height = 300 pixels) other than "data", which always requires a Tidy Data array.
240 |
Examples of usage
241 |
You can see examples of how these charts can be used in a Svelte project in this REPL , and how they can be used in a plain/vanilla javascript project in this CodePen .
242 |
Intended features
243 |
It is the intention to translate all of the most useful charts from Layer Cake's examples into components, as well as a number of other custom charts (eg. spine charts). For each of the charts, it is the intention to support the following functionalities:
244 |
245 | Every chart type to support a standard Tidy Data format.
246 | Optional title, legend and footnote types that can be added to charts.
247 | Optional hover and click-to-select functionality on all relevant chart types with custom events.
248 | Options/methods for inline labels, tooltips and annotations.
249 | Optional prefixes and suffixes for axis labels.
250 | Colour by group (z parameter) with colors = [array], and colours for hovered and highlighted/selected data points.
251 | Animated transitions when data or keys change (which can be enabled/disabled with animation = true/false).
252 | To group similar charts in a logical way to improve ease of use and allow for custom combinations and animated transitions (eg. scatter + beeswarm or line + area).
253 | Possibility to add custom LayerCake SVG/HTML/Canvas layers in front or behind standard layers of any chart.
254 | Support for pre-rendering and progressive enhancement.
255 |
256 |
Acknowledgement
257 |
These charts are largely based on the chart examples by Michael Keller , the author of the Layer Cake charts/graphics framework for Svelte.
259 |
260 |
261 |
262 |
304 |
--------------------------------------------------------------------------------
/src/apps/BarChart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/BarChart.svelte';
--------------------------------------------------------------------------------
/src/apps/Chart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/Chart.svelte';
--------------------------------------------------------------------------------
/src/apps/ColumnChart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/ColumnChart.svelte';
--------------------------------------------------------------------------------
/src/apps/DotPlotChart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/DotPlotChart.svelte';
--------------------------------------------------------------------------------
/src/apps/LineChart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/LineChart.svelte';
--------------------------------------------------------------------------------
/src/apps/ScatterChart.js:
--------------------------------------------------------------------------------
1 | export { default } from '../charts/ScatterChart.svelte';
--------------------------------------------------------------------------------
/src/charts/BarChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
126 |
127 |
128 | {#if title}
129 |
{title}
130 | {/if}
131 | {#if subtitle}
132 |
{subtitle}
133 | {/if}
134 | {#if alt}
135 |
{alt}
136 | {/if}
137 |
138 |
139 |
169 |
170 |
171 |
172 | {#if xAxis}
173 |
174 | {/if}
175 | {#if yAxis}
176 |
177 | {/if}
178 |
179 |
180 |
181 |
182 |
183 |
184 | {#if table}
185 |
186 |
187 |
188 | {/if}
189 |
190 | {#if legend && _zDomain}
191 |
192 | {/if}
193 | {#if footer}
194 |
195 | {/if}
196 |
197 | {#if output}
198 |
199 | {/if}
200 |
201 |
--------------------------------------------------------------------------------
/src/charts/Chart.svelte:
--------------------------------------------------------------------------------
1 |
67 |
68 | {#if props}
69 | {#key props.data}
70 | {#if type.toLowerCase() === "bar" && props.xKey && props.yKey}
71 |
72 | {:else if type.toLowerCase() === "bar-highlight" && props.xKey && props.yKey}
73 |
74 | {:else if type.toLowerCase() === "column" && props.xKey && props.yKey}
75 |
76 | {:else if type.toLowerCase() === "column-highlight" && props.xKey && props.yKey}
77 |
78 | {:else if type.toLowerCase() === "line" && props.xKey && props.yKey}
79 |
80 | {:else if type.toLowerCase() === "line-highlight" && props.xKey && props.yKey}
81 |
82 | {:else if type.toLowerCase() === "scatter" && props.xKey}
83 |
84 | {:else if type.toLowerCase() === "scatter-highlight" && props.xKey}
85 |
86 | {:else if type.toLowerCase() === "dotplot" && props.xKey && props.yKey}
87 |
88 | {/if}
89 | {/key}
90 | {/if}
91 |
--------------------------------------------------------------------------------
/src/charts/ColumnChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
120 |
121 |
122 | {#if title}
123 |
{title}
124 | {/if}
125 | {#if subtitle}
126 |
{subtitle}
127 | {/if}
128 | {#if alt}
129 |
{alt}
130 | {/if}
131 |
132 |
133 |
163 |
164 |
165 |
166 | {#if xAxis}
167 |
168 | {/if}
169 | {#if yAxis}
170 |
171 | {/if}
172 |
173 |
174 |
175 |
176 |
177 |
178 | {#if table}
179 |
180 |
181 |
182 | {/if}
183 |
184 | {#if legend && _zDomain}
185 |
186 | {/if}
187 | {#if footer}
188 |
189 | {/if}
190 |
191 | {#if output}
192 |
193 | {/if}
194 |
195 |
--------------------------------------------------------------------------------
/src/charts/DotPlotChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
111 |
112 |
113 | {#if title}
114 |
{title}
115 | {/if}
116 | {#if subtitle}
117 |
{subtitle}
118 | {/if}
119 | {#if alt}
120 |
{alt}
121 | {/if}
122 |
123 |
124 |
156 |
157 |
158 |
159 | {#if xAxis}
160 |
161 | {/if}
162 | {#if yAxis}
163 |
164 | {/if}
165 |
166 |
167 |
168 |
169 |
170 |
171 | {#if table}
172 |
173 |
174 |
175 | {/if}
176 |
177 | {#if false && legend && _zDomain}
178 |
179 | {/if}
180 | {#if footer}
181 |
182 | {/if}
183 |
184 | {#if output}
185 |
186 | {/if}
187 |
188 |
--------------------------------------------------------------------------------
/src/charts/LineChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
132 |
133 |
134 | {#if title}
135 |
{title}
136 | {/if}
137 | {#if subtitle}
138 |
{subtitle}
139 | {/if}
140 | {#if alt}
141 |
{alt}
142 | {/if}
143 |
144 |
145 |
174 |
175 |
176 |
177 | {#if xAxis}
178 |
179 | {/if}
180 | {#if yAxis}
181 |
182 | {/if}
183 | {#if area}
184 |
185 | {/if}
186 | {#if line}
187 |
188 | {/if}
189 | {#if labels}
190 |
191 | {/if}
192 |
193 |
194 |
195 |
196 |
197 | {#if table}
198 |
199 |
200 |
201 | {/if}
202 |
203 | {#if legend && _zDomain}
204 |
205 | {/if}
206 | {#if footer}
207 |
208 | {/if}
209 |
210 | {#if output}
211 |
212 | {/if}
213 |
214 |
--------------------------------------------------------------------------------
/src/charts/MarkerChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
50 |
51 | {#if title}
52 | {title}
53 | {/if}
54 | {#if subtitle}
55 | {subtitle}
56 | {/if}
57 | {#if alt}
58 | {alt}
59 | {/if}
60 |
61 |
62 |
81 | {#if width > 100}
82 |
83 |
84 |
85 | {#if xAxis}
86 |
87 | {/if}
88 |
89 |
90 |
91 | {/if}
92 |
93 |
94 |
95 | {#if footer}
96 |
97 | {/if}
98 |
99 |
--------------------------------------------------------------------------------
/src/charts/ScatterChart.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
124 |
125 |
126 | {#if title}
127 |
{title}
128 | {/if}
129 | {#if subtitle}
130 |
{subtitle}
131 | {/if}
132 | {#if alt}
133 |
{alt}
134 | {/if}
135 |
136 |
137 |
171 |
172 |
173 |
174 | {#if xAxis}
175 |
176 | {/if}
177 | {#if yAxis && yKey}
178 |
179 | {/if}
180 |
181 | {#if select || hover}
182 |
183 | {/if}
184 | {#if labels}
185 |
186 | {/if}
187 |
188 |
189 |
190 |
191 |
192 | {#if table}
193 |
194 |
195 |
196 | {/if}
197 |
198 | {#if legend && _zDomain}
199 |
200 | {/if}
201 | {#if footer}
202 |
203 | {/if}
204 |
205 | {#if output}
206 |
207 | {/if}
208 |
209 |
--------------------------------------------------------------------------------
/src/charts/shared/Annotations.svelte:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 | {#each annotations as d, i}
26 |
{d.text}
31 | {/each}
32 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/src/charts/shared/Area.svelte:
--------------------------------------------------------------------------------
1 |
35 |
36 | {#if $coords}
37 |
38 | {#each $coords as group, i}
39 |
40 | {/each}
41 |
42 | {/if}
43 |
--------------------------------------------------------------------------------
/src/charts/shared/ArrowheadDef.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/charts/shared/Arrows.svelte:
--------------------------------------------------------------------------------
1 |
70 |
71 |
72 | {#if annotations.length}
73 |
74 | {#each annotations as anno, i}
75 | {#if anno.arrows}
76 | {#each anno.arrows as arrow}
77 |
80 | {/each}
81 | {/if}
82 | {/each}
83 |
84 | {/if}
85 |
86 |
98 |
--------------------------------------------------------------------------------
/src/charts/shared/AxisRadial.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
26 |
35 |
43 |
44 | {#each $config.x as label, i}
45 |
54 |
55 | {label}
61 | {/each}
62 |
63 |
--------------------------------------------------------------------------------
/src/charts/shared/AxisX.html.svelte:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 | {#each tickVals as tick, i}
29 | {#if gridlines !== false}
30 |
31 | {/if}
32 | {#if tickMarks === true}
33 |
34 | {/if}
35 |
38 |
{i == tickVals.length - 1 ? prefix + formatTick(tick) + suffix : formatTick(tick)}
41 |
42 | {/each}
43 | {#if baseline === true}
44 |
45 | {/if}
46 |
47 |
48 |
89 |
--------------------------------------------------------------------------------
/src/charts/shared/AxisX.svelte:
--------------------------------------------------------------------------------
1 |
62 |
63 |
64 | {#each tickVals as tick, i}
65 |
66 | {#if gridlines !== false}
67 |
68 | {/if}
69 | {#if tickMarks === true}
70 |
71 | {/if}
72 |
79 | {i == tickVals.length - 1 ? prefix + formatTick(tick) + suffix : formatTick(tick)}
80 |
81 |
82 | {/each}
83 |
84 |
85 |
110 |
--------------------------------------------------------------------------------
/src/charts/shared/AxisY.html.svelte:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 | {#each tickVals as tick, i}
31 |
32 | {#if gridlines !== false}
33 |
34 | {/if}
35 | {#if baseline !== false && i === 0}
36 |
37 | {/if}
38 | {#if tickMarks === true}
39 |
40 | {/if}
41 |
{i == tickVals.length - 1 ? prefix + formatTick(tick) + suffix : formatTick(tick)}
49 |
50 | {/each}
51 |
52 |
53 |
86 |
--------------------------------------------------------------------------------
/src/charts/shared/AxisY.svelte:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 | {#each tickVals as tick, i}
42 |
43 | {#if gridlines !== false}
44 |
55 | {/if}
56 | {#if tickMarks === true}
57 |
67 | {/if}
68 |
74 | {i == tickVals.length - 1 ? prefix + formatTick(tick) + suffix : formatTick(tick)}
75 |
76 |
77 | {/each}
78 |
79 |
80 |
93 |
--------------------------------------------------------------------------------
/src/charts/shared/Bar.svelte:
--------------------------------------------------------------------------------
1 |
60 |
61 | {#if $coords}
62 | {#if mode === "confidence"}
63 |
64 | {#each mapData($coords) as d, i}
65 |
72 | {/each}
73 |
74 | {/if}
75 |
76 | {#each $coords as group, i}
77 | {#each group as d, j}
78 | {#if !(mode === 'confidence' && i > 0)}
79 |
80 |
81 | doHover(e, $data[i][j]) : null}
90 | on:mouseleave={hover ? (e) => doHover(e, null) : null}
91 | on:focus={select ? (e) => doHover(e, $data[i][j]) : null}
92 | on:blur={select ? (e) => doHover(e, null) : null}
93 | on:click={select ? (e) => doSelect(e, $data[i][j]) : null}
94 | tabindex="{hover || select ? 0 : -1}"
95 | />
96 | {/if}
97 | {/each}
98 | {/each}
99 |
100 | {/if}
101 |
102 |
--------------------------------------------------------------------------------
/src/charts/shared/Beeswarm.html.svelte:
--------------------------------------------------------------------------------
1 |
57 |
58 |
59 | {#each circles as d}
60 |
72 |
{$custom.getTitle(d)}
73 |
74 | {/each}
75 |
76 |
77 |
85 |
--------------------------------------------------------------------------------
/src/charts/shared/Beeswarm.svelte:
--------------------------------------------------------------------------------
1 |
57 |
58 |
59 | {#each circles as d}
60 |
68 | {$custom.getTitle(d)}
69 |
70 | {/each}
71 |
72 |
--------------------------------------------------------------------------------
/src/charts/shared/BeeswarmForce.html.svelte:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 | {#each simulation.nodes() as node}
33 |
45 |
{$custom.getTitle(node)}
46 |
47 | {/each}
48 |
49 |
50 |
58 |
--------------------------------------------------------------------------------
/src/charts/shared/BeeswarmForce.svelte:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 | {#each simulation.nodes() as node}
33 |
41 | {$custom.getTitle(node)}
42 |
43 | {/each}
44 |
45 |
--------------------------------------------------------------------------------
/src/charts/shared/Brush.svelte:
--------------------------------------------------------------------------------
1 |
86 |
87 |
88 | {#if min !== null}
89 |
90 |
91 |
92 | {/if}
93 |
94 |
95 |
128 |
--------------------------------------------------------------------------------
/src/charts/shared/CalendarMonth.svelte:
--------------------------------------------------------------------------------
1 |
59 |
60 | {#each days as day}
61 |
70 | {/each}
71 |
72 |
79 |
--------------------------------------------------------------------------------
/src/charts/shared/CirclePack.html.svelte:
--------------------------------------------------------------------------------
1 |
62 |
63 |
64 | {#each descendants as d}
65 |
70 |
74 |
87 |
{titleCase(d.data.id)}
88 | {#if d.data.data[valueKey]}
89 |
{commas(d.data.data[valueKey])}
90 | {/if}
91 |
92 |
93 | {/each}
94 |
95 |
96 |
156 |
--------------------------------------------------------------------------------
/src/charts/shared/CirclePackForce.svelte:
--------------------------------------------------------------------------------
1 |
60 | {#each nodes as point}
61 |
70 |
71 |
72 | {/each}
73 |
--------------------------------------------------------------------------------
/src/charts/shared/Column.svelte:
--------------------------------------------------------------------------------
1 |
60 |
61 | {#if $coords}
62 | {#if mode === "confidence"}
63 |
64 | {#each mapData($coords) as d, i}
65 |
72 | {/each}
73 |
74 | {/if}
75 |
76 | {#each $coords as group, i}
77 | {#each group as d, j}
78 | {#if !(mode === 'confidence' && i > 0)}
79 |
80 |
81 | doHover(e, $data[i][j]) : null}
90 | on:mouseleave={hover ? (e) => doHover(e, null) : null}
91 | on:focus={select ? (e) => doHover(e, $data[i][j]) : null}
92 | on:blur={select ? (e) => doHover(e, null) : null}
93 | on:click={select ? (e) => doSelect(e, $data[i][j]) : null}
94 | tabindex="{hover || select ? 0 : -1}"
95 | />
96 | {/if}
97 | {/each}
98 | {/each}
99 |
100 | {/if}
101 |
102 |
--------------------------------------------------------------------------------
/src/charts/shared/ColumnLinear.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 | {#each $data as d, i}
24 |
35 | {/each}
36 |
--------------------------------------------------------------------------------
/src/charts/shared/DotPlot.html.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | {#each $data as row}
14 |
15 |
23 |
24 | {#each $xGet(row) as circleX, i}
25 |
35 | {/each}
36 |
37 | {/each}
38 |
39 |
40 |
53 |
--------------------------------------------------------------------------------
/src/charts/shared/DotPlot.svelte:
--------------------------------------------------------------------------------
1 |
21 |
22 | {#if $coords}
23 |
24 | {#each $coords.map(d => ({x: d.map(e => e.x), y: d[0].y})) as d}
25 |
33 | {/each}
34 |
35 |
36 | {#each $coords as group, i}
37 | {#each group as d, j}
38 |
44 | {/each}
45 | {/each}
46 |
47 | {#if idKey && (hovered || selected || highlighted[0])}
48 | {#each $coords as group, i}
49 | {#each group as d, j}
50 | {#if [...highlighted, selected, hovered].includes($data[i][j][idKey])}
51 |
60 | {/if}
61 | {/each}
62 | {/each}
63 | {/if}
64 |
65 | {/if}
66 |
--------------------------------------------------------------------------------
/src/charts/shared/Export.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | {#if output.csv}
13 | getCSV(data, keys, title ? title : 'chart')}>Download data (CSV)
14 | {/if}
15 | {#if output.csv && output.png}|{/if}
16 | {#if output.png}
17 | getPNG(el, title ? title : 'chart')}>Download image (PNG)
18 | {/if}
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/charts/shared/Footer.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/charts/shared/ForceDirectedGraph.svelte:
--------------------------------------------------------------------------------
1 |
68 | {#each links as link}
69 |
70 |
76 | {$x(link.source)}
77 |
78 |
79 | {/each}
80 |
81 | {#each nodes as point}
82 |
91 | {$x(point)}
92 |
93 | {/each}
94 |
--------------------------------------------------------------------------------
/src/charts/shared/Key.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
68 |
69 |
70 | {#each $zDomain as item}
71 |
72 |
79 |
{displayName(item)}
80 |
81 | {/each}
82 |
83 |
--------------------------------------------------------------------------------
/src/charts/shared/Labels-html.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 | {#each $data as group}
20 | {cap(group.key)}
27 | {/each}
28 |
29 |
36 |
--------------------------------------------------------------------------------
/src/charts/shared/Labels.svelte:
--------------------------------------------------------------------------------
1 |
54 |
55 | {#if coordsWithLabels}
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | {#if coordsWithLabels?.[0]?.x}
67 | {#each coordsWithLabels as d, i}
68 | {#if labelAll || [hovered, selected].includes($data[i][idKey])}
69 |
81 | {content ? content : $data[i][labelKey]}
82 |
83 | {/if}
84 | {/each}
85 | {:else if coordsWithLabels?.[0]?.[0]?.x}
86 | {#each coordsWithLabels as d, i}
87 | {#if labelAll || [hovered, selected].includes($data[i][0][idKey])}
88 | {#if marker}
89 |
102 | {/if}
103 |
122 | {content ? content : $data[i][0][labelKey]}
123 |
124 | {/if}
125 | {/each}
126 | {/if}
127 |
128 | {/if}
129 |
130 |
135 |
--------------------------------------------------------------------------------
/src/charts/shared/Legend.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 | {#if Array.isArray(_domain) && Array.isArray(colors)}
16 |
17 | {#each _domain as label, i}
18 |
19 |
27 | {label}
28 |
29 | {/each}
30 |
31 | {/if}
32 |
33 |
--------------------------------------------------------------------------------
/src/charts/shared/Line.svelte:
--------------------------------------------------------------------------------
1 |
55 |
56 | {#if $coords}
57 |
58 | {#each $coords as group, i}
59 |
60 |
61 | doHover(e, $data[i]) : null}
65 | on:mouseleave={hover ? (e) => doHover(e, null) : null}
66 | on:focus={select ? (e) => doHover(e, $data[i]) : null}
67 | on:blur={select ? (e) => doHover(e, null) : null}
68 | on:click={select ? (e) => doSelect(e, $data[i]) : null}
69 | tabindex="{hover || select ? 0 : -1}"
70 | />
71 |
80 | {/each}
81 |
82 | {#if idKey && (hover || selected || highlighted[0])}
83 | {#each $coords as group, i}
84 | {#if [hovered, selected, ...highlighted].includes($data[i][0][idKey]) }
85 |
98 | {/if}
99 | {/each}
100 | {/if}
101 |
102 | {/if}
103 |
104 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/charts/shared/Map.canvas.svelte:
--------------------------------------------------------------------------------
1 |
55 |
--------------------------------------------------------------------------------
/src/charts/shared/Map.svg.svelte:
--------------------------------------------------------------------------------
1 |
53 |
54 | dispatch('mouseout')}
57 | >
58 | {#each features as feature}
59 | dispatch('mousemove', { e, props: feature.properties })}
66 | on:mousemove={handleMousemove(feature)}
67 | >
68 | {/each}
69 |
70 |
71 |
81 |
--------------------------------------------------------------------------------
/src/charts/shared/MapPoints.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 | {#each pointsData as d}
20 |
25 |
26 | {/each}
27 |
28 |
29 |
36 |
--------------------------------------------------------------------------------
/src/charts/shared/MultiLine.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 | {#each $data as group}
17 |
22 | {/each}
23 |
24 |
25 |
33 |
--------------------------------------------------------------------------------
/src/charts/shared/QuadTree.percent-range.svelte:
--------------------------------------------------------------------------------
1 |
40 |
41 |
50 |
51 |
56 |
63 |
--------------------------------------------------------------------------------
/src/charts/shared/QuadTree.svelte:
--------------------------------------------------------------------------------
1 |
36 |
37 |
46 |
47 |
52 |
59 |
--------------------------------------------------------------------------------
/src/charts/shared/Radar.svelte:
--------------------------------------------------------------------------------
1 |
29 |
30 |
33 | {#each $data as row}
34 |
35 |
42 |
43 |
44 | {#each $xGet(row) as circleR, i}
45 |
53 | {/each}
54 | {/each}
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/src/charts/shared/Sankey.svelte:
--------------------------------------------------------------------------------
1 |
34 |
35 |
40 |
41 |
42 |
43 | {#each sankeyData.links as d}
44 |
50 | {/each}
51 |
52 |
53 | {#each sankeyData.nodes as d, i}
54 |
60 |
67 | {d.id}
68 |
69 | {/each}
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/charts/shared/Scatter.canvas.svelte:
--------------------------------------------------------------------------------
1 |
35 |
--------------------------------------------------------------------------------
/src/charts/shared/Scatter.html.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {#each $data as d}
16 |
27 | {/each}
28 |
29 |
30 |
37 |
--------------------------------------------------------------------------------
/src/charts/shared/Scatter.svg.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 | {#if $coords}
21 |
22 | {#each $coords as d, i}
23 |
30 | {/each}
31 |
32 | {#if idKey && (hovered || selected || highlighted[0])}
33 | {#each $coords as d, i}
34 | {#if [...highlighted, selected, hovered].includes($data[i][idKey])}
35 |
44 | {/if}
45 | {/each}
46 | {/if}
47 |
48 | {/if}
49 |
--------------------------------------------------------------------------------
/src/charts/shared/Scatter.webgl.svelte:
--------------------------------------------------------------------------------
1 |
154 |
--------------------------------------------------------------------------------
/src/charts/shared/SetCoords.svelte:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/charts/shared/SharedTooltip.percent-range.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
68 |
69 |
78 | {#if visible === true}
79 |
82 |
95 | {/if}
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/charts/shared/SharedTooltip.svelte:
--------------------------------------------------------------------------------
1 |
37 |
38 |
69 |
70 |
79 | {#if visible === true}
80 |
83 |
96 | {/if}
97 |
98 |
99 |
--------------------------------------------------------------------------------
/src/charts/shared/SmallMultipleWrapper.percent-range.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
38 |
39 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/charts/shared/SmallMultipleWrapper.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
36 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/charts/shared/Stack.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 | {#each $points as d, i}
27 | {#if i < $points.length - 1}
28 |
37 | {/if}
38 | {/each}
39 |
40 |
--------------------------------------------------------------------------------
/src/charts/shared/Subtitle.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/charts/shared/SyncedBrushWrapper.percent-range.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
45 |
46 |
47 |
48 |
57 |
58 | {
60 | const filtered = ticks.filter(t => t % 1 === 0);
61 | if (filtered.length > 7) {
62 | return filtered.filter((t, i) => i % 2 === 0);
63 | }
64 | return filtered;
65 | }}
66 | />
67 |
70 |
71 |
72 |
75 |
78 |
79 |
80 |
81 |
82 |
83 |
92 |
93 |
96 |
99 |
100 |
101 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/src/charts/shared/SyncedBrushWrapper.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
45 |
46 |
47 |
48 |
55 |
56 | {
58 | const filtered = ticks.filter(t => t % 1 === 0);
59 | if (filtered.length > 7) {
60 | return filtered.filter((t, i) => i % 2 === 0);
61 | }
62 | return filtered;
63 | }}
64 | />
65 |
68 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
86 |
87 |
90 |
93 |
94 |
95 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/charts/shared/Table.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 | {#if data && keys}
20 |
21 |
22 |
23 | {#each keys as key}
24 | {key}
25 | {/each}
26 |
27 |
28 |
29 | {#each data as d}
30 |
31 | {#each keys as key}
32 | {d[key]}
33 | {/each}
34 |
35 | {/each}
36 |
37 |
38 | {/if}
--------------------------------------------------------------------------------
/src/charts/shared/Title.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/charts/shared/Tooltip.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
18 |
19 | {#if evt.detail}
20 |
27 |
28 |
29 | {/if}
30 |
--------------------------------------------------------------------------------
/src/charts/shared/Voronoi.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
50 |
51 | {#if voronoi}
52 |
53 | {#each $data as d, i}
54 |
55 |
56 | doHover(e, $data[i]) : null}
60 | on:mouseleave={hover ? e => doHover(e, null) : null}
61 | on:focus={select ? e => doHover(e, $data[i]): null}
62 | on:blur={select ? e => doHover(e, null) : null}
63 | on:click={select ? e => doSelect(e, $data[i]) : null}
64 | tabindex="{hover || select ? 0 : -1}"
65 | />
66 | {/each}
67 |
68 | {/if}
69 |
--------------------------------------------------------------------------------
/src/charts/shared/ss/AreaStacked.svelte:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 | {#each groups as group, i}
35 |
36 | {/each}
37 |
38 |
--------------------------------------------------------------------------------
/src/charts/shared/ss/BarStacked.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | {#each groups as group, i}
19 | {#each group as d, j}
20 |
29 | {/each}
30 | {/each}
31 |
32 |
--------------------------------------------------------------------------------
/src/charts/shared/ss/ColumnStacked.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {#each groups as group, i}
16 | {#each group as d, j}
17 |
26 | {/each}
27 | {/each}
28 |
29 |
--------------------------------------------------------------------------------
/src/charts/shared/ss/LineStacked.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 | {#each groups as group}
25 |
31 | {/each}
32 |
33 |
34 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/data/data-scatter.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | year: 1979,
4 | value: 7.19,
5 | alt: 12,
6 | group: 'apples'
7 | },
8 | {
9 | year: 1980,
10 | value: 7.83,
11 | alt: 15,
12 | group: 'apples'
13 | },
14 | {
15 | year: 1981,
16 | value: 7.24,
17 | alt: 17,
18 | group: 'apples'
19 | },
20 | {
21 | year: 1982,
22 | value: 7.44,
23 | alt: 28,
24 | group: 'apples'
25 | },
26 | {
27 | year: 1983,
28 | value: 7.51,
29 | alt: 23,
30 | group: 'apples'
31 | },
32 | {
33 | year: 1984,
34 | value: 7.1,
35 | alt: 17,
36 | group: 'apples'
37 | },
38 | {
39 | year: 1985,
40 | value: 6.91,
41 | alt: 11,
42 | group: 'apples'
43 | },
44 | {
45 | year: 1986,
46 | value: 7.53,
47 | alt: 13,
48 | group: 'apples'
49 | },
50 | {
51 | year: 1987,
52 | value: 7.47,
53 | alt: 18,
54 | group: 'apples'
55 | },
56 | {
57 | year: 1988,
58 | value: 7.48,
59 | alt: 20,
60 | group: 'apples'
61 | },
62 | {
63 | year: 1989,
64 | value: 7.03,
65 | alt: 24,
66 | group: 'apples'
67 | },
68 | {
69 | year: 1990,
70 | value: 6.23,
71 | alt: 26,
72 | group: 'bananas'
73 | },
74 | {
75 | year: 1991,
76 | value: 6.54,
77 | alt: 16,
78 | group: 'bananas'
79 | },
80 | {
81 | year: 1992,
82 | value: 7.54,
83 | alt: 25,
84 | group: 'bananas'
85 | },
86 | {
87 | year: 1993,
88 | value: 6.5,
89 | alt: 28,
90 | group: 'bananas'
91 | },
92 | {
93 | year: 1994,
94 | value: 7.18,
95 | alt: 11,
96 | group: 'bananas'
97 | },
98 | {
99 | year: 1995,
100 | value: 6.12,
101 | alt: 19,
102 | group: 'bananas'
103 | },
104 | {
105 | year: 1996,
106 | value: 7.87,
107 | alt: 14,
108 | group: 'bananas'
109 | },
110 | {
111 | year: 1997,
112 | value: 6.73,
113 | alt: 22,
114 | group: 'bananas'
115 | },
116 | {
117 | year: 1998,
118 | value: 6.55,
119 | alt: 13,
120 | group: 'bananas'
121 | },
122 | {
123 | year: 1999,
124 | value: 6.23,
125 | alt: 30,
126 | group: 'bananas'
127 | },
128 | {
129 | year: 2000,
130 | value: 6.31,
131 | alt: 27,
132 | group: 'bananas'
133 | },
134 | {
135 | year: 2001,
136 | value: 6.74,
137 | alt: 13,
138 | group: 'cherries'
139 | },
140 | {
141 | year: 2002,
142 | value: 5.95,
143 | alt: 18,
144 | group: 'cherries'
145 | },
146 | {
147 | year: 2003,
148 | value: 6.13,
149 | alt: 15,
150 | group: 'cherries'
151 | },
152 | {
153 | year: 2004,
154 | value: 6.04,
155 | alt: 11,
156 | group: 'cherries'
157 | },
158 | {
159 | year: 2005,
160 | value: 5.56,
161 | alt: 29,
162 | group: 'cherries'
163 | },
164 | {
165 | year: 2006,
166 | value: 5.91,
167 | alt: 26,
168 | group: 'cherries'
169 | },
170 | {
171 | year: 2007,
172 | value: 4.29,
173 | alt: 10,
174 | group: 'cherries'
175 | },
176 | {
177 | year: 2008,
178 | value: 4.72,
179 | alt: 14,
180 | group: 'cherries'
181 | },
182 | {
183 | year: 2009,
184 | value: 5.38,
185 | alt: 21,
186 | group: 'cherries'
187 | },
188 | {
189 | year: 2010,
190 | value: 4.92,
191 | alt: 20,
192 | group: 'cherries'
193 | },
194 | {
195 | year: 2011,
196 | value: 4.61,
197 | alt: 24,
198 | group: 'dates'
199 | },
200 | {
201 | year: 2012,
202 | value: 3.62,
203 | alt: 19,
204 | group: 'dates'
205 | },
206 | {
207 | year: 2013,
208 | value: 5.35,
209 | alt: 12,
210 | group: 'dates'
211 | },
212 | {
213 | year: 2014,
214 | value: 5.28,
215 | alt: 13,
216 | group: 'dates'
217 | },
218 | {
219 | year: 2015,
220 | value: 4.63,
221 | alt: 28,
222 | group: 'dates'
223 | },
224 | {
225 | year: 2016,
226 | value: 4.72,
227 | alt: 30,
228 | group: 'dates'
229 | }
230 | ];
--------------------------------------------------------------------------------
/src/data/data.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | year: 2017,
4 | value: 480,
5 | group: 'apples'
6 | },
7 | {
8 | year: 2017,
9 | value: 320,
10 | group: 'bananas'
11 | },
12 | {
13 | year: 2017,
14 | value: 640,
15 | group: 'cherries'
16 | },
17 | {
18 | year: 2017,
19 | value: 400,
20 | group: 'dates'
21 | },
22 | {
23 | year: 2018,
24 | value: 960,
25 | group: 'apples'
26 | },
27 | {
28 | year: 2018,
29 | value: 640,
30 | group: 'bananas'
31 | },
32 | {
33 | year: 2018,
34 | value: 640,
35 | group: 'cherries'
36 | },
37 | {
38 | year: 2018,
39 | value: 400,
40 | group: 'dates'
41 | },
42 | {
43 | year: 2019,
44 | value: 1440,
45 | group: 'apples'
46 | },
47 | {
48 | year: 2019,
49 | value: 1600,
50 | group: 'bananas'
51 | },
52 | {
53 | year: 2019,
54 | value: 960,
55 | group: 'cherries'
56 | },
57 | {
58 | year: 2019,
59 | value: 400,
60 | group: 'dates'
61 | },
62 | {
63 | year: 2020,
64 | value: 1920,
65 | group: 'apples'
66 | },
67 | {
68 | year: 2020,
69 | value: 3840,
70 | group: 'bananas'
71 | },
72 | {
73 | year: 2020,
74 | value: 960,
75 | group: 'cherries'
76 | },
77 | {
78 | year: 2020,
79 | value: 400,
80 | group: 'dates'
81 | }
82 | ]
--------------------------------------------------------------------------------
/src/js/accurate-beeswarm.js:
--------------------------------------------------------------------------------
1 | // Based on https://github.com/jtrim-ons/accurate-beeswarm-plot
2 | const seed = 1;
3 | const randomness1 = 5;
4 | const randomness2 = 2;
5 |
6 | export default class {
7 | constructor(items, radiusFun, xFun, padding, yOffset) {
8 | this.items = items;
9 | this.radiusFun = radiusFun;
10 | this.xFun = xFun;
11 | this.padding = padding;
12 | this.yOffset = yOffset;
13 | this.tieBreakFn = this._sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
14 | this.maxR = Math.max(...items.map(d => radiusFun(d)));
15 | this.rng = this._sfc32(1, 2, 3, seed);
16 | }
17 |
18 | calculateYPositions() {
19 | let all = this.items
20 | .map((d, i) => ({
21 | datum: d,
22 | originalIndex: i,
23 | x: this.xFun(d),
24 | r: this.radiusFun(d) + this.padding,
25 | y: null,
26 | placed: false
27 | }))
28 | .sort((a, b) => a.x - b.x);
29 | all.forEach(function(d, i) {
30 | d.index = i;
31 | });
32 | let tieBreakFn = this.tieBreakFn;
33 | all.forEach(function(d) {
34 | d.tieBreaker = tieBreakFn(d.x);
35 | });
36 | let allSortedByPriority = [...all].sort((a, b) => {
37 | let key_a = this.radiusFun(a.datum) + a.tieBreaker * randomness1;
38 | let key_b = this.radiusFun(b.datum) + b.tieBreaker * randomness1;
39 | if (key_a != key_b) return key_b - key_a;
40 | return a.x - b.x;
41 | });
42 | for (let item of allSortedByPriority) {
43 | item.placed = true;
44 | item.y = this._getBestYPosition(item, all);
45 | }
46 | all.sort((a, b) => a.originalIndex - b.originalIndex);
47 | return all.map(d => ({
48 | x: d.x,
49 | y: d.y + this.yOffset,
50 | r: this.radiusFun(d.datum)
51 | }));
52 | }
53 |
54 | // Random number generator (for reproducibility)
55 | // https://stackoverflow.com/a/47593316
56 | _sfc32(a, b, c, d) {
57 | let rng = function() {
58 | a >>>= 0;
59 | b >>>= 0;
60 | c >>>= 0;
61 | d >>>= 0;
62 | var t = (a + b) | 0;
63 | a = b ^ (b >>> 9);
64 | b = (c + (c << 3)) | 0;
65 | c = (c << 21) | (c >>> 11);
66 | d = (d + 1) | 0;
67 | t = (t + d) | 0;
68 | c = (c + t) | 0;
69 | return (t >>> 0) / 4294967296;
70 | };
71 | for (let i = 0; i < 10; i++) {
72 | rng();
73 | }
74 | return rng;
75 | }
76 |
77 | _getBestYPosition(item, all) {
78 | let forbiddenIntervals = [];
79 | for (let step of [-1, 1]) {
80 | let xDist;
81 | let r = item.r;
82 | for (
83 | let i = item.index + step;
84 | i >= 0 &&
85 | i < all.length &&
86 | (xDist = Math.abs(item.x - all[i].x)) < r + this.maxR;
87 | i += step
88 | ) {
89 | let other = all[i];
90 | if (!other.placed) continue;
91 | let sumOfRadii = r + other.r;
92 | if (xDist >= r + other.r) continue;
93 | let yDist = Math.sqrt(sumOfRadii * sumOfRadii - xDist * xDist);
94 | let forbiddenInterval = [other.y - yDist, other.y + yDist];
95 | forbiddenIntervals.push(forbiddenInterval);
96 | }
97 | }
98 | if (forbiddenIntervals.length == 0) {
99 | return item.r * (this.rng() - .5) * randomness2;
100 | }
101 | let candidatePositions = forbiddenIntervals.flat();
102 | candidatePositions.push(0);
103 | candidatePositions.sort((a, b) => {
104 | let abs_a = Math.abs(a);
105 | let abs_b = Math.abs(b);
106 | if (abs_a < abs_b) return -1;
107 | if (abs_a > abs_b) return 1;
108 | return a - b;
109 | });
110 | // find first candidate position that is not in any of the
111 | // forbidden intervals
112 | for (let i = 0; i < candidatePositions.length; i++) {
113 | let position = candidatePositions[i];
114 | if (
115 | forbiddenIntervals.every(
116 | interval => position <= interval[0] || position >= interval[1]
117 | )
118 | ) {
119 | return position;
120 | }
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/src/js/spread-labels.js:
--------------------------------------------------------------------------------
1 | // https://observablehq.com/@jtrim-ons/label-placement-for-a-slope-chart-2
2 | export default (ys, radius) => {
3 | let zs = ys.map((y, i) => y - i * radius * 2);
4 | return f(zs).map((x, i) => x + i * radius * 2);
5 | }
6 |
7 | const f = (zs) => {
8 | let batches = [];
9 | for (let z of zs) {
10 | batches.push({ size: 1, mean: z });
11 | while (batches.length > 1) {
12 | let b = batches[batches.length - 2];
13 | let c = batches[batches.length - 1];
14 | if (b.mean < c.mean) break;
15 | b.mean = (b.mean * b.size + c.mean * c.size) / (b.size + c.size);
16 | b.size = b.size + c.size;
17 | batches.pop();
18 | }
19 | }
20 | let xs = [];
21 | for (const batch of batches)
22 | for (let i = 0; i < batch.size; i++) xs.push(batch.mean);
23 | return xs;
24 | }
--------------------------------------------------------------------------------
/src/js/utils.js:
--------------------------------------------------------------------------------
1 | import html2canvas from 'html2canvas';
2 |
3 | export function groupData(data, domain, key) {
4 | let groups = [];
5 | if (key) {
6 | domain.forEach(group => {
7 | groups.push(data.filter(d => d[key] == group));
8 | });
9 | } else {
10 | groups = [data];
11 | }
12 | return groups;
13 | }
14 |
15 | export function stackData(data, domain, valKey, grpKey) {
16 | let groups = [];
17 | let base = JSON.parse(JSON.stringify(data.filter(d => d[grpKey] == domain[0])));
18 | base.forEach(d => d[valKey] = 0);
19 | domain.forEach(group => {
20 | let clone = JSON.parse(JSON.stringify(data.filter(d => d[grpKey] == group)));
21 | clone.forEach((d, i) => {
22 | d[valKey] += base[i][valKey];
23 | base[i][valKey] = d[valKey];
24 | });
25 | groups.push(clone);
26 | });
27 | return groups;
28 | }
29 |
30 | export function getCSV(data, keys = [], filename) {
31 | let str = '';
32 | let newkeys = [];
33 | keys.forEach(key => {
34 | if (key && !newkeys.includes(key)) {
35 | newkeys.push(key);
36 | }
37 | });
38 | str += newkeys.join(',') + '\n';
39 | data.forEach(d => {
40 | str += newkeys.map(key => d[key]).join(',') + '\n';
41 | });
42 | let content = 'data:text/csv;charset=utf-8,' + encodeURI(str);
43 | download(content, filename + '.csv');
44 | }
45 |
46 | export function getPNG(target, filename) {
47 | html2canvas(target)
48 | .then(canvas => {
49 | let content = canvas.toDataURL();
50 | download(content, filename + '.png');
51 | });
52 | }
53 |
54 | function download(content, filename) {
55 | var a = document.createElement('a');
56 | a.href = content;
57 | a.download = filename;
58 | a.click();
59 | }
60 |
61 | export function commas(num) {
62 | const parts = String(num).split(".");
63 | parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
64 | return parts.join(".");
65 | }
--------------------------------------------------------------------------------
/src/js/wrap.js:
--------------------------------------------------------------------------------
1 | // Based on https://observablehq.com/@jtrim-ons/svg-text-wrapping
2 | // Adapted to remove D3 dependency
3 | export default function (node, options = {}) {
4 | if (!options.disable) {
5 | const getVal = (val, fallback) => typeof val === "number" ? val : fallback;
6 | const width = getVal(options.width, 100);
7 | const dyAdjust = getVal(options.dyAdjust, 0.05);
8 | const lineHeightEms = getVal(options.lineHeightEms, 1);
9 | const lineHeightSquishFactor = getVal(options.lineHeightSquishFactor, 1);
10 | const splitOnHyphen = options.splitOnHyphen || true;
11 | const centreVertically = options.centreVertically || true;
12 |
13 | const x = +node.getAttribute("x");
14 | const y = +node.getAttribute("y");
15 | const anchor = node.getAttribute("text-anchor");
16 |
17 | const svgNode = (parent, type, content = null) => {
18 | const node = document.createElementNS("http://www.w3.org/2000/svg", type);
19 | if (content) node.textContent = content;
20 | parent.append(node);
21 | return node;
22 | }
23 |
24 | const words = [];
25 | node.textContent
26 | .split(/\s+/)
27 | .forEach(function (w) {
28 | if (splitOnHyphen) {
29 | var subWords = w.split("-");
30 | for (var i = 0; i < subWords.length - 1; i++)
31 | words.push(subWords[i] + "-");
32 | words.push(subWords[subWords.length - 1] + " ");
33 | } else {
34 | words.push(w + " ");
35 | }
36 | });
37 |
38 | node.textContent = ""; // Empty the text element
39 |
40 | // `tspan` is the tspan element that is currently being added to
41 | let tspan = svgNode(node, "tspan");
42 |
43 | let line = ""; // The current value of the line
44 | let prevLine = ""; // The value of the line before the last word (or sub-word) was added
45 | let nWordsInLine = 0; // Number of words in the line
46 | for (let i = 0; i < words.length; i++) {
47 | let word = words[i];
48 | prevLine = line;
49 | line = line + word;
50 | ++nWordsInLine;
51 | tspan.textContent = line.trim();
52 | if (tspan.getComputedTextLength() > width && nWordsInLine > 1) {
53 | // The tspan is too long, and it contains more than one word.
54 | // Remove the last word and add it to a new tspan.
55 | tspan.textContent = prevLine.trim();
56 | prevLine = "";
57 | line = word;
58 | nWordsInLine = 1;
59 | tspan = svgNode(node, "tspan", word.trim());
60 | }
61 | }
62 |
63 | const tspans = node.childNodes;
64 |
65 | let h = lineHeightEms;
66 | // Reduce the line height a bit if there are more than 2 lines.
67 | if (tspans.length > 2)
68 | for (let i = 0; i < tspans.length; i++) h *= lineHeightSquishFactor;
69 |
70 | let dx = 0;
71 | tspans.forEach((d, i) => {
72 | // Calculate the y offset (dy) for each tspan so that the vertical centre
73 | // of the tspans roughly aligns with the text element's y position.
74 | if (anchor === "end" && i !== 0) dx = -d.getComputedTextLength();
75 | let dy = i === 0 ? dyAdjust : 1;
76 | if (centreVertically && i === 0) dy -= ((tspans.length - 1) * h) / 2;
77 |
78 | d.setAttribute("dx", dx);
79 | d.setAttribute("dy", dy + "em");
80 | if (anchor !== "end") dx = -d.getComputedTextLength();
81 | });
82 | }
83 | }
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte';
2 | import config from '../config.json';
3 |
4 | const app = new App({
5 | target: document.body,
6 | hydrate: config.hydrate
7 | });
8 |
9 | export default app;
10 |
--------------------------------------------------------------------------------