Menu

AxisRadial.svelte component

Generates an SVG radial scale, useful for radar charts.

Param Default Required Description
lineLengthFactor number 1.1
no
How far to extend the lines from the circle's center. A value of 1 puts them at the circle's circumference.
labelPlacementFactor number 1.25
no
How far to place the labels from the circle's center. A value of 1 puts them at the circle's circumference.

Used in these examples:

<!--
  @component
  Generates an SVG radial scale, useful for radar charts.
 -->
<script>
  import { getContext } from 'svelte';

  const { width, height, xScale, extents, config } = getContext('LayerCake');

  /**
   * @typedef {Object} Props
   * @property {number} [lineLengthFactor=1.1] - How far to extend the lines from the circle's center. A value of `1` puts them at the circle's circumference.
   * @property {number} [labelPlacementFactor=1.25] - How far to place the labels from the circle's center. A value of `1` puts them at the circle's circumference.
   */

  /** @type {Props} */
  let { lineLengthFactor = 1.1, labelPlacementFactor = 1.25 } = $props();

  let max = $derived($xScale(Math.max(...$extents.x)));

  let lineLength = $derived(max * lineLengthFactor);
  let labelPlacement = $derived(max * labelPlacementFactor);

  let angleSlice = $derived((Math.PI * 2) / $config.x.length);

  /** @param {number} total
   *  @param {number} i */
  function anchor(total, i) {
    if (i === 0 || i === total / 2) {
      return 'middle';
    } else if (i < total / 2) {
      return 'start';
    }
    return 'end';
  }
</script>

<g transform="translate({$width / 2}, {$height / 2})">
  <circle cx="0" cy="0" r={max} stroke="#ccc" stroke-width="1" fill="#CDCDCD" fill-opacity="0.1"
  ></circle>
  <circle cx="0" cy="0" r={max / 2} stroke="#ccc" stroke-width="1" fill="none"></circle>

  {#each $config.x as label, i}
    {@const thisAngleSlice = angleSlice * i - Math.PI / 2}
    <line
      x1="0"
      y1="0"
      x2={lineLength * Math.cos(thisAngleSlice)}
      y2={lineLength * Math.sin(thisAngleSlice)}
      stroke="#ccc"
      stroke-width="1"
      fill="none"
    >
    </line>
    <text
      text-anchor={anchor($config.x.length, i)}
      dy="0.35em"
      font-size="12px"
      transform="translate({labelPlacement * Math.cos(thisAngleSlice)}, {labelPlacement *
        Math.sin(thisAngleSlice)})">{label}</text
    >
  {/each}
</g>