Custom Charts or Canvas Rendering
This example shows how to render a line chart with D3.js and sync it with the timeline.
The same approach can be used to render a canvas-based component to display large amounts of data without performance issues, as the timeline items are rendered as individual DOM elements (see Performance).
INFO
The basic principle is to render a custom component in a group (using the items-GROUPID
slot) and pass the viewport range to the custom component. That component is then responsible for rendering the data points within this range.
Position the custom component over a timeline row with CSS.
Jan 1, 1970 00:00
00:00:10
00:00:20
00:00:30
00:00:40
00:00:50
Code
vue
<script setup lang="ts">
import { } from 'vue';
import from './components/LineChart.vue';
const = ([
{ : 1, : 1, : 'range', : { '--item-background': 'var(--color-2)' }, : 1000000, : 4500000 },
{ : 3, : 1, : 'range', : 6000000, : 8000000 },
]);
const = [
{ : 'linechart', : 1, : 'point', : 1000000 },
{ : 'linechart', : 1, : 'point', : 1500000 },
{ : 'linechart', : 0.7, : 'point', : 2000000 },
{ : 'linechart', : 0, : 'point', : 2500000 },
{ : 'linechart', : 1, : 'point', : 3000000 },
{ : 'linechart', : 0, : 'point', : 3500000 },
{ : 'linechart', : 0, : 'point', : 4000000 },
{ : 'linechart', : 0, : 'point', : 4500000 },
{ : 'linechart', : 1, : 'point', : 5000000 },
{ : 'linechart', : 0.5, : 'point', : 5500000 },
{ : 'linechart', : 1, : 'point', : 6000000 },
{ : 'linechart', : 1, : 'point', : 6500000 },
{ : 'linechart', : 0.6, : 'point', : 7000000 },
];
</script>
<template>
<
=""
="[{: 1},{: 'linechart'}]"
="0"
="8000000"
>
< #items-linechart="{ , , }">
<
=""
=""
=""
/>
</>
</Timeline>
</template>
vue
<template>
< ="chart" ="root"></>
</template>
<script lang="ts" setup>
import { , } from 'vue';
// import * as d3 from 'd3'; (disabled due to vitepress)
const = <{
: number;
: number;
: { : number; : number; }[];
}>();
function (: number, : number, : typeof .) {
if (!.d3) {
// ensure d3 is loaded (due to import within vitepress)
(() => (, , ), 100);
return;
}
const = .('chart');
if (!) {
return;
}
d3.select('#chart').selectAll('svg').remove();
const = { : 2, : 0, : 2, : 0 };
const = . - . - .;
const = 32 - . - .;
const = d3.select('#chart')
.append('svg')
.attr('width', + . + .)
.attr('height', + . + .)
.append('g')
.attr('transform', `translate(${.},${.})`);
const = d3.scaleLinear().domain([, ]).range([0, ]);
const = d3.scaleLinear().domain([0, 1]).range([, 0]);
const = d3.line()
.x( => (.start))
.y( => (.value));
.append('path')
.datum()
.attr('class', 'line')
.attr('d', );
}
// Re-render chart when viewport changes:
(() => [., .],
() => (., ., .)
);
(() => {
(., ., .);
});
</script>
<style lang="scss" scoped>
.root {
width: 100%;
height: 100%;
position: absolute;
inset: 0;
}
:deep(.line) {
fill: none;
stroke: var(--color-1);
stroke-width: 2px;
}
</style>