Last active
January 12, 2021 17:05
-
-
Save nautilytics/47c1e69b4c9d3bb849af6d28c78c0475 to your computer and use it in GitHub Desktop.
A GeoJSON to PNG converter using D3 for Node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {createConverter} = require("convert-svg-to-png"); | |
const path = require("path"); | |
const sharp = require('sharp'); | |
const D3Node = require("d3-node"); | |
const {d3} = require("d3-node"); | |
// Set up global variables which can be changed | |
const width = 400; | |
const height = 400; | |
const fileName = "./UK.json"; | |
const activeFillColor = "#149E9C"; | |
const getRegion = feature => feature.properties.region; // helper func to grab the region of each feature | |
const getId = feature => feature.properties.PCON11CD; // helper func to grab the unique feature ID of each feature | |
const convertSvgFiles = async () => { | |
// Entry point into main convert GeoJSON to PNG function | |
const converter = createConverter(); | |
try { | |
// Load the GeoJSON file which can be located locally (or via a link) | |
const f = path.join(__dirname, fileName); | |
const json = require(f); | |
// Find all the unique regions in our data set, while keeping the features attached to the nested data | |
const regions = d3.nest() | |
.key(d => getRegion(d)) | |
.entries(json.features); | |
// Go through each region and create a generic FeatureCollection for the polygons within that region | |
for (const region of regions) { | |
// Using the FeatureCollection, center the region with the selected geographic projection | |
const projection = d3.geoMercator() | |
.fitSize([width, height], { | |
"type": "FeatureCollection", | |
"name": "UK_2", | |
"crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}}, | |
"features": region.values | |
}); | |
const p = d3.geoPath(projection); | |
// Go through each feature, or constituency, within the region, | |
// and render it as SVG with the feature highlighted | |
const features = region.values; | |
for (let feature of features) { | |
const renderedSVG = await renderSVG(features, feature, p); | |
try { | |
// Using the `sharp` library, take the rendered SVG string and generate a PNG | |
await sharp(Buffer.from(renderedSVG.svgString)) | |
.extract({ | |
left: 0, | |
top: renderedSVG.y1, | |
width: width, | |
height: renderedSVG.y2 - renderedSVG.y1 | |
}) | |
.png() | |
.toFile(`./PNGS/${getId(feature)}.png`); | |
} catch (err) { | |
console.error(err); | |
} | |
} | |
} | |
} finally { | |
await converter.destroy(); | |
process.exit(); | |
} | |
}; | |
const renderSVG = async (features, feature, p) => { | |
// Use D3 on the back-end to create an SVG of the FeatureCollection | |
const d3N = new D3Node(); | |
const svg = d3N.createSVG(width, height); | |
svg | |
.selectAll("path") | |
.data(features) | |
.enter() | |
.append("path") | |
.style("stroke", "black") | |
.style("fill", d => getId(d) === getId(feature) ? activeFillColor : "white") | |
.style("shape-rendering", "crispEdges") | |
.style("stroke-width", "1px") | |
.attr("d", p); | |
// Use the bounds of the feature to make sure our images don't have any extra white space around them | |
let y1, y2; | |
features.forEach(feature => { | |
const bound = p.bounds(feature); | |
if (!y1 || bound[0][1] < y1) y1 = bound[0][1]; | |
if (!y2 || bound[1][1] > y2) y2 = bound[1][1]; | |
}); | |
const svgString = d3N.svgString(); | |
return { | |
svgString, | |
y1: Math.floor(Math.max(y1, 0)), | |
y2: Math.floor(y2) | |
}; | |
}; | |
// Run the application to convert the SVG files | |
convertSvgFiles() | |
.then(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "geojson-to-png-converter", | |
"version": "1.0.0", | |
"main": "index.js", | |
"dependencies": { | |
"convert-svg-to-png": "^0.5.0", | |
"d3-node": "^2.2.0", | |
"sharp": "^0.23.3" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"type": "FeatureCollection", | |
"name": "UK", | |
"crs": { | |
"type": "name", | |
"properties": { | |
"name": "urn:ogc:def:crs:OGC:1.3:CRS84" | |
} | |
}, | |
"features": [ | |
{ | |
"type": "Feature", | |
"properties": { | |
"PCON11NM": "Amber Valley", | |
"PCON11CD": "R120", | |
"region": "East Midlands" | |
}, | |
"geometry": { | |
"type": "Polygon", | |
"coordinates": [ [ [ -1.3316, 53.081 ], [ -1.3341, 53.0789 ], [ -1.3347, 53.0776 ], [ -1.3358, 53.0771 ], [ -1.3366, 53.0757 ], [ -1.3358, 53.0746 ], [ -1.3383, 53.0727 ], [ -1.3422, 53.0709 ], [ -1.344, 53.0683 ], [ -1.3435, 53.0668 ], [ -1.3444, 53.0655 ], [ -1.3446, 53.0633 ], [ -1.3419, 53.0605 ], [ -1.3402, 53.0597 ], [ -1.3375, 53.0558 ], [ -1.3374, 53.0547 ], [ -1.3359, 53.0529 ], [ -1.3364, 53.0517 ], [ -1.3357, 53.0507 ], [ -1.3344, 53.0502 ], [ -1.3332, 53.0481 ], [ -1.3346, 53.0473 ], [ -1.333, 53.0446 ], [ -1.3338, 53.0429 ], [ -1.3336, 53.0417 ], [ -1.3346, 53.0406 ], [ -1.3332, 53.0397 ], [ -1.3326, 53.0383 ], [ -1.3326, 53.0364 ], [ -1.3332, 53.0356 ], [ -1.3313, 53.0318 ], [ -1.3318, 53.0309 ], [ -1.3291, 53.0307 ], [ -1.3278, 53.0284 ], [ -1.3259, 53.0274 ], [ -1.3246, 53.0261 ], [ -1.3221, 53.0202 ], [ -1.3186, 53.0161 ], [ -1.3202, 53.0155 ], [ -1.3183, 53.0138 ], [ -1.3196, 53.0117 ], [ -1.3192, 53.0102 ], [ -1.3158, 53.0086 ], [ -1.3136, 53.0067 ], [ -1.3134, 53.0046 ], [ -1.3123, 53.0046 ], [ -1.31, 53.0034 ], [ -1.308, 53.0039 ], [ -1.3074, 53.0036 ], [ -1.3098, 53.002 ], [ -1.314, 53.0013 ], [ -1.3169, 52.9992 ], [ -1.3183, 52.9967 ], [ -1.3224, 52.9939 ], [ -1.3242, 52.9937 ], [ -1.3227, 52.9921 ], [ -1.3231, 52.9898 ], [ -1.3246, 52.9895 ], [ -1.3238, 52.9883 ], [ -1.3262, 52.9886 ], [ -1.328, 52.9873 ], [ -1.3315, 52.987 ], [ -1.3285, 52.9843 ], [ -1.3281, 52.9816 ], [ -1.3304, 52.9809 ], [ -1.3328, 52.9781 ], [ -1.3362, 52.9779 ], [ -1.3372, 52.9785 ], [ -1.3399, 52.9782 ], [ -1.3423, 52.9789 ], [ -1.3477, 52.978 ], [ -1.3503, 52.9782 ], [ -1.352, 52.9778 ], [ -1.3554, 52.978 ], [ -1.3585, 52.9777 ], [ -1.362, 52.9767 ], [ -1.3672, 52.9773 ], [ -1.3693, 52.9759 ], [ -1.3701, 52.9736 ], [ -1.371, 52.9731 ], [ -1.3752, 52.9742 ], [ -1.3783, 52.9766 ], [ -1.386, 52.9791 ], [ -1.3859, 52.9802 ], [ -1.3842, 52.9816 ], [ -1.3937, 52.9817 ], [ -1.3955, 52.9807 ], [ -1.4027, 52.9796 ], [ -1.4093, 52.977 ], [ -1.4098, 52.9796 ], [ -1.4156, 52.9806 ], [ -1.4186, 52.9801 ], [ -1.4205, 52.981 ], [ -1.4244, 52.9814 ], [ -1.4299, 52.9801 ], [ -1.432, 52.9793 ], [ -1.4447, 52.9788 ], [ -1.4496, 52.9807 ], [ -1.4514, 52.9823 ], [ -1.4537, 52.9809 ], [ -1.4559, 52.9826 ], [ -1.4579, 52.9824 ], [ -1.4602, 52.9839 ], [ -1.4634, 52.9829 ], [ -1.4641, 52.9857 ], [ -1.4635, 52.9868 ], [ -1.4645, 52.9899 ], [ -1.464, 52.9919 ], [ -1.4667, 52.9917 ], [ -1.4671, 52.994 ], [ -1.4707, 52.9935 ], [ -1.4715, 52.9959 ], [ -1.4702, 52.9972 ], [ -1.4679, 52.9974 ], [ -1.4653, 52.9983 ], [ -1.465, 52.9992 ], [ -1.4688, 52.9987 ], [ -1.4696, 52.9999 ], [ -1.4696, 53.001 ], [ -1.4714, 53.0022 ], [ -1.4711, 53.0047 ], [ -1.4686, 53.0052 ], [ -1.4666, 53.0036 ], [ -1.4638, 53.0037 ], [ -1.4629, 53.0078 ], [ -1.4638, 53.011 ], [ -1.462, 53.0117 ], [ -1.4604, 53.0107 ], [ -1.4599, 53.0126 ], [ -1.4615, 53.013 ], [ -1.4615, 53.0149 ], [ -1.461, 53.016 ], [ -1.4584, 53.0181 ], [ -1.4572, 53.0186 ], [ -1.4555, 53.0205 ], [ -1.4506, 53.0223 ], [ -1.4491, 53.0238 ], [ -1.4476, 53.0264 ], [ -1.4475, 53.0281 ], [ -1.4452, 53.0329 ], [ -1.4453, 53.0336 ], [ -1.443, 53.0366 ], [ -1.4468, 53.0372 ], [ -1.4504, 53.0364 ], [ -1.4497, 53.0377 ], [ -1.4509, 53.0392 ], [ -1.4534, 53.0405 ], [ -1.4564, 53.0407 ], [ -1.4815, 53.0463 ], [ -1.4817, 53.0475 ], [ -1.4805, 53.0487 ], [ -1.4804, 53.0497 ], [ -1.4815, 53.0526 ], [ -1.4831, 53.0552 ], [ -1.4839, 53.0595 ], [ -1.4884, 53.0637 ], [ -1.4871, 53.0642 ], [ -1.4838, 53.0644 ], [ -1.4815, 53.0658 ], [ -1.4803, 53.0678 ], [ -1.4779, 53.0676 ], [ -1.477, 53.0684 ], [ -1.4773, 53.0699 ], [ -1.4793, 53.0733 ], [ -1.476, 53.0747 ], [ -1.47, 53.0758 ], [ -1.4694, 53.0785 ], [ -1.4681, 53.0787 ], [ -1.4656, 53.0816 ], [ -1.4657, 53.0826 ], [ -1.4608, 53.0832 ], [ -1.4592, 53.0827 ], [ -1.4581, 53.0834 ], [ -1.4612, 53.0864 ], [ -1.4632, 53.0898 ], [ -1.4654, 53.0917 ], [ -1.4653, 53.0924 ], [ -1.469, 53.0959 ], [ -1.47, 53.0965 ], [ -1.4716, 53.0992 ], [ -1.4685, 53.1003 ], [ -1.4693, 53.1019 ], [ -1.4687, 53.1062 ], [ -1.4676, 53.107 ], [ -1.4654, 53.1108 ], [ -1.4615, 53.1102 ], [ -1.46, 53.1083 ], [ -1.4573, 53.1088 ], [ -1.4555, 53.1096 ], [ -1.4524, 53.1064 ], [ -1.4505, 53.1055 ], [ -1.4503, 53.1045 ], [ -1.4482, 53.1036 ], [ -1.4434, 53.1045 ], [ -1.4373, 53.1049 ], [ -1.4325, 53.1059 ], [ -1.4301, 53.1053 ], [ -1.4274, 53.1055 ], [ -1.4254, 53.1039 ], [ -1.4237, 53.1033 ], [ -1.4223, 53.1045 ], [ -1.4203, 53.1055 ], [ -1.4197, 53.1065 ], [ -1.4173, 53.1056 ], [ -1.4138, 53.1055 ], [ -1.4099, 53.1064 ], [ -1.41, 53.1074 ], [ -1.408, 53.1075 ], [ -1.4072, 53.1069 ], [ -1.4029, 53.1073 ], [ -1.4005, 53.1062 ], [ -1.3949, 53.1047 ], [ -1.3925, 53.1053 ], [ -1.3912, 53.1052 ], [ -1.3891, 53.1064 ], [ -1.384, 53.107 ], [ -1.379, 53.1088 ], [ -1.377, 53.1086 ], [ -1.3732, 53.1077 ], [ -1.3727, 53.1055 ], [ -1.3728, 53.1038 ], [ -1.3703, 53.1024 ], [ -1.3689, 53.1001 ], [ -1.3696, 53.099 ], [ -1.3669, 53.0977 ], [ -1.366, 53.0967 ], [ -1.3641, 53.0959 ], [ -1.364, 53.0945 ], [ -1.365, 53.0932 ], [ -1.3623, 53.0918 ], [ -1.3607, 53.0904 ], [ -1.359, 53.0898 ], [ -1.357, 53.0883 ], [ -1.3531, 53.0862 ], [ -1.3509, 53.0866 ], [ -1.3448, 53.0862 ], [ -1.3437, 53.0866 ], [ -1.3417, 53.0856 ], [ -1.3398, 53.0842 ], [ -1.3316, 53.081 ] ] ] | |
} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment