1
0
mirror of https://github.com/d3/d3.git synced 2025-12-08 19:46:24 +00:00
d3/docs/components/WorldMap.vue
2023-06-09 15:38:01 -07:00

70 lines
2.1 KiB
Vue

<script setup>
import * as d3 from "d3";
import * as topojson from "topojson-client";
import deferRender from "./deferRender.js";
</script>
<script>
const outline = {type: "Sphere"};
const graticule = d3.geoGraticule10();
let landPromises = {};
async function render(node, {projection, rotate, resolution, width, landPromise}) {
const land = await landPromise;
rotate = rotate && projection.rotate();
const path = d3.geoPath(projection);
const svg = d3.select(node);
let frame;
let x;
function update() {
svg.selectAll("[name='outline']").attr("d", path(outline));
svg.selectAll("[name='graticule']").attr("d", path(graticule));
svg.selectAll("[name='feature']").attr("d", path(land));
}
svg.on("pointermove", rotate && (resolution === "110m") && ((event) => {
if (!frame) frame = requestAnimationFrame(rerender);
([x] = d3.pointer(event));
}));
function rerender() {
frame = null;
projection.rotate([rotate[0] + x / width * 20, rotate[1], rotate[2]]);
update();
}
update();
}
export default {
props: {
projection: {type: Function},
rotate: {type: Boolean, default: false},
resolution: {type: String, default: "110m"},
width: {type: Number, default: 688},
height: {type: Number, default: 400},
},
mounted() {
this.landPromise = landPromises[this.resolution] ??= d3
.json(`https://cdn.jsdelivr.net/npm/world-atlas@2.0.2/land-${this.resolution}.json`)
.then((world) => topojson.feature(world, world.objects.land));
this.disconnect = deferRender(this.$el, async () => render(this.$el, this));
},
updated() {
render(this.$el, this);
},
unmounted() {
if (this.disconnect) this.disconnect();
}
}
</script>
<template>
<svg :width="width" :height="height" :viewBox="[0, 0, width, height].join(' ')" style="max-width: 100%; height: auto;">
<path name="outline" fill="var(--vp-c-bg-alt)" />
<path name="graticule" stroke="currentColor" stroke-opacity="0.2" fill="none" />
<path name="feature" fill="currentColor" />
<path name="outline" stroke="currentColor" fill="none" />
</svg>
</template>