Published
Edited
Aug 24, 2020
3 stars
Insert cell
Insert cell
paths = ['CIRCLE', 'MAP']
Insert cell
sampleGeoPath = pathGen(geoJsonNoMultiPolygon.features[5])
Insert cell
flubber.toCircle(sampleGeoPath, 10, 10, 10)(0.3)
Insert cell
viewof currentPath = Scrubber(paths, {
autoplay: true,
loop: true,
delay: 1000,
format: d => d
})
Insert cell
html`<style>
svg path {
fill: transparent;
stroke: black;
}
</style>`
Insert cell
scaleR = d3.scaleLinear().domain([0, 1000]).range([0, 30])
Insert cell
pathExample = {
const svg = d3
.create('svg')
.call(q.setSize, config.mapWidth, config.mapHeight);
const g = svg.append('g').call(q.move, () => [10, 10]);

const updatePath = node =>
node
.transition()
.duration(400)
.ease(d3.easeLinear)
.attrTween('d', function(d) {
console.log('tweening');
var previous = d3.select(this).attr('d');
if (d === 'circle') return flubber.toCircle(sampleGeoPath, 100, 50, 50);
return flubber.interpolate(previous, sampleGeoPath);
});

const enterMap = region =>
region
.append('path')
.attr('class', 'province')
.attr('data-region', getRegionName)
.attr('d', pathGen);

const updateMap = region => region.call(mapAnim);

const mapAnim = region =>
region
.transition()
.duration(500)
.attrTween('d', function(d) {
try {
const prevPath = d3.select(this).attr('d');
const regionName = getRegionName(d);
const [_y, _x] = provinceCoords[regionName];
const [x, y] = koreaProjection([_x, _y]);
const radius = scaleR(provinceData[regionName]);
if (currentPath === 'CIRCLE')
return flubber.toCircle(prevPath, x, y, radius);
const geoPath = pathGen(d);
return flubber.fromCircle(x, y, radius, geoPath);
} catch (err) {}
});

function render(pathMode) {
console.log('rerender');
const provinces = g
.selectAll('.province')
.data(geoJsonNoMultiPolygon.features, (d, i) => i)
.join(enterMap, updateMap);
}
render();
return Object.assign(svg.node(), { render });
}
Insert cell
getRegionName = d => d.properties.name_eng
Insert cell
pathExample.render(currentPath)
Insert cell
pathGen = d3.geoPath(koreaProjection)
Insert cell
config = ({
mapWidth: 400,
mapHeight: 400
})
Insert cell
koreaProjection = d3
.geoMercator()
// the center uses longtitude and latitude
// get Long/Lat data from google maps
.center([128, 36])
.fitSize([config.mapWidth, config.mapHeight], geoJson)
Insert cell
provinceData = _.mapValues(provinceCoords, () =>
Math.round(Math.random() * 1000)
)
Insert cell
Insert cell
topoData = FileAttachment('topoKorea.json').json()
Insert cell
geoJson = topojson.feature(topoData, topoData.objects.skorea_provinces_2018_geo)
Insert cell
geoJsonNoMultiPolygon = {
const features = _.cloneDeep(geoJson.features);
features.forEach(f => {
if (f.geometry.type !== 'MultiPolygon') return null;
f.geometry.coordinates.forEach((cs, i) => {
features.push({
type: 'Feature',
properties: f.properties,
geometry: { type: 'Polygon', coordinates: cs },
index: i + 1
});
});
});

const _features = features.filter(f => f.geometry.type !== 'MultiPolygon');

const _geo = { type: 'FeatureCollection', features: _features };
return rewind(_geo);
}
Insert cell
topojson = require('topojson@v3.0.2')
Insert cell
Insert cell
q = require('https://unpkg.com/d3-quicktool@0.4.2/dist/bundle.min.js')
Insert cell
Insert cell
_ = require('lodash@v4.17.15')
Insert cell
flubber = require('https://unpkg.com/flubber@0.3.0')
Insert cell
import { rewind } from '@rabelais/geojson-rewind'
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more