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, depending on your app structure, such as if you're using Sapper, 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.html.svelte';
  import AxisY from './components/AxisY.html.svelte';
  import Annotations from './components/Annotations.svelte';
  import Arrows from './components/Arrows.svelte';
  import ArrowheadDef from './components/ArrowheadDef.svelte';

  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: 100%;
    position: relative;
  }
</style>

<div class="chart-container">
  <LayerCake
    ssr={true}
    percentRange={true}
    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={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={data}
  >
    <Svg>
      <ArrowheadDef/>
      <Arrows {annotations}/>
    </Svg>
  </LayerCake>
</div>