@lgv/visualization-map 0.0.5 → 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/package.json +4 -2
- package/src/index.js +4 -1
- package/src/layout/heat.js +2 -5
- package/src/layout/map.js +23 -0
- package/src/visualization/cluster.js +63 -0
- package/src/visualization/index.js +7 -6
- package/src/visualization/marker-cluster.css +108 -0
- package/src/visualization/route.js +43 -0
- package/webpack.common.js +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lgv/visualization-map",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
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 };
|
package/src/layout/heat.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import L from "leaflet";
|
|
2
2
|
|
|
3
|
-
import {
|
|
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
|
|
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;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
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
|
|
|
@@ -25,10 +27,9 @@ 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
|
-
|
|
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;
|
|
@@ -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
|
}
|
|
@@ -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;
|