Menu

Column annotatedEdit

1979
1980
1981
1982
1983
0
5
10
15
Example text...

Since we want an ordinal x-axis and Layer Cake defaults to a linear scale, pass in a custom scale to xScale with a few formatting options. Set the y-scale to always start at 0 so you don't show misleading differences between groups.

Since it's tricky to server-side render circles in SVG, this example uses a second <LayerCake> component for the arrow, which renders client-side and uses the position='absolute' prop to make sure the two cakes are super-imposed on one another.

For the annotation arrowhead, note that you may need to provide an explicit link to your SVG marker id, such as in ./_components/Arrows.svelte using window.location.href.

<script>
  import { LayerCake, Svg, ScaledSvg, Html } from 'layercake';
  import { scaleBand } from 'd3-scale';

  import Column from './_components/Column.svelte';
  import AxisX from './_components/AxisX.percent-range.html.svelte';
  import AxisY from './_components/AxisY.percent-range.html.svelte';
  import Annotations from './_components/Annotations.html.svelte';
  import Arrows from './_components/Arrows.svelte';
  import ArrowheadMarker from './_components/ArrowheadMarker.svelte';

  // This example loads csv data as json using @rollup/plugin-dsv
  import data from './_data/groups.csv';

  const xKey = 'year';
  const yKey = 'value';

  const annotations = [
    {
      text: 'Example text...',
      top: '18%',
      left: '30%',
      arrows: [{
        clockwise: false, // true or false, defaults to true
        source: {
          anchor: 'left-bottom', // can be `{left, middle, right},{top-middle-bottom}`
          dx: -2,
          dy: -7
        },
        target: {
          x: '28%',
          y: '75%'
        }
      },
      {
        source: {
          anchor: 'right-bottom',
          dy: -7,
          dx: 5
        },
        target: {
          x: '68%',
          y: '48%'
        }
      }]
    }
  ];

  data.forEach(d => {
    d[yKey] = +d[yKey];
  });
</script>

<style>
  .chart-container {
    width: 100%;
    height: 400px;
    position: relative;
  }
</style>

<div class="chart-container">
  <LayerCake
    ssr
    percentRange
    position='absolute'
    padding={{ top: 0, right: 0, bottom: 20, left: 20 }}
    x={xKey}
    y={yKey}
    xScale={scaleBand().paddingInner(0.028).round(true)}
    xDomain={['1979', '1980', '1981', '1982', '1983']}
    yDomain={[0, null]}
    {data}
  >
    <ScaledSvg>
      <Column/>
    </ScaledSvg>

    <Html>
      <AxisX
        gridlines={false}
      />
      <AxisY
        ticks={4}
        gridlines={false}
      />
      <Annotations {annotations}/>
    </Html>
  </LayerCake>

  <!--
    Add a second cake for the arrows that is rendered once the page is loaded
    since the arrows are hard to draw within the viewbox
  -->
  <LayerCake
    position='absolute'
    padding={{ top: 0, right: 0, bottom: 20, left: 20 }}
    x={xKey}
    y={yKey}
    xScale={scaleBand().paddingInner(0.028).round(true)}
    xDomain={['1979', '1980', '1981', '1982', '1983']}
    yDomain={[0, null]}
    {data}
  >
    <Svg>
      <svelte:fragment slot="defs">
        <ArrowheadMarker/>
      </svelte:fragment>
      <Arrows {annotations}/>
    </Svg>
  </LayerCake>
</div>