@lgv/visualization-map 0.0.4 → 0.0.7

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/.gitlab-ci.yml CHANGED
@@ -6,10 +6,6 @@ stages:
6
6
  include:
7
7
  ###################################### GITLAB TEMPLATES ######################################
8
8
  - template: Security/SAST.gitlab-ci.yml
9
-
10
- # overwrites
11
- - project: "lgensinger/cicd-templates"
12
- file: "node/module/eslint-sast.yml"
13
9
 
14
10
  - project: "lgensinger/cicd-templates"
15
11
  file: "node/module/nodejs-scan-sast.yml"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lgv/visualization-map",
3
- "version": "0.0.4",
3
+ "version": "0.0.7",
4
4
  "type": "module",
5
5
  "description": "ES6 d3.js core visualization scaffold object and utilities for maps.",
6
6
  "main": "src/index.js",
@@ -34,6 +34,7 @@
34
34
  "browser-env": "^3.3.0",
35
35
  "c8": "^7.11.3",
36
36
  "css-loader": "^6.7.2",
37
+ "file-loader": "^6.2.0",
37
38
  "html-webpack-plugin": "^5.3.2",
38
39
  "style-loader": "^3.3.1",
39
40
  "webpack": "^5.86.0",
@@ -43,9 +44,10 @@
43
44
  "dependencies": {
44
45
  "@deck.gl/core": "^8.8.20",
45
46
  "@deck.gl/layers": "^8.8.20",
46
- "@lgv/visualization-chart": "^0.3.21",
47
+ "@lgv/visualization-chart": "^0.3.26",
47
48
  "@msrvida/vega-deck.gl": "^3.3.4",
48
49
  "leaflet": "^1.9.2",
50
+ "leaflet.markercluster": "^1.5.3",
49
51
  "vega": "^5.22.1"
50
52
  },
51
53
  "ava": {
package/src/index.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import { HeatLayout } from "./layout/heat.js";
2
+ import { MapLayout } from "./layout/map.js";
2
3
 
3
4
  import { MapData } from "./structure/index.js";
4
5
 
6
+ import { Clustermap } from "./visualization/cluster.js";
5
7
  import { Heatmap } from "./visualization/heatmap.js";
8
+ import { Routemap } from "./visualization/route.js";
6
9
  import { VisualizationMap } from "./visualization/index.js";
7
10
 
8
- export { HeatLayout, Heatmap, MapData, VisualizationMap };
11
+ export { Clustermap, HeatLayout, Heatmap, MapData, MapLayout, Routemap, VisualizationMap };
@@ -1,22 +1,19 @@
1
1
  import L from "leaflet";
2
2
 
3
- import { MapData } from "../structure/index.js";
3
+ import { MapLayout } from "./map.js";
4
4
 
5
5
  /**
6
6
  * HeatLayout is a data-bound layout abstraction for a heatmap.
7
7
  * @param {array} data - geojson
8
8
  * @param {class} map - Leaflet map object
9
9
  */
10
- class HeatLayout extends MapData {
10
+ class HeatLayout extends MapLayout {
11
11
 
12
12
  constructor(data, map) {
13
13
 
14
14
  // initialize inheritance
15
15
  super(data);
16
16
 
17
- // update self
18
- this.map = map;
19
-
20
17
  }
21
18
 
22
19
  /**
@@ -0,0 +1,23 @@
1
+ import { MapData } from "../structure/index.js";
2
+
3
+ /**
4
+ * MapLayout is a data-bound layout abstraction for a leaflet map.
5
+ * @param {array} data - geojson
6
+ * @param {class} map - Leaflet map object
7
+ */
8
+ class MapLayout extends MapData {
9
+
10
+ constructor(data, map) {
11
+
12
+ // initialize inheritance
13
+ super(data);
14
+
15
+ // update self
16
+ this.map = map;
17
+
18
+ }
19
+
20
+ }
21
+
22
+ export { MapLayout };
23
+ export default MapLayout;
@@ -0,0 +1,63 @@
1
+ import L from "leaflet";
2
+ import MarkerClusterGroup from "leaflet.markercluster";
3
+ import defaultIcon from "leaflet/dist/images/marker-icon.png";
4
+
5
+ import { VisualizationMap } from "./index.js";
6
+ import { MapLayout as ML } from "../layout/map.js";
7
+
8
+ import { configuration, configurationLayout } from "../configuration.js";
9
+
10
+ /**
11
+ * Clustermap is a map abstraction for a clustered visualization.
12
+ * @param {object} data - usually array; occasionally object
13
+ * @param {string} label - identifer for chart brand
14
+ * @param {float} height - specified height of chart
15
+ * @param {object} markerIcon - Leaflet object
16
+ * @param {class} MapData - lgv data class
17
+ * @param {string} name - name of chart
18
+ * @param {float} width - specified width of chart
19
+ */
20
+ class Clustermap extends VisualizationMap {
21
+
22
+ constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapLayout=null, markerIcon=L.icon({iconUrl: defaultIcon}), tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
23
+
24
+ // initialize inheritance
25
+ super(data, width, height, MapLayout ? MapLayout : new ML(data), tileServerUrl, label, name);
26
+
27
+ // set default icon
28
+ L.Marker.prototype.setIcon(markerIcon);
29
+
30
+ // initialize marker group
31
+ this.markerClusterGroup = L.markerClusterGroup();
32
+
33
+ }
34
+
35
+ /**
36
+ * Generate main visualization, i.e. everything that sits inside the map.
37
+ */
38
+ generateChart() {
39
+
40
+ // check if marker group exists
41
+ if (!this.map.hasLayer(this.markerClusterGroup)) {
42
+
43
+ // add popup info to marker
44
+ let geoJsonLayer = L.geoJson(this.data, {
45
+ onEachFeature: function (feature, layer) {
46
+ layer.bindPopup(`<div><div id="popup-poster"><div data-id="${feature.properties.id}" style="background-image: url(${feature.properties.poster})"></div></div><div><p><strong>${feature.properties.label}</strong></p><p>${feature.properties.value}</p></div>`);
47
+ }
48
+ });
49
+
50
+ // add markers to group
51
+ this.markerClusterGroup.addLayer(geoJsonLayer);
52
+
53
+ // add marker layer to map
54
+ this.map.addLayer(this.markerClusterGroup);
55
+
56
+ }
57
+
58
+ }
59
+
60
+ }
61
+
62
+ export { Clustermap };
63
+ export default Clustermap;
@@ -21,10 +21,10 @@ import { configuration, configurationColor, configurationLayout } from "../confi
21
21
  */
22
22
  class Heatmap extends VisualizationMap {
23
23
 
24
- constructor(data, width=configurationLayout.width, height=configurationLayout.height, HeatLayout=null, label=configuration.branding, name=configuration.name) {
24
+ constructor(data, width=configurationLayout.width, height=configurationLayout.height, HeatLayout=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
25
25
 
26
26
  // initialize inheritance
27
- super(data, width, height, HeatLayout ? HeatLayout : new HL(data), label, name);
27
+ super(data, width, height, HeatLayout ? HeatLayout : new HL(data), tileServerUrl, label, name);
28
28
 
29
29
  // initialize vega
30
30
  VegaDeckGl.use(vega, deck, layers, luma);
@@ -1,7 +1,9 @@
1
- import { degreeToRadian, LinearGrid, radianToDegree } from "@lgv/visualization-chart";
1
+ import { LinearGrid } from "@lgv/visualization-chart";
2
2
  import { mean } from "d3-array";
3
3
  import L from "leaflet";
4
4
  import "leaflet/dist/leaflet.css";
5
+ import "leaflet/dist/images/marker-shadow.png";
6
+ import "./marker-cluster.css";
5
7
 
6
8
  import { configuration, configurationLayout } from "../configuration.js";
7
9
 
@@ -16,7 +18,7 @@ import { configuration, configurationLayout } from "../configuration.js";
16
18
  */
17
19
  class VisualizationMap extends LinearGrid {
18
20
 
19
- constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapData=null, label=configuration.branding, name=configuration.name) {
21
+ constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapData=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
20
22
 
21
23
  // initialize inheritance
22
24
  super(data, width, height, MapData, label, name);
@@ -25,14 +27,13 @@ class VisualizationMap extends LinearGrid {
25
27
  this.determineDataType();
26
28
 
27
29
  // determine x/y center
28
- let x = this.isFeatureCollection ? mean(this.data.features, d => d.geometry.coordinates[1]) : (this.isPoint ? this.data.coordinates[1] : (this.isXY ? mean([this.data.metadata.bounds[0][1],this.data.metadata.bounds[1][1]]) : 0));
29
-
30
- let y = this.isFeatureCollection ? mean(this.data.features, d => d.geometry.coordinates[0]) : (this.isPoint ? this.data.coordinates[0] : (this.isXY ? mean([this.data.metadata.bounds[0][0],this.data.metadata.bounds[1][0]]) : 0));
31
-
30
+ let x = this.isFeatureCollection ? mean(this.data.features, d => typeof(d.geometry.coordinates[0]) == "object" ? mean(d.geometry.coordinates.map(x => x[1]).flat()) : d.geometry.coordinates[1]) : (this.isPoint ? this.data.coordinates[1] : (this.isXY ? mean([this.data.metadata.bounds[0][1],this.data.metadata.bounds[1][1]]) : 0));
31
+ let y = this.isFeatureCollection ? mean(this.data.features, d => typeof(d.geometry.coordinates[0]) == "object" ? mean(d.geometry.coordinates.map(x => x[0]).flat()) : d.geometry.coordinates[0]) : (this.isPoint ? this.data.coordinates[0] : (this.isXY ? mean([this.data.metadata.bounds[0][0],this.data.metadata.bounds[1][0]]) : 0));
32
+
32
33
  // update self
33
34
  this.center = [x,y];
34
35
  this.map = null;
35
- this.tileserver = configurationLayout.tileserver;
36
+ this.tileServerUrl = tileServerUrl;
36
37
  this.zoom = 1;
37
38
 
38
39
  }
@@ -68,7 +69,7 @@ class VisualizationMap extends LinearGrid {
68
69
  * Generate main visualization, i.e. everything that sits inside the svg.
69
70
  */
70
71
  determineDataType() {
71
- this.isFeatureCollection = this.data && this.Data.source.features;
72
+ this.isFeatureCollection = this.data !== (null || undefined) && this.Data.source.features !== (null || undefined);
72
73
  this.isPoint = this.data && this.data.coordinates && this.data.type.lower() == "point";
73
74
  this.isXY = this.data && this.data.metadata && this.data.results;
74
75
  }
@@ -143,7 +144,7 @@ class VisualizationMap extends LinearGrid {
143
144
  this.attachEvents();
144
145
 
145
146
  // update tile server
146
- L.tileLayer(this.tileserver).addTo(this.map);
147
+ L.tileLayer(this.tileServerUrl).addTo(this.map);
147
148
 
148
149
  // fit to bounds
149
150
  this.fitToData();
@@ -0,0 +1,108 @@
1
+ :root {
2
+
3
+ --marker-cluster-small: rgba(181, 226, 140, 0.6);
4
+ --marker-cluster-small-div: rgba(110, 204, 57, 0.6);
5
+ --marker-cluster-medium: rgba(241, 211, 87, 0.6);
6
+ --marker-cluster-medium-div: rgba(240, 194, 12, 0.6);
7
+ --marker-cluster-large: rgba(253, 156, 115, 0.6);
8
+ --marker-cluster-large-div: rgba(241, 128, 23, 0.6);
9
+
10
+ }
11
+
12
+ .marker-cluster-small {
13
+ background-color: var(--marker-cluster-small);
14
+ }
15
+ .marker-cluster-small div {
16
+ background-color: var(--marker-cluster-small-div);
17
+ }
18
+
19
+ .marker-cluster-medium {
20
+ background-color: var(--marker-cluster-medium);
21
+ }
22
+ .marker-cluster-medium div {
23
+ background-color: var(--marker-cluster-medium-div);
24
+ }
25
+
26
+ .marker-cluster-large {
27
+ background-color: var(--marker-cluster-large);
28
+ }
29
+ .marker-cluster-large div {
30
+ background-color: var(--marker-cluster-large-div);
31
+ }
32
+
33
+ .marker-cluster {
34
+ background-clip: padding-box;
35
+ border-radius: 2.5em;
36
+ }
37
+ .marker-cluster div {
38
+ width: 2.5em;
39
+ height: 2.5em;
40
+ text-align: center;
41
+ border-radius: 2.5em;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content:center;
45
+ margin-left: 0.45em;
46
+ margin-top: 0.45em;
47
+ }
48
+
49
+ /***************** POP UP *****************/
50
+
51
+ .cluster-map .leaflet-popup-content {
52
+
53
+ margin-bottom: 0;
54
+ margin-left: 0;
55
+ margin-top: 0;
56
+
57
+ }
58
+
59
+ /* wrap */
60
+ .cluster-map .leaflet-popup-content > div {
61
+
62
+ display: flex;
63
+
64
+ }
65
+
66
+ /* poster parent */
67
+ .cluster-map .leaflet-popup-content > div > div:first-of-type {
68
+
69
+ height: 100%;
70
+ overflow: hidden;
71
+
72
+ }
73
+
74
+ /* poster */
75
+ .cluster-map .leaflet-popup-content > div > div:first-of-type > div {
76
+
77
+ background-position: center;
78
+ background-repeat: no-repeat;
79
+ background-size: cover;
80
+ cursor: pointer;
81
+ height: 5em;
82
+ margin-right: 1em;
83
+ transition: .3s cubic-bezier(.25,.8,.25,1);
84
+ transition-property: transform;
85
+ width: 5em;
86
+
87
+ }
88
+
89
+ .cluster-map .leaflet-popup-content > div > div:first-of-type:hover > div,
90
+ .cluster-map .leaflet-popup-content > div > div:first-of-type:focus > div {
91
+
92
+ transform: scale(1.1);
93
+
94
+ }
95
+
96
+ /* text wrap */
97
+ .cluster-map .leaflet-popup-content > div > div:last-of-type {
98
+
99
+ margin-top: 1em;
100
+
101
+ }
102
+
103
+ /* text */
104
+ .cluster-map .leaflet-popup-content p {
105
+
106
+ margin: 0;
107
+
108
+ }
@@ -0,0 +1,43 @@
1
+ import { select, Selection } from "d3-selection";
2
+ //import { transition, Transition } from "d3-transition";
3
+ import transition from "d3-transition";
4
+ import "d3-transition";
5
+ import L from "leaflet";
6
+
7
+ import { VisualizationMap } from "./index.js";
8
+ import { MapLayout as ML } from "../layout/map.js";
9
+
10
+ import { configuration, configurationLayout } from "../configuration.js";
11
+
12
+ /**
13
+ * Routemap is a map abstraction for a routing visualization.
14
+ * @param {object} data - usually array; occasionally object
15
+ * @param {string} label - identifer for chart brand
16
+ * @param {float} height - specified height of chart
17
+ * @param {class} MapData - lgv data class
18
+ * @param {string} name - name of chart
19
+ * @param {float} width - specified width of chart
20
+ */
21
+ class Routemap extends VisualizationMap {
22
+
23
+ constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapLayout=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
24
+
25
+ // initialize inheritance
26
+ super(data, width, height, MapLayout ? MapLayout : new ML(data), tileServerUrl, label, name);
27
+
28
+ }
29
+
30
+ /**
31
+ * Generate main visualization, i.e. everything that sits inside the map.
32
+ */
33
+ generateChart() {
34
+
35
+ // add lines
36
+ L.geoJSON(this.data).addTo(this.map);
37
+
38
+ }
39
+
40
+ }
41
+
42
+ export { Routemap };
43
+ export default Routemap;
package/webpack.common.js CHANGED
@@ -33,6 +33,14 @@ const commonConfig = {
33
33
  {
34
34
  test: /\.css$/i,
35
35
  use: ["style-loader", "css-loader"]
36
+ },
37
+ {
38
+ test: /\.(png|jpe?g|gif)$/i,
39
+ use: [
40
+ {
41
+ loader: 'file-loader',
42
+ }
43
+ ]
36
44
  }
37
45
  ]
38
46
  }