@swr-data-lab/components 1.12.5 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ChartList/ChartList.mdx +13 -0
- package/src/ChartList/ChartList.stories.svelte +48 -0
- package/src/ChartList/ChartList.svelte +117 -0
- package/src/ChartList/index.ts +2 -0
- package/src/Intro.mdx +2 -2
- package/src/app.d.ts +1 -1
- package/src/index.js +3 -0
- package/src/maplibre/VectorLayer/VectorLayer.svelte +6 -2
- package/src/utils/formatDate.js +13 -13
- package/src/utils/formatNumber.js +5 -5
- package/src/utils/getColorsBetween.js +11 -11
- package/src/utils/getComparisonDiffs.js +5 -5
- package/src/utils/getLaenderFromTopo.js +21 -21
- package/src/utils/getLaenderNicenameFromAgs.js +19 -19
- package/src/utils/isSvelteComponent.js +1 -1
- package/src/utils/prepareSophoraModel.js +32 -26
- package/src/utils/scrollIntoViewWithOffset.js +3 -3
- package/src/utils/slugify.ts +8 -8
- package/src/utils/topoToGeo.js +2 -2
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Story, Meta, Primary, Controls, Stories } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
import * as ChartListStories from './ChartList.stories.svelte';
|
|
4
|
+
|
|
5
|
+
<Meta of={ChartListStories} />
|
|
6
|
+
|
|
7
|
+
# Chart List
|
|
8
|
+
|
|
9
|
+
Utility component for displaying a list of charts with associated embed URLs during development (typically on the `/` route of your Svelte project).
|
|
10
|
+
|
|
11
|
+
<Stories />
|
|
12
|
+
|
|
13
|
+
<Controls />
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import { within, expect } from 'storybook/test';
|
|
4
|
+
|
|
5
|
+
import DesignTokens from '../DesignTokens/DesignTokens.svelte';
|
|
6
|
+
|
|
7
|
+
import ChartList from './ChartList.svelte';
|
|
8
|
+
|
|
9
|
+
const { Story } = defineMeta({
|
|
10
|
+
title: 'Meta/ChartList',
|
|
11
|
+
component: ChartList
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const testCharts = [
|
|
15
|
+
{ title: 'Baden-Württemberg Loosers', slug: 'bw-loosers' },
|
|
16
|
+
{ title: 'Baden-Württemberg Winners', slug: 'bw-winners' },
|
|
17
|
+
{ title: 'Rheinland-Pfalz Loosers', slug: 'rp-loosers' },
|
|
18
|
+
{ title: 'Rheinland-Pfalz Winners', slug: 'rp-winners' }
|
|
19
|
+
];
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<Story
|
|
23
|
+
name="Default"
|
|
24
|
+
asChild
|
|
25
|
+
play={async ({ canvasElement, step }) => {
|
|
26
|
+
const canvas = within(canvasElement);
|
|
27
|
+
|
|
28
|
+
await step('Project title renders', async () => {
|
|
29
|
+
const titleEl = canvas.getByTestId('chartlist-project-title');
|
|
30
|
+
expect(titleEl).toHaveTextContent('Grafiken für p110: Wie sieht der Wald von morgen aus?');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await step('All chart list items render', async () => {
|
|
34
|
+
testCharts.forEach((c) => {
|
|
35
|
+
const el = canvas.getByText(c.title);
|
|
36
|
+
expect(el).toBeTruthy();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<DesignTokens>
|
|
42
|
+
<ChartList
|
|
43
|
+
baseUrl="https://static.datenhub.net/apps/p110_wald-klimawandel/main"
|
|
44
|
+
charts={testCharts}
|
|
45
|
+
project="p110: Wie sieht der Wald von morgen aus?"
|
|
46
|
+
/>
|
|
47
|
+
</DesignTokens>
|
|
48
|
+
</Story>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { dev } from '$app/environment';
|
|
3
|
+
|
|
4
|
+
type ProjectPrefix = 'p' | 't';
|
|
5
|
+
type ProjectIdentifier = `${ProjectPrefix}${number}: ${string}`;
|
|
6
|
+
|
|
7
|
+
interface ChartSpec {
|
|
8
|
+
title: string;
|
|
9
|
+
slug: string;
|
|
10
|
+
}
|
|
11
|
+
interface ChartListProps {
|
|
12
|
+
project?: ProjectIdentifier;
|
|
13
|
+
charts?: ChartSpec[];
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
let { project, charts, baseUrl }: ChartListProps = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<main>
|
|
20
|
+
<div class="inner">
|
|
21
|
+
<h1 data-testid="chartlist-project-title">Grafiken für {project}</h1>
|
|
22
|
+
{#if charts}
|
|
23
|
+
<table>
|
|
24
|
+
<thead>
|
|
25
|
+
<tr>
|
|
26
|
+
<th>Title</th>
|
|
27
|
+
{#if baseUrl}
|
|
28
|
+
<th>Embed URL</th>
|
|
29
|
+
{/if}
|
|
30
|
+
</tr>
|
|
31
|
+
</thead>
|
|
32
|
+
<tbody>
|
|
33
|
+
{#each charts as chart}
|
|
34
|
+
<tr>
|
|
35
|
+
<td>
|
|
36
|
+
<a href="./{chart.slug}{dev ? '' : '.html'}">{chart.title}</a>
|
|
37
|
+
</td>
|
|
38
|
+
{#if baseUrl}
|
|
39
|
+
<td>
|
|
40
|
+
<input type="text" value={`${baseUrl}/${chart.slug}.html`} />
|
|
41
|
+
</td>
|
|
42
|
+
{/if}
|
|
43
|
+
</tr>
|
|
44
|
+
{/each}
|
|
45
|
+
</tbody>
|
|
46
|
+
</table>
|
|
47
|
+
{/if}
|
|
48
|
+
</div>
|
|
49
|
+
</main>
|
|
50
|
+
|
|
51
|
+
<style>
|
|
52
|
+
:global(*) {
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
color: inherit;
|
|
57
|
+
}
|
|
58
|
+
main {
|
|
59
|
+
display: flex;
|
|
60
|
+
justify-content: center;
|
|
61
|
+
align-items: center;
|
|
62
|
+
flex-flow: column;
|
|
63
|
+
font-family: var(--swr-sans);
|
|
64
|
+
font-size: var(--fs-small-1);
|
|
65
|
+
max-width: 60rem;
|
|
66
|
+
margin: 0 auto;
|
|
67
|
+
}
|
|
68
|
+
.inner {
|
|
69
|
+
width: 100%;
|
|
70
|
+
border: 1px solid rgb(0, 0, 0);
|
|
71
|
+
}
|
|
72
|
+
h1 {
|
|
73
|
+
font-size: var(--fs-small-1);
|
|
74
|
+
width: 100%;
|
|
75
|
+
border-bottom: 1px solid black;
|
|
76
|
+
padding-bottom: 0.2em;
|
|
77
|
+
background-color: rgb(233, 238, 245);
|
|
78
|
+
}
|
|
79
|
+
table {
|
|
80
|
+
border-collapse: collapse;
|
|
81
|
+
border-spacing: 0;
|
|
82
|
+
width: 100%;
|
|
83
|
+
}
|
|
84
|
+
a {
|
|
85
|
+
display: block;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
88
|
+
th,
|
|
89
|
+
td,
|
|
90
|
+
h1 {
|
|
91
|
+
padding: 0.2em 0.4em;
|
|
92
|
+
text-align: left;
|
|
93
|
+
}
|
|
94
|
+
th {
|
|
95
|
+
border-bottom: 1px solid black;
|
|
96
|
+
}
|
|
97
|
+
tr {
|
|
98
|
+
border-bottom: 1px solid black;
|
|
99
|
+
&:last-child {
|
|
100
|
+
border-bottom: 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
input {
|
|
105
|
+
display: block;
|
|
106
|
+
width: 100%;
|
|
107
|
+
padding: 0.1em 0.3em;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
a:hover,
|
|
111
|
+
a:focus-visible {
|
|
112
|
+
text-decoration: underline;
|
|
113
|
+
}
|
|
114
|
+
a:last-child {
|
|
115
|
+
border-bottom: 0;
|
|
116
|
+
}
|
|
117
|
+
</style>
|
package/src/Intro.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Meta } from
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
2
|
|
|
3
3
|
<Meta title="About" />
|
|
4
4
|
|
|
5
5
|
# SWR Data Lab Components
|
|
6
6
|
|
|
7
|
-
Experimental component library for SWR Data Lab interactives.
|
|
7
|
+
Experimental component library for SWR Data Lab interactives.
|
package/src/app.d.ts
CHANGED
package/src/index.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
FillLayoutProps,
|
|
5
5
|
FillPaintProps,
|
|
6
6
|
LineLayoutProps,
|
|
7
|
+
CircleLayoutProps,
|
|
8
|
+
CirclePaintProps,
|
|
9
|
+
SymbolPaintProps,
|
|
10
|
+
SymbolLayoutProps,
|
|
7
11
|
LinePaintProps,
|
|
8
12
|
MapGeoJSONFeature,
|
|
9
13
|
MapLayerMouseEvent
|
|
@@ -22,8 +26,8 @@
|
|
|
22
26
|
visible?: boolean;
|
|
23
27
|
minZoom?: number;
|
|
24
28
|
maxZoom?: number;
|
|
25
|
-
paint?: LinePaintProps | FillPaintProps;
|
|
26
|
-
layout?: LineLayoutProps | FillLayoutProps;
|
|
29
|
+
paint?: LinePaintProps | FillPaintProps | CirclePaintProps | SymbolPaintProps;
|
|
30
|
+
layout?: LineLayoutProps | FillLayoutProps | CircleLayoutProps | SymbolLayoutProps;
|
|
27
31
|
hovered?: MapGeoJSONFeature | undefined;
|
|
28
32
|
selected?: MapGeoJSONFeature | undefined;
|
|
29
33
|
|
package/src/utils/formatDate.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { timeFormat } from
|
|
1
|
+
import { timeFormat } from 'd3-time-format';
|
|
2
2
|
|
|
3
3
|
const formats = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
4
|
+
dayMonthYear: '%-d.%-m.%Y',
|
|
5
|
+
dayMonth: '%-d.%-m.',
|
|
6
|
+
dayMonthYearShort: '%-d.%-m.%y',
|
|
7
|
+
dayMonthHourMinute: '%-d.%-m., %-H.%M Uhr',
|
|
8
|
+
dayMonthYearHourMinute: '%-d.%-m.%Y, %-H.%M Uhr',
|
|
9
|
+
hourMinuteSophora: '%-H:%M Uhr',
|
|
10
|
+
hourMinute: '%-H.%M'
|
|
11
|
+
};
|
|
12
12
|
|
|
13
|
-
const formatDate = ({ date, format =
|
|
14
|
-
|
|
15
|
-
}
|
|
13
|
+
const formatDate = ({ date, format = 'dayMonthYear' }) => {
|
|
14
|
+
return timeFormat(formats[format] || format)(new Date(date));
|
|
15
|
+
};
|
|
16
16
|
|
|
17
|
-
export default formatDate
|
|
17
|
+
export default formatDate;
|
|
@@ -2,12 +2,12 @@ import { formatLocale } from 'd3-format';
|
|
|
2
2
|
|
|
3
3
|
export const defaultFormat = ',.1f';
|
|
4
4
|
export const defaultLocale = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
decimal: ',',
|
|
6
|
+
thousands: ' ',
|
|
7
|
+
grouping: [3],
|
|
8
|
+
currency: ['', '€']
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export default formatNumber = ({ number, format = defaultFormat, locale = defaultLocale }) => {
|
|
12
|
-
|
|
12
|
+
return formatLocale(locale).format(format)(number);
|
|
13
13
|
};
|
|
@@ -9,17 +9,17 @@ import { range } from 'd3-array';
|
|
|
9
9
|
* @returns
|
|
10
10
|
*/
|
|
11
11
|
const getColorsBetween = (from, to, props = { n: 1, includeFromTo: false }) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
const step = 1 / (props.n + 1);
|
|
13
|
+
const fromColor = Color(from);
|
|
14
|
+
const toColor = Color(to);
|
|
15
|
+
const colorsBetween = range(1, props.n + 1)
|
|
16
|
+
.map((i) => fromColor.mix(toColor, i * step))
|
|
17
|
+
.map((c) => c.hex().toString());
|
|
18
|
+
if (props.includeFromTo) {
|
|
19
|
+
return [from, ...colorsBetween, to];
|
|
20
|
+
} else {
|
|
21
|
+
return colorsBetween;
|
|
22
|
+
}
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export default getColorsBetween;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const getComparisonDiffs = (a, b) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
return {
|
|
3
|
+
diff: a - b,
|
|
4
|
+
diffRel: (a / b - 1) * 100,
|
|
5
|
+
diffTag: a > b ? 'higher' : a === b ? 'equal' : 'smaller'
|
|
6
|
+
};
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export default getComparisonDiffs;
|
|
@@ -7,29 +7,29 @@ import { range } from 'd3-array';
|
|
|
7
7
|
* @returns geojson
|
|
8
8
|
*/
|
|
9
9
|
const getLaenderFromTopo = (topo) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const states = [];
|
|
11
|
+
const stateIds = range(1, 17).map((n) => String(n).padStart(2, '0'));
|
|
12
|
+
const key = Object.keys(topo.objects)[0];
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
stateIds.forEach((id) => {
|
|
15
|
+
const state = {
|
|
16
|
+
geometry: merge(
|
|
17
|
+
topo,
|
|
18
|
+
topo.objects[key].geometries.filter(
|
|
19
|
+
(g) => g.properties.id && g.properties.id.startsWith(id)
|
|
20
|
+
)
|
|
21
|
+
),
|
|
22
|
+
id,
|
|
23
|
+
type: 'Feature',
|
|
24
|
+
properties: { id }
|
|
25
|
+
};
|
|
26
|
+
states.push(state);
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
return {
|
|
30
|
+
type: 'FeatureCollection',
|
|
31
|
+
features: states
|
|
32
|
+
};
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export default getLaenderFromTopo;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
const map = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
2
|
+
'01': 'Schleswig-Holstein',
|
|
3
|
+
'02': 'Hamburg',
|
|
4
|
+
'03': 'Niedersachsen',
|
|
5
|
+
'04': 'Bremen',
|
|
6
|
+
'05': 'Nordrhein-Westfalen',
|
|
7
|
+
'06': 'Hessen',
|
|
8
|
+
'07': 'Rheinland-Pfalz',
|
|
9
|
+
'08': 'Baden-Württemberg',
|
|
10
|
+
'09': 'Bayern',
|
|
11
|
+
10: 'Saarland',
|
|
12
|
+
11: 'Berlin',
|
|
13
|
+
12: 'Brandenburg',
|
|
14
|
+
13: 'Mecklenburg-Vorpommern',
|
|
15
|
+
14: 'Sachsen',
|
|
16
|
+
15: 'Sachsen-Anhalt',
|
|
17
|
+
16: 'Thüringen'
|
|
18
|
+
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Get nicename for land ags
|
|
22
22
|
* @param {string} ags
|
|
23
23
|
* @returns {string} nicename
|
|
24
24
|
*/
|
|
25
|
-
const getLaenderNicenameFromAgs = (ags) => map[ags]
|
|
25
|
+
const getLaenderNicenameFromAgs = (ags) => map[ags];
|
|
26
26
|
|
|
27
|
-
export default getLaenderNicenameFromAgs
|
|
27
|
+
export default getLaenderNicenameFromAgs;
|
|
@@ -7,7 +7,7 @@ import { SvelteComponent } from 'svelte';
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const isSvelteComponent = (component) => {
|
|
10
|
-
|
|
10
|
+
return SvelteComponent.isPrototypeOf(component) || typeof component === 'function';
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export default isSvelteComponent;
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
const SELECTORS = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
2
|
+
showScrollUp: 'a.back-to-top',
|
|
3
|
+
showPlayerbar: '#playerbar',
|
|
4
|
+
showSharing: '.sharing',
|
|
5
|
+
showAuthors: '.meta-top .meta-authors',
|
|
6
|
+
allowZoom: 'meta[name=viewport]'
|
|
7
|
+
};
|
|
8
8
|
|
|
9
|
-
const IS_MOBILE = window.innerWidth < 768
|
|
9
|
+
const IS_MOBILE = window.innerWidth < 768;
|
|
10
10
|
|
|
11
11
|
const prepareSophoraModel = (config) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
console.log('###SWRDATA### updating dom with following config: ', config);
|
|
13
|
+
Object.entries(config).forEach(([k, v], _) => {
|
|
14
|
+
const element = document.querySelector(SELECTORS[k]);
|
|
15
|
+
// show/hide elements
|
|
16
|
+
if (k.startsWith('show')) {
|
|
17
|
+
if (
|
|
18
|
+
(v === 'none' || (v === 'mobile' && IS_MOBILE) || (v === 'desktop' && !IS_MOBILE)) &&
|
|
19
|
+
element
|
|
20
|
+
) {
|
|
21
|
+
element.style.display = 'none';
|
|
22
|
+
element.style.visibility = 'hidden';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// enable/disable zoom
|
|
26
|
+
if (k === 'allowZoom') {
|
|
27
|
+
if (!v && element) {
|
|
28
|
+
element.setAttribute(
|
|
29
|
+
'content',
|
|
30
|
+
'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
30
36
|
|
|
31
|
-
export default prepareSophoraModel
|
|
37
|
+
export default prepareSophoraModel;
|
|
@@ -6,9 +6,9 @@ const OFFSET = -50;
|
|
|
6
6
|
* @param {number} offset
|
|
7
7
|
*/
|
|
8
8
|
const scrollIntoViewWithOffset = (ref, offset) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const yOffset = offset !== 'undefined' ? offset : OFFSET;
|
|
10
|
+
const y = ref.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
|
11
|
+
window.scrollTo({ top: y, behavior: 'smooth' });
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export default scrollIntoViewWithOffset;
|
package/src/utils/slugify.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Source: https://svelte.dev/playground/b130be5e485441a1842ae97e4ce4f244?version=5.20.0
|
|
2
2
|
|
|
3
3
|
export default function slugify(str: string): string {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
return str
|
|
5
|
+
.replace(/\s+/g, '-')
|
|
6
|
+
.replace(/-+/g, '-')
|
|
7
|
+
.trim()
|
|
8
|
+
.normalize('NFKD')
|
|
9
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/[^a-z0-9 -]/g, '');
|
|
12
12
|
}
|
package/src/utils/topoToGeo.js
CHANGED
|
@@ -6,8 +6,8 @@ import { feature } from 'topojson-client';
|
|
|
6
6
|
* @returns {object} geojson
|
|
7
7
|
*/
|
|
8
8
|
const topoToGeo = (topojson) => {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const key = Object.keys(topojson.objects)[0];
|
|
10
|
+
return feature(topojson, topojson.objects[key]);
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export default topoToGeo;
|