diff --git a/docs/src/content/components/GeoContext.md b/docs/src/content/components/GeoContext.md
index f7b2ce3e0..6e780cab0 100644
--- a/docs/src/content/components/GeoContext.md
+++ b/docs/src/content/components/GeoContext.md
@@ -12,3 +12,15 @@ related: [Chart]
## Playground
+
+## Geojson Preview
+
+
+
+## Topojson Preview
+
+
+
+## Shapefile Preview
+
+
diff --git a/docs/src/content/components/LineChart.md b/docs/src/content/components/LineChart.md
index 692dfda7b..50d7a3193 100644
--- a/docs/src/content/components/LineChart.md
+++ b/docs/src/content/components/LineChart.md
@@ -13,6 +13,40 @@ related: [Chart, Spline]
+### Performance Wide Data
+
+> Wide data (property per series)
+
+
+
+### Performance Wide Data Processed
+
+> Wide data (property per series). Pre-processed before passed to LineChart
+
+
+
+### Performance Series Arrays
+
+> Array per series, each with `x` / `y` items
+
+
+
+### Performance Dimension Arrays
+
+> Individual arrays per dimension, similar to uplot
+
+
+
+### Performance Dimension Arrays Processed
+
+> Individual arrays per dimension, similar to uplot. Pre-processed before passed to LineChart
+
+
+
+### Performance Streaming
+
+
+
+
+
+
+
+
+ {/if}
+
+
+
+
+ {#if geojson?.features}
+ {#each geojson?.features as feature}
+
+ {/each}
+ {/if}
+
+
+
+ {#snippet children({ data })}
+
+ {#each Object.entries(data.properties) as [key, value]}
+
+ {/each}
+
+ {/snippet}
+
+ {/snippet}
+
+ {:else}
+ Please enter input below
+ {/if}
+
+
+
+ Input
+ Parsed
+
+
+ {#if selectedTab === 'input'}
+
+ {:else if selectedTab === 'geojson'}
+
+ {/if}
+
diff --git a/docs/src/examples/GeoContext/shapefile-preview.svelte b/docs/src/examples/GeoContext/shapefile-preview.svelte
new file mode 100644
index 000000000..1ac87242a
--- /dev/null
+++ b/docs/src/examples/GeoContext/shapefile-preview.svelte
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if geojson}
+
+
+
+
+
+ {:else}
+ Please specify a file
+ {/if}
+
+
diff --git a/docs/src/examples/GeoContext/topojson-preview.svelte b/docs/src/examples/GeoContext/topojson-preview.svelte
new file mode 100644
index 000000000..d16e1f140
--- /dev/null
+++ b/docs/src/examples/GeoContext/topojson-preview.svelte
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
+ {#if geojson}
+
+ {#snippet children({ context })}
+ {#if projection === geoMercator && serviceUrl}
+
+
+
+
+
+
+
+ {/if}
+
+
+
+
+ {#if geojson?.features}
+ {#each geojson.features as feature}
+
+ {/each}
+ {/if}
+
+
+
+ {#snippet children({ data })}
+
+ {#each Object.entries(data.properties) as [key, value]}
+
+ {/each}
+
+ {/snippet}
+
+ {/snippet}
+
+ {:else}
+ Please enter input below
+ {/if}
+
+
+
+ Input
+ TopoJSON
+ GeoJSON
+
+
+
+ {#if selectedTab === 'input'}
+
+ {:else if selectedTab === 'topojson'}
+
+ {:else if selectedTab === 'geojson'}
+
+
+ {/if}
+
+
diff --git a/docs/src/examples/LineChart/perf-dimension-arrays-processed.svelte b/docs/src/examples/LineChart/perf-dimension-arrays-processed.svelte
new file mode 100644
index 000000000..99cfd26b8
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-dimension-arrays-processed.svelte
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Single
+ Series
+
+
+
+ {#key chartProps}
+ {#if example === 'single'}
+
+ {#if show}
+ d[0]}
+ y={(d) => d[1]}
+ props={chartProps}
+ brush
+ profile
+ />
+ {/if}
+
+ {:else if example === 'series'}
+
+ {#if show}
+ d[0]}
+ y={(d) => d[1]}
+ series={[
+ {
+ key: 'cpu',
+ data: chartData.cpu,
+ color: 'var(--color-danger)'
+ },
+ {
+ key: 'ram',
+ data: chartData.ram,
+ color: 'var(--color-warning)'
+ },
+ {
+ key: 'tcp',
+ data: chartData.tcp,
+ color: 'var(--color-success)'
+ }
+ ]}
+ props={chartProps}
+ brush
+ profile
+ />
+ {/if}
+
+ {/if}
+ {/key}
+
+
+ data: {format(data.cpu.length)} points
+
diff --git a/docs/src/examples/LineChart/perf-dimension-arrays.svelte b/docs/src/examples/LineChart/perf-dimension-arrays.svelte
new file mode 100644
index 000000000..d8eff21df
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-dimension-arrays.svelte
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Single
+ Series
+
+
+
+ {#key chartProps}
+ {#if example === 'single'}
+
+ {#if show}
+ d[0]}
+ y={(d) => d[1]}
+ props={chartProps}
+ brush
+ profile
+ />
+ {/if}
+
+ {:else if example === 'series'}
+
+
+ {#if show}
+ d[0]}
+ y={(d) => d[1]}
+ series={[
+ {
+ key: 'cpu',
+ data: zip(data.date, data.cpu),
+ color: 'var(--color-danger)'
+ },
+ {
+ key: 'ram',
+ data: zip(data.date, data.ram),
+ color: 'var(--color-warning)'
+ },
+ {
+ key: 'tcp',
+ data: zip(data.date, data.tcp),
+ color: 'var(--color-success)'
+ }
+ ]}
+ props={chartProps}
+ brush
+ profile
+ />
+ {/if}
+
+ {/if}
+ {/key}
+
+
+ data: {format(data.cpu.length)} points
+
diff --git a/docs/src/examples/LineChart/perf-series-arrays.svelte b/docs/src/examples/LineChart/perf-series-arrays.svelte
new file mode 100644
index 000000000..f36ab6266
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-series-arrays.svelte
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Single
+ Series
+
+
+
+ {#key chartProps}
+ {#if example === 'single'}
+
+ {#if show}
+
+ {/if}
+
+ {:else if example === 'series'}
+
+ {#if show}
+
+ {/if}
+
+ {/if}
+ {/key}
+
+
+ data: {format(data.cpu.length)} points
+
diff --git a/docs/src/examples/LineChart/perf-streaming.svelte b/docs/src/examples/LineChart/perf-streaming.svelte
new file mode 100644
index 000000000..3c1b7da10
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-streaming.svelte
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if show && chartData.length}
+
+ {/if}
+
+
+ data: {format(chartData.length)} points
+
diff --git a/docs/src/examples/LineChart/perf-wide-data-processed.svelte b/docs/src/examples/LineChart/perf-wide-data-processed.svelte
new file mode 100644
index 000000000..c338d37c8
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-wide-data-processed.svelte
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Single
+ Series
+
+
+
+ {#key chartProps}
+ {#if example === 'single'}
+
+ {#if show}
+
+ {/if}
+
+ {:else if example === 'series'}
+
+ {#if show}
+
+ {/if}
+
+ {/if}
+ {/key}
+
+
+ data: {format(chartData.length)} points
+
diff --git a/docs/src/examples/LineChart/perf-wide-data.svelte b/docs/src/examples/LineChart/perf-wide-data.svelte
new file mode 100644
index 000000000..59fba7b1c
--- /dev/null
+++ b/docs/src/examples/LineChart/perf-wide-data.svelte
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Yes
+ No
+
+
+
+
+
+ Single
+ Series
+
+
+
+ {#key chartProps}
+ {#if example === 'single'}
+
+ {#if show}
+ 100 - d.idl} props={chartProps} brush profile />
+ {/if}
+
+ {:else if example === 'series'}
+
+ {#if show}
+ 100 - d.idl, color: 'var(--color-danger)' },
+ {
+ key: 'ram',
+ value: (d) => (100 * d.writ) / (d.writ + d.used),
+ color: 'var(--color-warning)'
+ },
+ { key: 'tcp', value: (d) => d.send, color: 'var(--color-success)' }
+ ]}
+ props={chartProps}
+ brush
+ profile
+ />
+ {/if}
+
+ {/if}
+ {/key}
+
+
+ data: {format(data.length)} points
+
diff --git a/docs/src/lib/data.remote.ts b/docs/src/lib/data.remote.ts
index ec43400d4..d30a88745 100644
--- a/docs/src/lib/data.remote.ts
+++ b/docs/src/lib/data.remote.ts
@@ -3,7 +3,8 @@ import { parse, sortFunc } from '@layerstack/utils';
import { ascending, flatGroup, max, mean, min } from 'd3-array';
import { csvParse, autoType } from 'd3-dsv';
-import { prerender, getRequestEvent } from '$app/server';
+import { prerender, getRequestEvent, query } from '$app/server';
+import { z } from 'zod';
import type { PenguinsData } from '$static/data/examples/penguins.js';
import type { AppleStockData } from '$static/data/examples/date/apple-stock.js';
@@ -190,3 +191,58 @@ export const getForceGroupDots = prerender(async () => {
}[];
return data;
});
+
+export const getWideData = prerender(async () => {
+ const { fetch } = getRequestEvent();
+ const data = (await fetch('/data/examples/bench/wide_data/data.json').then((r) => r.json())) as {
+ epoch: number;
+ idl: number;
+ recv: number;
+ send: number;
+ writ: number;
+ used: number;
+ free: number;
+ }[];
+ return data;
+});
+
+export const getDimensionArrays = prerender(async () => {
+ const { fetch } = getRequestEvent();
+ const data = (await fetch('/data/examples/bench/dimension_arrays/data.json').then((r) =>
+ r.json()
+ )) as {
+ date: number[];
+ cpu: number[];
+ ram: number[];
+ tcp: number[];
+ };
+ return data;
+});
+
+export const getSeriesArrays = prerender(async () => {
+ const { fetch } = getRequestEvent();
+ const data = (await fetch('/data/examples/bench/series_arrays/data.json').then((r) =>
+ r.json()
+ )) as {
+ cpu: {
+ x: Date;
+ y: number;
+ }[];
+ ram: {
+ x: Date;
+ y: number;
+ }[];
+ tcp: {
+ x: Date;
+ y: number;
+ }[];
+ };
+ return data;
+});
+
+export const getShapeData = query(z.string().nullable(), async (file) => {
+ if (!file) return null;
+ const { fetch } = getRequestEvent();
+ const geojson = await fetch(file).then((r) => r.json());
+ return geojson;
+});
\ No newline at end of file