Layer Cake

repository·main·Indexed 23 days ago

https://github.com/mhkeller/layercake

A headless visualization framework for Svelte designed to create reusable graphics. It provides structural scaffolding, coordinate mapping, and layout components (Svg, Canvas, Html, WebGL), while allowing developers to implement their own rendering logic via custom components and Svelte's getContext.

Tokens
8.9K
Snippets
39
Records
53
Agent score
77%

What's inside layercake

  1. How Layer Cake works (Core Concepts)

    main

    Layer Cake is a "headless" graphics framework for Svelte. Unlike high-level charting libraries, it does not provide pre-built charts (like scatter or bar charts). Instead, it provides the coordinate system, scales, and empty containers (layout components) to help you build your own custom layers.

    Key Mental Models:

    1. Custom Layers: All chart elements (axes, plots, annotations) are components you create within your own project. Layer Cake only provides the infrastructure.
    2. Data Extents: Layer Cake uses a flat array of objects to measure data extents. If your data is complex (e.g., multi-series), pass a flat array to the flatData prop so accessors can calculate scale extents correctly.
    3. Scale Logic:
      • For categorical scales (scaleBand, scalePoint, scaleOrdinal), Layer Cake uses the unique values in your data as the extent.
      • For continuous scales (e.g., scaleLinear), it uses the [min, max] values.
      • Y-Scale Inversion: For non-categorical y-scales, Layer Cake defaults the range to [height, 0] to match the DOM coordinate system, making drawing easier.
  2. Check Svelte version compatibility

    main

    Layer Cake's compatibility depends on the version you are using:

    • Svelte 5: Supported by the current version of Layer Cake.
    • Svelte 3 or 4: You must use version 8.4.4 of Layer Cake.

    Note that current examples use Svelte Rune syntax.

  3. Use xGet and yGet for cleaner coordinate mapping

    main

    To avoid the verbose syntax of $xScale($x(d)), LayerCake provides xGet(d) and yGet(d) functions. These functions combine the accessor and the scale into a single call, returning the scaled coordinate directly. This makes components more reusable because they rely on the context accessors rather than hardcoded data keys.

    Equivalent operations: $xScale($x(d)) is equivalent to $xGet(d).

    <script>
    	import { getContext } from 'svelte';
    
    	const { data, xGet, yGet } = getContext('LayerCake');
    </script>
    
    {#each $data as d}
    	<circle cx={$xGet(d)} cy={$yGet(d)} r="5" fill="#000" />
    {/each}
  4. Use flatData for non-flat datasets

    main

    If your data prop is not a flat array of objects (e.g., nested multi-series data or GeoJSON), use the flatData prop to provide a flat version of the data. LayerCake uses flatData exclusively to calculate the extents (min/max) for the scales, but it will still pass your original data prop to the child components.

    <script>
    	const data = [{ key: 'apples', values: [{ month: '2015-03-01', value: 3840 }] }];
    	const flatData = [{ month: '2015-04-01', value: 3840, group: 'apples' }];
    </script>
    
    <LayerCake x="month" y="value" {data} {flatData}>
    	<!-- Components go here -->
    </LayerCake>
  5. Use the debug feature to inspect scales and domains

    main

    If your chart is not displaying correctly, you can enable the debug prop on the <LayerCake> component to print diagnostic information to the console. This information includes:

    1. The bounding box dimensions of your chart container.
    2. The scales currently in use, including:
      • The accessor function or string key.
      • The scale type.
      • The domain.
      • The range.

    This is particularly useful for identifying if CSS is failing to size the parent container or if data issues (like undefined or NaN values) are causing incorrect extent calculations for the domain.

    <LayerCake
      debug={true}
    
      <!-- Can also be set simply with this Svelte shorthand -->
      debug
    >
  6. Create custom layer components using getContext

    main

    To draw elements, create your own Svelte components and access the Layer Cake state using Svelte's getContext('LayerCake').

    Everything returned from the context is a Svelte store, so you must prefix them with $ in your template. You can access:

    • data: The raw data array.
    • x, y, z, r: Accessor functions for the dimensions.
    • xScale, yScale, zScale, rScale: The D3 scales.
    • xGet, yGet: Combined accessor and scale functions (e.g., $xGet(d) is equivalent to $xScale($x(d)))

    Example: A Scatter Layer

    <script>
    	import { getContext } from 'svelte';
    
    	// Access the context using the 'LayerCake' keyword
    	const { data, xGet, yGet } = getContext('LayerCake');
    
    	// Customizable defaults via props
    	let { fill = '#000', r = 5 } = $props();
    </script>
    
    <g>
    	{#each $data as d}
    		<circle cx={$xGet(d)} cy={$yGet(d)} {fill} {r} />
    	{/each}
    </g>
    <script>
    	// Import the getContext function from svelte
    	import { getContext } from 'svelte';
    
    	// Access the context using the 'LayerCake' keyword
    	// Grab some helpful functions
    	const { data, xGet, yGet } = getContext('LayerCake');
    
    	// Customizable defaults
    	let { fill = '#000', r = 5 } = $props();
    </script>
    
    <g>
    	{#each $data as d}
    		<circle cx={$xGet(d)} cy={$yGet(d)} {fill} {r} />
    	{/each}
    </g>
  7. Access computed context values in LayerCake

    main

    LayerCake computes additional properties based on your input props and exposes them via Svelte context. You can access these values in two ways:

    1. As slot props: Using the let: keyword on the <LayerCake> component.
    2. Via getContext: Using Svelte's getContext('LayerCake') inside child components.

    Commonly accessed values include scales (xScale, yScale), dimensions (width, height), and the data itself (data).

    <LayerCake let:xScale let:yGet let:containerWidth>
    	<!-- Components... -->
    </LayerCake>
  8. Configure Server-Side Rendering (SSR)

    main

    To render charts on the server, set ssr={true}. Because container dimensions are unknown during SSR, you should use this in conjunction with:

    1. percentRange={true}: Sets scale ranges to [0, 100] (or [100, 0] for y) to create a percent coordinate system.
    2. ScaledSvg components or HTML components using percentage scales.

    You can also set position='absolute' to stack an SSR-rendered layer underneath a client-side interactive layer.