From 67ad6c53da4d757a99b9c766ad95d531c06f53ac Mon Sep 17 00:00:00 2001 From: Basile Bruneau Date: Tue, 5 May 2020 22:06:39 +0200 Subject: [PATCH] feat: support diagonal grid and pins on it --- README.md | 3 ++- index.js | 67 +++++++++++++++++++++++++++++++++++++++++-------------- test.js | 9 ++++---- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f152be8..949fed7 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ const map = new DottedMap({ height, width, // (one of both if enough) - countries: ['FRA', 'DEU'] // if not present, whole world is used + countries: ['FRA', { id: 'DEU', svgOptions: { color: 'blue' } }] // if not present, whole world is used region: { lat: {min, max}, lng: {min, max} }, // if not present, it fits the countries or the world + grid: 'vertical' | 'diagonal', }) // → it will cache the points array diff --git a/index.js b/index.js index 7ac11df..e6946cd 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const geojsonByCountry = geojsonWorld.features.reduce((countries, feature) => { }, {}); const DEFAULT_WORLD_REGION = { - lat: { min: -65, max: 78 }, + lat: { min: -56, max: 71 }, lng: { min: -179, max: 179 }, }; @@ -51,7 +51,7 @@ const computeGeojsonBox = (geojson) => { } }; -function DottedMap({ height = 0, width = 0, countries = [], region }) { +function DottedMap({ height = 0, width = 0, countries = [], region, grid = 'vertocam' }) { if (height <= 0 && width <= 0) { throw new Error('height or width is required'); } @@ -82,33 +82,66 @@ function DottedMap({ height = 0, width = 0, countries = [], region }) { const points = {}; - for (let x = 0; x < width; x += 1) { - for (let y = 0; y < height; y += 1) { - const pointGoogle = [(x / width) * X_RANGE + X_MIN, Y_MAX - (y / height) * Y_RANGE]; + const ystep = grid === 'diagonal' ? Math.sqrt(3) / 2 : 1; + + for (let y = 0; y * ystep < height; y += 1) { + for (let x = 0; x < width; x += 1) { + const localx = y % 2 === 0 && grid === 'diagonal' ? x + 0.5 : x; + const localy = y * ystep; + + const pointGoogle = [(localx / width) * X_RANGE + X_MIN, Y_MAX - (localy / height) * Y_RANGE]; const wgs84Point = proj4(proj4.defs('GOOGLE'), proj4.defs('WGS84'), pointGoogle); + if (inside.feature(geojson, wgs84Point) !== -1) { - points[[x, y].join(';')] = { x, y }; + points[[x, y].join(';')] = { x: localx, y: localy }; } } } return { addPin({ lat, lng, data, svgOptions }) { - const [rawX, rawY] = proj4(proj4.defs('GOOGLE'), [lng, lat]); - const [x, y] = [Math.round((width * (rawX - X_MIN)) / X_RANGE), Math.round((height * (Y_MAX - rawY)) / Y_RANGE)]; - points[[x, y].join(';')] = { x, y, data, svgOptions }; + const [googleX, googleY] = proj4(proj4.defs('GOOGLE'), [lng, lat]); + let [rawX, rawY] = [(width * (googleX - X_MIN)) / X_RANGE, (height * (Y_MAX - googleY)) / Y_RANGE]; + const y = Math.round(rawY / ystep); + if (y % 2 === 0 && grid === 'diagonal') { + rawX -= 0.5; + } + const x = Math.round(rawX); + let [localx, localy] = [x, Math.round(y) * ystep]; + if (y % 2 === 0 && grid === 'diagonal') { + localx += 0.5; + } + + points[[x, y].join(';')] = { x: localx, y: localy, data, svgOptions }; }, getPoints() { return Object.values(points); }, - getSVG({ shape, color = 'current', backgroundColor, radius = 0.5 }) { - return ` - ${Object.values(points) - .map( - ({ x, y, svgOptions = {} }) => - ``, - ) - .join('\n')} + getSVG({ shape = 'circle', color = 'current', backgroundColor = 'transparent', radius = 0.5 }) { + const getPoint = ({ x, y, svgOptions = {} }) => { + const pointRadius = svgOptions.radius || radius; + if (shape === 'circle') { + return ``; + } else if (shape === 'hexagon') { + const sqrt3radius = Math.sqrt(3) * pointRadius; + + const polyPoints = [ + [x + sqrt3radius, y - pointRadius], + [x + sqrt3radius, y + pointRadius], + [x, y + 2 * pointRadius], + [x - sqrt3radius, y + pointRadius], + [x - sqrt3radius, y - pointRadius], + [x, y - 2 * pointRadius], + ]; + + return ``; + } + }; + + return ` + ${Object.values(points).map(getPoint).join('\n')} `; }, }; diff --git a/test.js b/test.js index d42b21f..6d83557 100644 --- a/test.js +++ b/test.js @@ -1,8 +1,9 @@ const DottedMap = require('./index.js'); -const map = new DottedMap({ height: 100, countries: ['FRA'] }); +const map = new DottedMap({ height: 100, grid: 'diagonal' }); -map.addPin({ lat: 48.85, lng: 2.35, svgOptions: { color: 'red', radius: 0.45 } }); -// map.addPin({ lat: 47.65, lng: -2.76, svgOptions: { color: 'red', radius: 0.5 } }); +const pinColor = '#D6FF79'; -console.log(map.getSVG({ radius: 0.3, color: 'grey' })); +map.addPin({ lat: 48.85, lng: 2.35, svgOptions: { color: pinColor, radius: 0.22 } }); + +console.log(map.getSVG({ radius: 0.22, color: '#423B38', shape: 'circle', backgroundColor: '020300' }));