はじめに
SvelteのコンポーネントライブラリーであるLayerChartを触ってみようと思い立ち、触ってみましたので、その記録を記したいと思います
LayerChartは、Svelte向けのデータ視覚化ライブラリーであり、折れ線グラフや棒グラフなど、データの視覚化に必要なコンポーネント群を提供しています
単体での利用は可能ですが、Svelte UXというUIコンポーネントライブラリのインストール時にLayerChartのオプションがありますので、今回はそちらを利用してすぐに触ってみようという形で進めました
インストール
※パッケージマネージャーにpnpmを利用していますが、npmに読み替えてもOKです
pnpm create svelte-ux@latest
これで対話型のインストールが始まります
テンプレート選択時にLayerChartがありますので、そちらを選択して進めます
最後にSvelte5使うかを聞かれますが今回は4のまま進めます
(既にstableでしたが追いついていないのでした、次の記事からは5でいきたい気持ちです)
ローカルサーバーを起動すると以下のような画面が出ます
若干崩れていますが、 TaiwindCSSなども同時にセットアップしてくれています
ちなみに、上記は実はCSSの設定が壊れていて、手直しすると以下のような感じになります
こちらは修正のPRを送ってマージされたので、以下のデザインになると思います
LayerChartのコンポーネントを使ってみる
せっかくなのでGeo系のコンポーネントを使ってみようとしたのですが、その前に簡単な例をやってみようということで、Examplesの Cartesian & Polarの先頭にある、Arcの例をそのまま追加してみます
<script lang="ts">
import { Arc, Chart, Svg, Group, LinearGradient, Text } from 'layerchart';
import { RangeField } from 'svelte-ux';
let value = 50;
</script>
<main class="p-2">
<div class="mb-2">
<RangeField label="Value" bind:value />
</div>
<div class="h-[120px] p-4 border rounded">
<Chart>
<Svg center>
<Group y={16}>
<LinearGradient class="from-secondary to-primary" let:url>
<Arc
{value}
range={[-120, 120]}
outerRadius={60}
innerRadius={50}
cornerRadius={5}
spring
let:value
fill={url}
track={{ class: 'fill-none stroke-surface-content/10' }}
>
<Text
value={Math.round(value) + '%'}
textAnchor="middle"
verticalAnchor="middle"
class="text-3xl tabular-nums"
/>
</Arc>
</LinearGradient>
</Group>
</Svg>
</Chart>
</div>
</main>
左のメニューに追加して、見てみるとこんな感じで出来ています(グラデーションがかかるはずでしたが、色の設定をちゃんとしていないのでうまくいってないっぽいですが)
Svelte UXのRangeFieldコンポーネントとの相性も良いですね
こんな感じで大量のコンポーネントが用意されていますが、中身を見るとD3を利用しているものが多そうです
D3をSvelteでいい感じに使えるライブラリーみたいなイメージでしょうか?
Geoの例
最後にGeoのコンポーネントの例をやってみます
まず、d3-geoの追加が必要です
pnpm add d3-geo
例ではtopojson-clientも利用していたので追加しています
pnpm add topojson-client
型定義も入れておきます
pnpm add -D @types/d3-geo
pnpm add -D @types/topojson-client
pnpm add -D @types/topojson-specification
データ読み込み箇所
import type { GeometryCollection, Topology } from 'topojson-specification';
import pageSource from './+page.svelte?raw';
export async function load() {
return {
geojson: (await fetch('https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json').then((r) =>
r.json()
)) as Topology<{
states: GeometryCollection<{ name: string }>;
}>,
meta: {
pageSource,
related: ['examples/ZoomableTileMap']
}
};
}
GeoTile使用例
<script lang="ts">
import { geoMercator } from 'd3-geo';
import { feature } from 'topojson-client';
import { Canvas, Chart, GeoPath, GeoTile } from 'layerchart';
export let data;
const states = feature(data.geojson, data.geojson.objects.states);
$: filteredStates = {
...states,
features: states.features.filter(
(d) => Number(d.id) < 60 && d.properties.name !== 'Alaska' && d.properties.name !== 'Hawaii'
)
};
let zoomDelta = 0;
let selectedFeature: typeof filteredStates | (typeof filteredStates.features)[0];
$: selectedFeature = filteredStates;
</script>
<main class="p-2">
<div class="h-[600px]">
<Chart
geo={{
projection: geoMercator,
fitGeojson: selectedFeature
}}
>
<Canvas>
<GeoTile
url={(x, y, z) => {
return `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
}}
{zoomDelta}
/>
</Canvas>
<Canvas>
<GeoPath geojson={filteredStates} class="stroke-black/20" />
</Canvas>
</Chart>
</div>
</main>
こんな感じで地図が出ます
(LayerChartのExampleをそのまま利用したので、場所はアメリカです)
タイルURLの指定の仕方がちょっと分かりづらくてハマりました
感想
触ってみた感想ですが、D3をラップして使いやすくしているような感じを受けました
グラフ描画が必要であれば、選択肢としてなかなか良いのではないかと思います
Geo系のコンポーネントは個人的には使いづらくて、使い慣れているMaplibre GL JSの方が良いかも…と思いました