119 lines
4.2 KiB
Svelte
119 lines
4.2 KiB
Svelte
<!--
|
|
@component
|
|
Generates an SVG y-axis. This component is also configured to detect if your y-scale is an ordinal scale. If so, it will place the tickMarks in the middle of the bandwidth.
|
|
-->
|
|
<script>
|
|
import { getContext } from 'svelte';
|
|
|
|
const { xRange, yScale, width } = getContext('LayerCake');
|
|
|
|
/** @type {Boolean} [tickMarks=false] - Show marks next to the tick label. */
|
|
export let tickMarks = false;
|
|
|
|
/** @type {String} [labelPosition='even'] - Whether the label sits even with its value ('even') or sits on top ('above') the tick mark. Default is 'even'. */
|
|
export let labelPosition = 'even';
|
|
|
|
/** @type {Boolean} [snapBaselineLabel=false] - When labelPosition='even', adjust the lowest label so that it sits above the tick mark. */
|
|
export let snapBaselineLabel = false;
|
|
|
|
/** @type {Boolean} [gridlines=true] - Show gridlines extending into the chart area. */
|
|
export let gridlines = true;
|
|
|
|
/** @type {Number} [tickMarkLength=undefined] - The length of the tick mark. If not set, becomes the length of the widest tick. */
|
|
export let tickMarkLength = undefined;
|
|
|
|
/** @type {Function} [format=d => d] - A function that passes the current tick value and expects a nicely formatted value in return. */
|
|
export let format = d => d;
|
|
|
|
/** @type {Number|Array|Function} [ticks=4] - If this is a number, it passes that along to the [d3Scale.ticks](https://github.com/d3/d3-scale) function. If this is an array, hardcodes the ticks to those values. If it's a function, passes along the default tick values and expects an array of tick values in return. */
|
|
export let ticks = 4;
|
|
|
|
/** @type {Number} [tickGutter=0] - The amount of whitespace between the start of the tick and the chart drawing area (the xRange min). */
|
|
export let tickGutter = 2;
|
|
|
|
/** @type {Number} [dx=0] - Any optional value passed to the `dx` attribute on the text label. */
|
|
export let dx = 0;
|
|
|
|
/** @type {Number} [dy=0] - Any optional value passed to the `dy` attribute on the text label. */
|
|
export let dy = 0;
|
|
|
|
/** @type {Number} [charPixelWidth=7.25] - Used to calculate the widest label length to offset labels. Adjust if the automatic tick length doesn't look right because you have a bigger font (or just set `tickMarkLength` to a pixel value). */
|
|
export let charPixelWidth = 7.25;
|
|
|
|
$: isBandwidth = typeof $yScale.bandwidth === 'function';
|
|
|
|
$: tickVals = Array.isArray(ticks)
|
|
? ticks
|
|
: isBandwidth
|
|
? $yScale.domain()
|
|
: typeof ticks === 'function'
|
|
? ticks($yScale.ticks())
|
|
: $yScale.ticks(ticks);
|
|
|
|
function calcStringLength(sum, val) {
|
|
if (val === ',' || val === '.') return sum + charPixelWidth * 0.5;
|
|
return sum + charPixelWidth;
|
|
}
|
|
|
|
$: tickLen =
|
|
tickMarks === true
|
|
? labelPosition === 'above'
|
|
? tickMarkLength ?? widestTickLen
|
|
: tickMarkLength ?? 6
|
|
: 0;
|
|
|
|
$: widestTickLen = Math.max(
|
|
10,
|
|
Math.max(...tickVals.map(d => format(d).toString().split('').reduce(calcStringLength, 0)))
|
|
);
|
|
|
|
$: x1 = -tickGutter - (labelPosition === 'above' ? widestTickLen : tickLen);
|
|
$: y = isBandwidth ? $yScale.bandwidth() / 2 : 0;
|
|
|
|
$: maxTickValPx = Math.max(...tickVals.map($yScale));
|
|
</script>
|
|
|
|
<g class="axis y-axis">
|
|
{#each tickVals as tick (tick)}
|
|
{@const tickValPx = $yScale(tick)}
|
|
<g class="tick tick-{tick}" transform="translate({$xRange[0]}, {tickValPx})">
|
|
{#if gridlines === true}
|
|
<line class="gridline" {x1} x2={$width} y1={y} y2={y}></line>
|
|
{/if}
|
|
{#if tickMarks === true}
|
|
<line class="tick-mark" {x1} x2={x1 + tickLen} y1={y} y2={y}></line>
|
|
{/if}
|
|
<text
|
|
x={x1}
|
|
{y}
|
|
dx={dx + (labelPosition === 'even' ? -3 : 0)}
|
|
text-anchor={labelPosition === 'above' ? 'start' : 'end'}
|
|
dy={dy +
|
|
(labelPosition === 'above' || (snapBaselineLabel === true && tickValPx === maxTickValPx)
|
|
? -3
|
|
: 4)}>{format(tick)}</text
|
|
>
|
|
</g>
|
|
{/each}
|
|
</g>
|
|
|
|
<style>
|
|
.tick {
|
|
font-size: 11px;
|
|
}
|
|
|
|
.tick line {
|
|
stroke: #aaa;
|
|
}
|
|
.tick .gridline {
|
|
stroke-dasharray: 2;
|
|
}
|
|
|
|
.tick text {
|
|
fill: #666;
|
|
}
|
|
|
|
.tick.tick-0 line {
|
|
stroke-dasharray: 0;
|
|
}
|
|
</style> |