@lgv/visualization-map 0.0.1 → 0.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lgv/visualization-map",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "description": "ES6 d3.js core visualization scaffold object and utilities for maps.",
6
6
  "main": "src/index.js",
@@ -42,7 +42,7 @@
42
42
  "dependencies": {
43
43
  "@deck.gl/core": "^8.8.20",
44
44
  "@deck.gl/layers": "^8.8.20",
45
- "@lgv/visualization-chart": "^0.3.5",
45
+ "@lgv/visualization-chart": "^0.3.6",
46
46
  "@msrvida/vega-deck.gl": "^3.3.4",
47
47
  "leaflet": "^1.9.2",
48
48
  "vega": "^5.22.1"
@@ -6,12 +6,12 @@ const configuration = {
6
6
  };
7
7
 
8
8
  const configurationColor = {
9
- p1: ["#eb4034","#34ebe5"]
9
+ p1: ["#F7BBB5", "#F37765", "#EF4223", "#992B20", "#37150E"]
10
10
  };
11
11
 
12
12
  const configurationLayout = {
13
13
  height: process.env.LGV_HEIGHT || 400,
14
- tileserver: process.env.LGV_TILESERVER || "https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}{r}.png",
14
+ tileserver: process.env.LGV_TILESERVER || "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
15
15
  width: process.env.LGV_WIDTH || 400
16
16
  }
17
17
 
@@ -30,21 +30,25 @@ class HeatLayout extends MapData {
30
30
 
31
31
  if (this.map && data.type == "FeatureCollection") {
32
32
 
33
- // project to xy
34
- result = data.features.map(d => {
35
-
36
- // convert to xy
37
- let xy = this.map.latLngToContainerPoint(L.latLng(d.geometry.coordinates[1], d.geometry.coordinates[0]));
33
+ let bounds = this.map.getBounds();
38
34
 
39
- return {
40
- count: d.properties.count,
41
- id: d.properties.id,
42
- label: d.properties.name,
43
- x: xy.x,
44
- y: xy.y
45
- }
46
-
47
- });
35
+ // project to xy
36
+ result = data.features
37
+ .filter(d => d.geometry.coordinates[1] >= bounds._southWest.lat && d.geometry.coordinates[1] <= bounds._northEast.lat && d.geometry.coordinates[0] >= bounds._southWest.lng && d.geometry.coordinates[0] <= bounds._northEast.lng)
38
+ .map(d => {
39
+
40
+ // convert to xy
41
+ let xy = this.map.latLngToContainerPoint(L.latLng(d.geometry.coordinates[1], d.geometry.coordinates[0]));
42
+
43
+ return {
44
+ count: d.properties.count,
45
+ id: d.properties.id,
46
+ label: d.properties.name,
47
+ x: xy.x,
48
+ y: xy.y
49
+ }
50
+
51
+ });
48
52
 
49
53
  }
50
54
 
@@ -11,7 +11,7 @@ import { HeatLayout as HL } from "../layout/heat.js";
11
11
  import { configuration, configurationColor, configurationLayout } from "../configuration.js";
12
12
 
13
13
  /**
14
- * VisualizationMap is a map abstraction.
14
+ * Heatmap is a map abstraction for a heatmap visualization.
15
15
  * @param {object} data - usually array; occasionally object
16
16
  * @param {string} label - identifer for chart brand
17
17
  * @param {float} height - specified height of chart
@@ -43,7 +43,7 @@ class Heatmap extends VisualizationMap {
43
43
  let isHighDensityDisplay = window.devicePixelRatio > 1 && window.innerWidth * window.devicePixelRatio > 3360 && window.innerHeight * window.devicePixelRatio > 1942;
44
44
 
45
45
  // set starting size
46
- let base = isHighDensityDisplay ? this.unit * 1.75 : this.unit * 1.5;
46
+ let base = isHighDensityDisplay ? this.unit * 1.75 : this.unit * 2;
47
47
  let mark = base;
48
48
 
49
49
  // determine mark size
@@ -64,7 +64,7 @@ class Heatmap extends VisualizationMap {
64
64
  mark = base - 5;
65
65
  break;
66
66
  }
67
-
67
+ console.log(mark)
68
68
  return mark;
69
69
 
70
70
  }
@@ -72,12 +72,7 @@ class Heatmap extends VisualizationMap {
72
72
  /**
73
73
  * Generate main visualization, i.e. everything that sits inside the map.
74
74
  */
75
- generateChart(e) {
76
-
77
- // process data
78
- // update data object now that map exists
79
- this.Data.map = this.map;
80
- this.data = this.Data.update;
75
+ generateChart() {
81
76
 
82
77
  // generate vega specification
83
78
  let spec = this.generateSpecification();
@@ -123,11 +118,11 @@ class Heatmap extends VisualizationMap {
123
118
  return {
124
119
  width: this.width,
125
120
  height: this.height,
126
- data: [{ name: this.name, values: this.data }],
121
+ data: [{ name: this.name, values: this.isXY ? this.data.results : this.data }],
127
122
  scales: [
128
123
  {
129
124
  name: "color",
130
- type: "log",
125
+ type: "linear",
131
126
  domain: { data: this.name, field: "count" },
132
127
  range: { scheme: this.name, count: configurationColor.p1.length }
133
128
  }
@@ -143,6 +138,7 @@ class Heatmap extends VisualizationMap {
143
138
  y: { field: "y" },
144
139
  size: { value: this.mark },
145
140
  fill: { scale: "color", field: "count" },
141
+ opacity: { value: 1 }
146
142
  },
147
143
  },
148
144
  }
@@ -21,8 +21,18 @@ class VisualizationMap extends LinearGrid {
21
21
  // initialize inheritance
22
22
  super(data, width, height, MapData, label, name);
23
23
 
24
+ // determine type of data object
25
+ this.isFeatureCollection = this.data.features;
26
+ this.isPoint = this.data.coordinates && this.data.type.lower() == "point";
27
+ this.isXY = this.data.metadata && this.data.results;
28
+
29
+ // determine x/y center
30
+ let x = this.isFeatureCollection ? mean(this.data.features, d => d.geometry.coordinates[1]) : (this.isPoint ? this.data.coordinates[1] : mean([this.data.metadata.bounds[0][1],this.data.metadata.bounds[1][1]]));
31
+
32
+ let y = this.isFeatureCollection ? mean(this.data.features, d => d.geometry.coordinates[0]) : (this.isPoint ? this.data.coordinates[0] : mean([this.data.metadata.bounds[0][0],this.data.metadata.bounds[1][0]]));
33
+
24
34
  // update self
25
- this.center = [mean(this.data.features, d => d.geometry.coordinates[1]), mean(this.data.features, d => d.geometry.coordinates[0])];
35
+ this.center = [x,y];
26
36
  this.map = null;
27
37
  this.tileserver = configurationLayout.tileserver;
28
38
  this.zoom = 1;
@@ -30,12 +40,32 @@ class VisualizationMap extends LinearGrid {
30
40
  }
31
41
 
32
42
  /**
33
- * Generate main visualization, i.e. everything that sits inside the svg.
43
+ * Attach event handlers for map events.
34
44
  */
35
- generateChart() {
45
+ attachEvents() {
46
+ this.map.on("moveend", e => {
36
47
 
37
- //
48
+ // update dimensions on class
49
+ let containerSize = this.map.getSize();
50
+ this.heightSpecified = containerSize.y;
51
+ this.widthSpecified = containerSize.x;
38
52
 
53
+ // process data
54
+ // update data object now that map exists
55
+ this.Data.map = this.map;
56
+ this.data = this.Data.update;
57
+
58
+ // render overlay
59
+ this.generateChart();
60
+
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Generate main visualization, i.e. everything that sits inside the svg.
66
+ */
67
+ generateChart() {
68
+ // empty method for specific map visualizations to overwrite
39
69
  }
40
70
 
41
71
  /**
@@ -43,21 +73,56 @@ class VisualizationMap extends LinearGrid {
43
73
  */
44
74
  generateCore() {
45
75
 
46
- // determine averaged center of coordinates
47
- // without curvature of earth accounted for
76
+ // pull dom element styles
77
+ let styles = window.getComputedStyle(this.container.node());
78
+ let height = parseFloat(styles.height.split("px")[0]);
79
+ let width = parseFloat(styles.width.split("px")[0]);
80
+
81
+ // check for unset width or height
82
+ if (height == 0 || width == 0) {
83
+
84
+ // add dom element attribute
85
+ this.container.node().setAttribute(`data-${this.branding}`, this.name);
86
+
87
+ // generate css for account for unset dimension(s)
88
+ let property = `[data-${this.branding}="${this.name}"]`;
89
+ let value = width == 0 && height == 0 ? `{ height: ${this.height}px; width: ${this.width}px; }` : (width == 0 ? `{ width: ${this.width}px; }` : `{ height: ${this.height}px; }`);
90
+
91
+ // generate stylesheet and insert in document
92
+ let style = document.createElement("style");
93
+ style.type = "text/css";
94
+ style.append(document.createTextNode(`${property} ${value}`));
95
+ document.head.append(style);
96
+
97
+ }
98
+
99
+ // update stored dimensions
100
+ if (height > 0) this.heightSpecified = height;
101
+ if (width > 0) this.widthSpecified = width;
102
+
103
+ // initialize map
48
104
  this.map = L.map(this.container.node(), {
49
105
  center: this.center,
50
106
  zoom: this.zoom
51
107
  });
52
108
 
53
109
  // add handlers for leaflet events
54
- this.map.on("moveend", this.generateChart.bind(this));
110
+ this.attachEvents();
55
111
 
56
112
  // update tile server
57
113
  L.tileLayer(this.tileserver).addTo(this.map);
58
114
 
59
- // fit to center + distance
60
- this.map.fitBounds(L.geoJSON(this.Data.source).getBounds());
115
+ // determine bounding box
116
+ let bounds = (this.isFeatureCollection || this.isPoint) ? L.geoJSON(this.Data.source).getBounds() : this.data.metadata.bounds;
117
+
118
+ // fit to bounds
119
+ if (this.isFeatureCollection || this.isXY) {
120
+ // several data points
121
+ this.map.fitBounds(bounds);
122
+ } else {
123
+ // zoom out if only provided single data point
124
+ this.map.setView(bounds.getCenter(), this.map.getMaxZoom() / 2);
125
+ }
61
126
 
62
127
  }
63
128
 
@@ -74,6 +139,37 @@ class VisualizationMap extends LinearGrid {
74
139
 
75
140
  }
76
141
 
142
+ /**
143
+ * Update visualization.
144
+ * @param {object} data - geojson
145
+ * @param {float} height - specified height of chart
146
+ * @param {float} width - specified width of chart
147
+ */
148
+ update(data, width, height) {
149
+
150
+ // update self
151
+ this.heightSpecified = height || this.heightSpecified;
152
+ this.widthSpecified = width || this.widthSpecified;
153
+
154
+ // if layout data object
155
+ if (this.Data.height && this.Data.width) {
156
+
157
+ // update layout attributes
158
+ this.Data.height = this.heightSpecified;
159
+ this.Data.width = this.widthSpecified;
160
+
161
+ }
162
+
163
+ // recalculate values
164
+ this.Data.source = data;
165
+ this.Data.data = this.Data.update;
166
+ this.data = this.Data.data;
167
+
168
+ // generate visualization
169
+ this.generateChart();
170
+
171
+ }
172
+
77
173
  }
78
174
 
79
175
  export { VisualizationMap };