Menu

Calendar (one cake per month)Edit

2018-04-012018-04-022018-04-032018-04-042018-04-052018-04-062018-04-072018-04-082018-04-092018-04-102018-04-112018-04-122018-04-132018-04-142018-04-152018-04-162018-04-172018-04-182018-04-192018-04-202018-04-212018-04-222018-04-232018-04-242018-04-252018-04-262018-04-272018-04-282018-04-292018-04-30
2018-07-012018-07-022018-07-032018-07-042018-07-052018-07-062018-07-072018-07-082018-07-092018-07-102018-07-112018-07-122018-07-132018-07-142018-07-152018-07-162018-07-172018-07-182018-07-192018-07-202018-07-212018-07-222018-07-232018-07-242018-07-252018-07-262018-07-272018-07-282018-07-292018-07-302018-07-31

Another small multiple example that generates the full date range for that month and puts each month inside its own div.

<script>
  import { LayerCake, ScaledSvg } from 'layercake';
  import { nest } from 'd3-collection';
  import { scaleQuantize } from 'd3-scale';

  import CalendarMonth from './_components/CalendarMonth.svelte';

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

  const monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ];

  const datesTransformed = dates.map(row => {
    row.date = new Date(row.timestring);
    return row;
  });

  const gutter = 10;
  const seriesColors = ['#fff5cc', '#ffeba9', '#ffe182', '#ffd754', '#ffcc00'];

  /* --------------------------------------------
   * Group by month then by date
   */
  const byMonthByDate = nest()
    .key(d => d.date.getUTCMonth())
    .key(d => d.timestring.split('T')[0])
    .entries(datesTransformed);

  const sortedData = byMonthByDate.sort((a, b) => a.key - b.key);
</script>

{#each sortedData as month, i}
  <div
    class="chart-container"
    style="width:calc({100 / sortedData.length}% - {gutter}px);{i === 0
      ? `margin-right:${gutter * 2}px`
      : ''}"
    data-month={monthNames[+month.key]}
  >
    <LayerCake
      ssr
      percentRange
      padding={{ top: 1, right: 1, bottom: 1, left: 1 }}
      x="key"
      z={d => d.values.length}
      zScale={scaleQuantize()}
      zRange={seriesColors}
      data={month.values}
    >
      <ScaledSvg>
        <CalendarMonth calcCellSize={() => 100 / 7} />
      </ScaledSvg>
    </LayerCake>
  </div>
{/each}

<style>
  /*
    The wrapper div needs to have an explicit width and height in CSS.
    It can also be a flexbox child or CSS grid element.
    The point being it needs dimensions since the <LayerCake> element will
    expand to fill it.
    The width is being set inline-below.
  */
  .chart-container {
    --margin-top: 25px;
    display: inline-block;
    position: relative;
    vertical-align: top;
    height: calc(250px - var(--margin-top));
    margin-top: var(--margin-top);
  }
  .chart-container:before {
    content: attr(data-month);
    position: absolute;
    top: 0;
    left: 0;
    transform: translate(0, -100%);
  }
</style>