dotted-map 3.0.0 → 3.1.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/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
 
8
8
  <img src="https://raw.githubusercontent.com/NTag/dotted-map/master/images/world-diagonal-circle-dark.svg" width="100%" />
9
9
 
10
+ <img src="https://raw.githubusercontent.com/NTag/dotted-map/master/images/world-orthographic-circle-dark.svg" width="100%" />
11
+
10
12
  <img src="https://raw.githubusercontent.com/NTag/dotted-map/master/images/france-diagonal-hexagon-light.svg" height="150px" />
11
13
  <img src="https://raw.githubusercontent.com/NTag/dotted-map/master/images/italy-diagonal-hexagon-light.svg" height="150px" />
12
14
  <img src="https://raw.githubusercontent.com/NTag/dotted-map/master/images/uk-diagonal-hexagon-light.svg" height="150px" />
@@ -124,9 +126,10 @@ import DottedMap from 'dotted-map';
124
126
  const map = new DottedMap({
125
127
  height,
126
128
  width, // just specify either height or width, so the ratio of the map is correct
127
- countries: ['FRA'] // look into `countries.geo.json` to see which keys to use. You can also omit this parameter and the whole world will be used
129
+ countries: [FRA] // look into `countries.geo.json` to see which keys to use. You can also omit this parameter and the whole world will be used
128
130
  region: { lat: { min, max }, lng: { min, max } }, // if not present, it will fit the countries (and if no country is specified, the whole world)
129
- grid: 'vertical' | 'diagonal', // how points should be aligned
131
+ grid: vertical | diagonal’, // how points should be aligned
132
+ projection: { name, center }, // optional, see below
130
133
  avoidOuterPins: false | true, // if it’s true, prevent adding pins when they are outside of region/countries
131
134
  });
132
135
 
@@ -152,6 +155,39 @@ map.getSVG({
152
155
  // <svg><circle … /><circle …></svg>
153
156
  ```
154
157
 
158
+ ### Projection
159
+
160
+ By default, the map uses the Mercator projection. You can optionally pass a `projection` parameter to use a different one:
161
+
162
+ ```js
163
+ const map = new DottedMap({
164
+ height: 60,
165
+ grid: 'diagonal',
166
+ projection: { name: 'robinson' },
167
+ });
168
+ ```
169
+
170
+ Available projections: `mercator` (default), `equirectangular`, `robinson`, `equalEarth`, `mollweide`, `miller`, `sinusoidal`, `orthographic`, `gallPeters`, `vanDerGrinten`.
171
+
172
+ You can also pass a `center` to shift the map's center point. This is especially useful for `orthographic` (which shows a single hemisphere) but works with any projection:
173
+
174
+ ```js
175
+ // Orthographic projection centered on North America
176
+ const map = new DottedMap({
177
+ height: 60,
178
+ grid: 'diagonal',
179
+ projection: { name: 'orthographic', center: { lat: 40, lng: -100 } },
180
+ });
181
+
182
+ // Robinson projection centered on the Pacific
183
+ const map = new DottedMap({
184
+ height: 60,
185
+ projection: { name: 'robinson', center: { lat: 0, lng: 150 } },
186
+ });
187
+ ```
188
+
189
+ Note: for `orthographic`, pins on the back side of the globe (not visible) will be ignored.
190
+
155
191
  ## Acknowledgments
156
192
 
157
193
  Countries are from https://github.com/johan/world.geo.json.
package/dist/index.cjs CHANGED
@@ -12766,6 +12766,26 @@ var countries_geo_default = {
12766
12766
 
12767
12767
  //#endregion
12768
12768
  //#region src/with-countries.ts
12769
+ const PROJECTIONS = {
12770
+ mercator: "+proj=merc +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12771
+ equirectangular: "+proj=eqc +lon_0={lng} +lat_ts=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12772
+ robinson: "+proj=robin +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12773
+ equalEarth: "+proj=eqearth +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12774
+ mollweide: "+proj=moll +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12775
+ miller: "+proj=mill +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12776
+ sinusoidal: "+proj=sinu +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12777
+ orthographic: "+proj=ortho +lat_0={lat} +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12778
+ gallPeters: "+proj=cea +lon_0={lng} +lat_ts=45 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12779
+ vanDerGrinten: "+proj=vandg +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m"
12780
+ };
12781
+ const DEFAULT_PROJECTION = { name: "mercator" };
12782
+ const getProj4String = (projection = DEFAULT_PROJECTION) => {
12783
+ const template = PROJECTIONS[projection.name];
12784
+ const lat = projection.center?.lat ?? 0;
12785
+ const lng = projection.center?.lng ?? 0;
12786
+ return template.replace("{lat}", String(lat)).replace("{lng}", String(lng));
12787
+ };
12788
+ const isFinitePoint = (point) => point.every((v) => Number.isFinite(v));
12769
12789
  const typedWorld = countries_geo_default;
12770
12790
  const geojsonByCountry = typedWorld.features.reduce((countries, feature) => {
12771
12791
  countries[feature.id] = feature;
@@ -12788,8 +12808,8 @@ const DEFAULT_WORLD_REGION = {
12788
12808
  max: 71
12789
12809
  },
12790
12810
  lng: {
12791
- min: -179,
12792
- max: 179
12811
+ min: -168,
12812
+ max: 168
12793
12813
  }
12794
12814
  };
12795
12815
  const computeGeojsonBox = (geojson) => {
@@ -12826,8 +12846,9 @@ const computeGeojsonBox = (geojson) => {
12826
12846
  };
12827
12847
  } else throw new Error(`Unknown geojson type ${geojson.type}`);
12828
12848
  };
12829
- const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertical" }) => {
12849
+ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertical", projection = DEFAULT_PROJECTION }) => {
12830
12850
  if (height <= 0 && width <= 0) throw new Error("height or width is required");
12851
+ const proj4String = getProj4String(projection);
12831
12852
  let geojson = typedWorld;
12832
12853
  let resolvedRegion = region;
12833
12854
  if (countries.length > 0) {
@@ -12838,8 +12859,34 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12838
12859
  if (!resolvedRegion) resolvedRegion = computeGeojsonBox(geojson);
12839
12860
  } else if (!resolvedRegion) resolvedRegion = DEFAULT_WORLD_REGION;
12840
12861
  const poly = geojsonToMultiPolygons(geojson);
12841
- const [X_MIN, Y_MIN] = (0, proj4.default)("GOOGLE", [resolvedRegion.lng.min, resolvedRegion.lat.min]);
12842
- const [X_MAX, Y_MAX] = (0, proj4.default)("GOOGLE", [resolvedRegion.lng.max, resolvedRegion.lat.max]);
12862
+ const SAMPLES = 100;
12863
+ const r = resolvedRegion;
12864
+ let X_MIN = Infinity;
12865
+ let Y_MIN = Infinity;
12866
+ let X_MAX = -Infinity;
12867
+ let Y_MAX = -Infinity;
12868
+ for (let i = 0; i <= SAMPLES; i++) {
12869
+ const frac = i / SAMPLES;
12870
+ const sampleLat = r.lat.min + frac * (r.lat.max - r.lat.min);
12871
+ const sampleLng = r.lng.min + frac * (r.lng.max - r.lng.min);
12872
+ const candidates = [
12873
+ [sampleLng, r.lat.min],
12874
+ [sampleLng, r.lat.max],
12875
+ [r.lng.min, sampleLat],
12876
+ [r.lng.max, sampleLat],
12877
+ [sampleLng, sampleLat]
12878
+ ];
12879
+ for (const point of candidates) {
12880
+ const [px, py] = (0, proj4.default)(proj4String, point);
12881
+ if (Number.isFinite(px) && Number.isFinite(py)) {
12882
+ X_MIN = Math.min(X_MIN, px);
12883
+ Y_MIN = Math.min(Y_MIN, py);
12884
+ X_MAX = Math.max(X_MAX, px);
12885
+ Y_MAX = Math.max(Y_MAX, py);
12886
+ }
12887
+ }
12888
+ }
12889
+ if (!Number.isFinite(X_MIN)) throw new Error("No valid projected points found for the given region and projection");
12843
12890
  const X_RANGE = X_MAX - X_MIN;
12844
12891
  const Y_RANGE = Y_MAX - Y_MIN;
12845
12892
  if (width <= 0) width = Math.round(height * X_RANGE / Y_RANGE);
@@ -12849,7 +12896,9 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12849
12896
  for (let y = 0; y * ystep < height; y += 1) for (let x = 0; x < width; x += 1) {
12850
12897
  const localx = y % 2 === 0 && grid === "diagonal" ? x + .5 : x;
12851
12898
  const localy = y * ystep;
12852
- if ((0, _turf_boolean_point_in_polygon.default)((0, proj4.default)("GOOGLE", "WGS84", [localx / width * X_RANGE + X_MIN, Y_MAX - localy / height * Y_RANGE]), poly)) points[[x, y].join(";")] = {
12899
+ const wgs84Point = (0, proj4.default)(proj4String, "WGS84", [localx / width * X_RANGE + X_MIN, Y_MAX - localy / height * Y_RANGE]);
12900
+ if (!isFinitePoint(wgs84Point) || !(0, _turf_boolean_point_in_polygon.default)(wgs84Point, poly)) continue;
12901
+ points[[x, y].join(";")] = {
12853
12902
  x: localx,
12854
12903
  y: localy
12855
12904
  };
@@ -12866,17 +12915,19 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12866
12915
  grid,
12867
12916
  height,
12868
12917
  width,
12869
- ystep
12918
+ ystep,
12919
+ projection
12870
12920
  };
12871
12921
  };
12872
12922
  const getMapJSON = (props) => JSON.stringify(getMap(props));
12873
- const getCacheKey = ({ height = 0, width = 0, countries = [], region, grid = "vertical" }) => {
12923
+ const getCacheKey = ({ height = 0, width = 0, countries = [], region, grid = "vertical", projection = DEFAULT_PROJECTION }) => {
12874
12924
  return [
12875
12925
  JSON.stringify(region),
12876
12926
  grid,
12877
12927
  height,
12878
12928
  width,
12879
- JSON.stringify(countries)
12929
+ JSON.stringify(countries),
12930
+ JSON.stringify(projection)
12880
12931
  ].join(" ");
12881
12932
  };
12882
12933
  var DottedMap = class extends require_without_countries {
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as MapSettings, c as Region, s as Point, t as DottedMapSettings } from "./types-ByIhMtjO.cjs";
1
+ import { a as MapSettings, c as Projection, l as ProjectionName, s as Point, t as DottedMapSettings, u as Region } from "./types-vOcy-UuQ.cjs";
2
2
  import DottedMapWithoutCountries from "./without-countries.cjs";
3
3
 
4
4
  //#region src/with-countries.d.ts
@@ -10,4 +10,4 @@ declare class DottedMap extends DottedMapWithoutCountries {
10
10
  }: DottedMapSettings);
11
11
  }
12
12
  //#endregion
13
- export { type DottedMapSettings, DottedMapWithoutCountries, type MapSettings, type Point, type Region, DottedMap as default, getMapJSON };
13
+ export { type DottedMapSettings, DottedMapWithoutCountries, type MapSettings, type Point, type Projection, type ProjectionName, type Region, DottedMap as default, getMapJSON };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as MapSettings, c as Region, s as Point, t as DottedMapSettings } from "./types-UL1f7mia.mjs";
1
+ import { a as MapSettings, c as Projection, l as ProjectionName, s as Point, t as DottedMapSettings, u as Region } from "./types-F6gvGCSl.mjs";
2
2
  import DottedMapWithoutCountries from "./without-countries.mjs";
3
3
 
4
4
  //#region src/with-countries.d.ts
@@ -10,4 +10,4 @@ declare class DottedMap extends DottedMapWithoutCountries {
10
10
  }: DottedMapSettings);
11
11
  }
12
12
  //#endregion
13
- export { type DottedMapSettings, DottedMapWithoutCountries, type MapSettings, type Point, type Region, DottedMap as default, getMapJSON };
13
+ export { type DottedMapSettings, DottedMapWithoutCountries, type MapSettings, type Point, type Projection, type ProjectionName, type Region, DottedMap as default, getMapJSON };
package/dist/index.mjs CHANGED
@@ -12762,6 +12762,26 @@ var countries_geo_default = {
12762
12762
 
12763
12763
  //#endregion
12764
12764
  //#region src/with-countries.ts
12765
+ const PROJECTIONS = {
12766
+ mercator: "+proj=merc +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12767
+ equirectangular: "+proj=eqc +lon_0={lng} +lat_ts=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12768
+ robinson: "+proj=robin +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12769
+ equalEarth: "+proj=eqearth +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12770
+ mollweide: "+proj=moll +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12771
+ miller: "+proj=mill +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12772
+ sinusoidal: "+proj=sinu +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12773
+ orthographic: "+proj=ortho +lat_0={lat} +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12774
+ gallPeters: "+proj=cea +lon_0={lng} +lat_ts=45 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12775
+ vanDerGrinten: "+proj=vandg +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m"
12776
+ };
12777
+ const DEFAULT_PROJECTION = { name: "mercator" };
12778
+ const getProj4String = (projection = DEFAULT_PROJECTION) => {
12779
+ const template = PROJECTIONS[projection.name];
12780
+ const lat = projection.center?.lat ?? 0;
12781
+ const lng = projection.center?.lng ?? 0;
12782
+ return template.replace("{lat}", String(lat)).replace("{lng}", String(lng));
12783
+ };
12784
+ const isFinitePoint = (point) => point.every((v) => Number.isFinite(v));
12765
12785
  const typedWorld = countries_geo_default;
12766
12786
  const geojsonByCountry = typedWorld.features.reduce((countries, feature) => {
12767
12787
  countries[feature.id] = feature;
@@ -12784,8 +12804,8 @@ const DEFAULT_WORLD_REGION = {
12784
12804
  max: 71
12785
12805
  },
12786
12806
  lng: {
12787
- min: -179,
12788
- max: 179
12807
+ min: -168,
12808
+ max: 168
12789
12809
  }
12790
12810
  };
12791
12811
  const computeGeojsonBox = (geojson) => {
@@ -12822,8 +12842,9 @@ const computeGeojsonBox = (geojson) => {
12822
12842
  };
12823
12843
  } else throw new Error(`Unknown geojson type ${geojson.type}`);
12824
12844
  };
12825
- const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertical" }) => {
12845
+ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertical", projection = DEFAULT_PROJECTION }) => {
12826
12846
  if (height <= 0 && width <= 0) throw new Error("height or width is required");
12847
+ const proj4String = getProj4String(projection);
12827
12848
  let geojson = typedWorld;
12828
12849
  let resolvedRegion = region;
12829
12850
  if (countries.length > 0) {
@@ -12834,8 +12855,34 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12834
12855
  if (!resolvedRegion) resolvedRegion = computeGeojsonBox(geojson);
12835
12856
  } else if (!resolvedRegion) resolvedRegion = DEFAULT_WORLD_REGION;
12836
12857
  const poly = geojsonToMultiPolygons(geojson);
12837
- const [X_MIN, Y_MIN] = proj4("GOOGLE", [resolvedRegion.lng.min, resolvedRegion.lat.min]);
12838
- const [X_MAX, Y_MAX] = proj4("GOOGLE", [resolvedRegion.lng.max, resolvedRegion.lat.max]);
12858
+ const SAMPLES = 100;
12859
+ const r = resolvedRegion;
12860
+ let X_MIN = Infinity;
12861
+ let Y_MIN = Infinity;
12862
+ let X_MAX = -Infinity;
12863
+ let Y_MAX = -Infinity;
12864
+ for (let i = 0; i <= SAMPLES; i++) {
12865
+ const frac = i / SAMPLES;
12866
+ const sampleLat = r.lat.min + frac * (r.lat.max - r.lat.min);
12867
+ const sampleLng = r.lng.min + frac * (r.lng.max - r.lng.min);
12868
+ const candidates = [
12869
+ [sampleLng, r.lat.min],
12870
+ [sampleLng, r.lat.max],
12871
+ [r.lng.min, sampleLat],
12872
+ [r.lng.max, sampleLat],
12873
+ [sampleLng, sampleLat]
12874
+ ];
12875
+ for (const point of candidates) {
12876
+ const [px, py] = proj4(proj4String, point);
12877
+ if (Number.isFinite(px) && Number.isFinite(py)) {
12878
+ X_MIN = Math.min(X_MIN, px);
12879
+ Y_MIN = Math.min(Y_MIN, py);
12880
+ X_MAX = Math.max(X_MAX, px);
12881
+ Y_MAX = Math.max(Y_MAX, py);
12882
+ }
12883
+ }
12884
+ }
12885
+ if (!Number.isFinite(X_MIN)) throw new Error("No valid projected points found for the given region and projection");
12839
12886
  const X_RANGE = X_MAX - X_MIN;
12840
12887
  const Y_RANGE = Y_MAX - Y_MIN;
12841
12888
  if (width <= 0) width = Math.round(height * X_RANGE / Y_RANGE);
@@ -12845,7 +12892,9 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12845
12892
  for (let y = 0; y * ystep < height; y += 1) for (let x = 0; x < width; x += 1) {
12846
12893
  const localx = y % 2 === 0 && grid === "diagonal" ? x + .5 : x;
12847
12894
  const localy = y * ystep;
12848
- if (booleanPointInPolygon(proj4("GOOGLE", "WGS84", [localx / width * X_RANGE + X_MIN, Y_MAX - localy / height * Y_RANGE]), poly)) points[[x, y].join(";")] = {
12895
+ const wgs84Point = proj4(proj4String, "WGS84", [localx / width * X_RANGE + X_MIN, Y_MAX - localy / height * Y_RANGE]);
12896
+ if (!isFinitePoint(wgs84Point) || !booleanPointInPolygon(wgs84Point, poly)) continue;
12897
+ points[[x, y].join(";")] = {
12849
12898
  x: localx,
12850
12899
  y: localy
12851
12900
  };
@@ -12862,17 +12911,19 @@ const getMap = ({ height = 0, width = 0, countries = [], region, grid = "vertica
12862
12911
  grid,
12863
12912
  height,
12864
12913
  width,
12865
- ystep
12914
+ ystep,
12915
+ projection
12866
12916
  };
12867
12917
  };
12868
12918
  const getMapJSON = (props) => JSON.stringify(getMap(props));
12869
- const getCacheKey = ({ height = 0, width = 0, countries = [], region, grid = "vertical" }) => {
12919
+ const getCacheKey = ({ height = 0, width = 0, countries = [], region, grid = "vertical", projection = DEFAULT_PROJECTION }) => {
12870
12920
  return [
12871
12921
  JSON.stringify(region),
12872
12922
  grid,
12873
12923
  height,
12874
12924
  width,
12875
- JSON.stringify(countries)
12925
+ JSON.stringify(countries),
12926
+ JSON.stringify(projection)
12876
12927
  ].join(" ");
12877
12928
  };
12878
12929
  var DottedMap = class extends DottedMapWithoutCountries {
@@ -1,4 +1,12 @@
1
1
  //#region src/types.d.ts
2
+ type ProjectionName = 'mercator' | 'equirectangular' | 'robinson' | 'equalEarth' | 'mollweide' | 'miller' | 'sinusoidal' | 'orthographic' | 'gallPeters' | 'vanDerGrinten';
3
+ interface Projection {
4
+ name: ProjectionName;
5
+ center?: {
6
+ lat: number;
7
+ lng: number;
8
+ };
9
+ }
2
10
  interface Region {
3
11
  lat: {
4
12
  min: number;
@@ -15,6 +23,7 @@ interface MapSettings {
15
23
  countries?: string[];
16
24
  region?: Region;
17
25
  grid?: 'vertical' | 'diagonal';
26
+ projection?: Projection;
18
27
  }
19
28
  interface DottedMapSettings extends MapSettings {
20
29
  avoidOuterPins?: boolean;
@@ -60,6 +69,7 @@ interface MapData {
60
69
  height: number;
61
70
  width: number;
62
71
  ystep: number;
72
+ projection?: Projection;
63
73
  }
64
74
  interface ImageInfo {
65
75
  region: Region;
@@ -67,4 +77,4 @@ interface ImageInfo {
67
77
  height: number;
68
78
  }
69
79
  //#endregion
70
- export { MapSettings as a, Region as c, MapData as i, SvgSettings as l, DottedMapWithoutCountriesSettings as n, PinInput as o, ImageInfo as r, Point as s, DottedMapSettings as t };
80
+ export { MapSettings as a, Projection as c, SvgSettings as d, MapData as i, ProjectionName as l, DottedMapWithoutCountriesSettings as n, PinInput as o, ImageInfo as r, Point as s, DottedMapSettings as t, Region as u };
@@ -1,4 +1,12 @@
1
1
  //#region src/types.d.ts
2
+ type ProjectionName = 'mercator' | 'equirectangular' | 'robinson' | 'equalEarth' | 'mollweide' | 'miller' | 'sinusoidal' | 'orthographic' | 'gallPeters' | 'vanDerGrinten';
3
+ interface Projection {
4
+ name: ProjectionName;
5
+ center?: {
6
+ lat: number;
7
+ lng: number;
8
+ };
9
+ }
2
10
  interface Region {
3
11
  lat: {
4
12
  min: number;
@@ -15,6 +23,7 @@ interface MapSettings {
15
23
  countries?: string[];
16
24
  region?: Region;
17
25
  grid?: 'vertical' | 'diagonal';
26
+ projection?: Projection;
18
27
  }
19
28
  interface DottedMapSettings extends MapSettings {
20
29
  avoidOuterPins?: boolean;
@@ -60,6 +69,7 @@ interface MapData {
60
69
  height: number;
61
70
  width: number;
62
71
  ystep: number;
72
+ projection?: Projection;
63
73
  }
64
74
  interface ImageInfo {
65
75
  region: Region;
@@ -67,4 +77,4 @@ interface ImageInfo {
67
77
  height: number;
68
78
  }
69
79
  //#endregion
70
- export { MapSettings as a, Region as c, MapData as i, SvgSettings as l, DottedMapWithoutCountriesSettings as n, PinInput as o, ImageInfo as r, Point as s, DottedMapSettings as t };
80
+ export { MapSettings as a, Projection as c, SvgSettings as d, MapData as i, ProjectionName as l, DottedMapWithoutCountriesSettings as n, PinInput as o, ImageInfo as r, Point as s, DottedMapSettings as t, Region as u };
@@ -3,6 +3,25 @@ let proj4 = require("proj4");
3
3
  proj4 = require_chunk.__toESM(proj4);
4
4
 
5
5
  //#region src/without-countries.ts
6
+ const PROJECTIONS = {
7
+ mercator: "+proj=merc +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
8
+ equirectangular: "+proj=eqc +lon_0={lng} +lat_ts=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
9
+ robinson: "+proj=robin +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
10
+ equalEarth: "+proj=eqearth +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
11
+ mollweide: "+proj=moll +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12
+ miller: "+proj=mill +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
13
+ sinusoidal: "+proj=sinu +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
14
+ orthographic: "+proj=ortho +lat_0={lat} +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
15
+ gallPeters: "+proj=cea +lon_0={lng} +lat_ts=45 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
16
+ vanDerGrinten: "+proj=vandg +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m"
17
+ };
18
+ const DEFAULT_PROJECTION = { name: "mercator" };
19
+ const getProj4String = (projection = DEFAULT_PROJECTION) => {
20
+ const template = PROJECTIONS[projection.name];
21
+ const lat = projection.center?.lat ?? 0;
22
+ const lng = projection.center?.lng ?? 0;
23
+ return template.replace("{lat}", String(lat)).replace("{lng}", String(lng));
24
+ };
6
25
  var DottedMapWithoutCountries = class {
7
26
  constructor({ map, avoidOuterPins = false }) {
8
27
  this.points = map.points;
@@ -16,6 +35,7 @@ var DottedMapWithoutCountries = class {
16
35
  this.height = map.height;
17
36
  this.ystep = map.ystep;
18
37
  this.avoidOuterPins = avoidOuterPins;
38
+ this.proj4String = getProj4String(map.projection ?? DEFAULT_PROJECTION);
19
39
  this.image = {
20
40
  region: map.region,
21
41
  width: map.width,
@@ -37,16 +57,20 @@ var DottedMapWithoutCountries = class {
37
57
  return point;
38
58
  }
39
59
  getPin({ lat, lng }) {
40
- const [googleX, googleY] = (0, proj4.default)("GOOGLE", [lng, lat]);
60
+ const projected = (0, proj4.default)(this.proj4String, [lng, lat]);
61
+ if (!projected.every((v) => Number.isFinite(v))) return;
62
+ const [projX, projY] = projected;
41
63
  if (this.avoidOuterPins) return;
42
- let rawX = this.width * (googleX - this.X_MIN) / this.X_RANGE;
43
- const rawY = this.height * (this.Y_MAX - googleY) / this.Y_RANGE;
64
+ let rawX = this.width * (projX - this.X_MIN) / this.X_RANGE;
65
+ const rawY = this.height * (this.Y_MAX - projY) / this.Y_RANGE;
44
66
  const y = Math.round(rawY / this.ystep);
45
67
  if (y % 2 === 0 && this.grid === "diagonal") rawX -= .5;
46
68
  let localx = Math.round(rawX);
47
69
  const localy = Math.round(y) * this.ystep;
48
70
  if (y % 2 === 0 && this.grid === "diagonal") localx += .5;
49
- const [localLng, localLat] = (0, proj4.default)("GOOGLE", "WGS84", [localx * this.X_RANGE / this.width + this.X_MIN, this.Y_MAX - localy * this.Y_RANGE / this.height]);
71
+ const inverse = (0, proj4.default)(this.proj4String, "WGS84", [localx * this.X_RANGE / this.width + this.X_MIN, this.Y_MAX - localy * this.Y_RANGE / this.height]);
72
+ if (!inverse.every((v) => Number.isFinite(v))) return;
73
+ const [localLng, localLat] = inverse;
50
74
  return {
51
75
  x: localx,
52
76
  y: localy,
@@ -1,4 +1,4 @@
1
- import { c as Region, i as MapData, l as SvgSettings, n as DottedMapWithoutCountriesSettings, o as PinInput, r as ImageInfo, s as Point } from "./types-ByIhMtjO.cjs";
1
+ import { c as Projection, d as SvgSettings, i as MapData, l as ProjectionName, n as DottedMapWithoutCountriesSettings, o as PinInput, r as ImageInfo, s as Point, u as Region } from "./types-vOcy-UuQ.cjs";
2
2
 
3
3
  //#region src/without-countries.d.ts
4
4
  declare class DottedMapWithoutCountries {
@@ -13,6 +13,7 @@ declare class DottedMapWithoutCountries {
13
13
  private ystep;
14
14
  private avoidOuterPins;
15
15
  private pins;
16
+ private proj4String;
16
17
  image: ImageInfo;
17
18
  constructor({
18
19
  map,
@@ -40,4 +41,4 @@ declare class DottedMapWithoutCountries {
40
41
  }?: SvgSettings): string;
41
42
  }
42
43
  //#endregion
43
- export { type DottedMapWithoutCountriesSettings, type ImageInfo, type MapData, type PinInput, type Point, type Region, type SvgSettings, DottedMapWithoutCountries as default };
44
+ export { type DottedMapWithoutCountriesSettings, type ImageInfo, type MapData, type PinInput, type Point, type Projection, type ProjectionName, type Region, type SvgSettings, DottedMapWithoutCountries as default };
@@ -1,4 +1,4 @@
1
- import { c as Region, i as MapData, l as SvgSettings, n as DottedMapWithoutCountriesSettings, o as PinInput, r as ImageInfo, s as Point } from "./types-UL1f7mia.mjs";
1
+ import { c as Projection, d as SvgSettings, i as MapData, l as ProjectionName, n as DottedMapWithoutCountriesSettings, o as PinInput, r as ImageInfo, s as Point, u as Region } from "./types-F6gvGCSl.mjs";
2
2
 
3
3
  //#region src/without-countries.d.ts
4
4
  declare class DottedMapWithoutCountries {
@@ -13,6 +13,7 @@ declare class DottedMapWithoutCountries {
13
13
  private ystep;
14
14
  private avoidOuterPins;
15
15
  private pins;
16
+ private proj4String;
16
17
  image: ImageInfo;
17
18
  constructor({
18
19
  map,
@@ -40,4 +41,4 @@ declare class DottedMapWithoutCountries {
40
41
  }?: SvgSettings): string;
41
42
  }
42
43
  //#endregion
43
- export { type DottedMapWithoutCountriesSettings, type ImageInfo, type MapData, type PinInput, type Point, type Region, type SvgSettings, DottedMapWithoutCountries as default };
44
+ export { type DottedMapWithoutCountriesSettings, type ImageInfo, type MapData, type PinInput, type Point, type Projection, type ProjectionName, type Region, type SvgSettings, DottedMapWithoutCountries as default };
@@ -1,6 +1,25 @@
1
1
  import proj4 from "proj4";
2
2
 
3
3
  //#region src/without-countries.ts
4
+ const PROJECTIONS = {
5
+ mercator: "+proj=merc +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
6
+ equirectangular: "+proj=eqc +lon_0={lng} +lat_ts=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
7
+ robinson: "+proj=robin +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
8
+ equalEarth: "+proj=eqearth +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
9
+ mollweide: "+proj=moll +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
10
+ miller: "+proj=mill +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
11
+ sinusoidal: "+proj=sinu +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
12
+ orthographic: "+proj=ortho +lat_0={lat} +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m",
13
+ gallPeters: "+proj=cea +lon_0={lng} +lat_ts=45 +x_0=0 +y_0=0 +datum=WGS84 +units=m",
14
+ vanDerGrinten: "+proj=vandg +lon_0={lng} +x_0=0 +y_0=0 +datum=WGS84 +units=m"
15
+ };
16
+ const DEFAULT_PROJECTION = { name: "mercator" };
17
+ const getProj4String = (projection = DEFAULT_PROJECTION) => {
18
+ const template = PROJECTIONS[projection.name];
19
+ const lat = projection.center?.lat ?? 0;
20
+ const lng = projection.center?.lng ?? 0;
21
+ return template.replace("{lat}", String(lat)).replace("{lng}", String(lng));
22
+ };
4
23
  var DottedMapWithoutCountries = class {
5
24
  constructor({ map, avoidOuterPins = false }) {
6
25
  this.points = map.points;
@@ -14,6 +33,7 @@ var DottedMapWithoutCountries = class {
14
33
  this.height = map.height;
15
34
  this.ystep = map.ystep;
16
35
  this.avoidOuterPins = avoidOuterPins;
36
+ this.proj4String = getProj4String(map.projection ?? DEFAULT_PROJECTION);
17
37
  this.image = {
18
38
  region: map.region,
19
39
  width: map.width,
@@ -35,16 +55,20 @@ var DottedMapWithoutCountries = class {
35
55
  return point;
36
56
  }
37
57
  getPin({ lat, lng }) {
38
- const [googleX, googleY] = proj4("GOOGLE", [lng, lat]);
58
+ const projected = proj4(this.proj4String, [lng, lat]);
59
+ if (!projected.every((v) => Number.isFinite(v))) return;
60
+ const [projX, projY] = projected;
39
61
  if (this.avoidOuterPins) return;
40
- let rawX = this.width * (googleX - this.X_MIN) / this.X_RANGE;
41
- const rawY = this.height * (this.Y_MAX - googleY) / this.Y_RANGE;
62
+ let rawX = this.width * (projX - this.X_MIN) / this.X_RANGE;
63
+ const rawY = this.height * (this.Y_MAX - projY) / this.Y_RANGE;
42
64
  const y = Math.round(rawY / this.ystep);
43
65
  if (y % 2 === 0 && this.grid === "diagonal") rawX -= .5;
44
66
  let localx = Math.round(rawX);
45
67
  const localy = Math.round(y) * this.ystep;
46
68
  if (y % 2 === 0 && this.grid === "diagonal") localx += .5;
47
- const [localLng, localLat] = proj4("GOOGLE", "WGS84", [localx * this.X_RANGE / this.width + this.X_MIN, this.Y_MAX - localy * this.Y_RANGE / this.height]);
69
+ const inverse = proj4(this.proj4String, "WGS84", [localx * this.X_RANGE / this.width + this.X_MIN, this.Y_MAX - localy * this.Y_RANGE / this.height]);
70
+ if (!inverse.every((v) => Number.isFinite(v))) return;
71
+ const [localLng, localLat] = inverse;
48
72
  return {
49
73
  x: localx,
50
74
  y: localy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotted-map",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Create a SVG map filled with dots for the world or countries",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",