geojs 1.4.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geojs",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "JavaScript Geo Visualization and Analysis Library",
5
5
  "homepage": "https://github.com/OpenGeoscience/geojs",
6
6
  "license": "Apache-2.0",
@@ -37,7 +37,6 @@
37
37
  "babel-plugin-transform-object-rest-spread": "^6.26.0",
38
38
  "babel-polyfill": "^6.26.0",
39
39
  "babel-preset-env": "^1.7.0",
40
- "body-parser": "^1.19.0",
41
40
  "bootstrap": "^3.4.1",
42
41
  "bootswatch": "^3.4.1",
43
42
  "codemirror": "^5.54.0",
@@ -51,7 +50,6 @@
51
50
  "eslint-plugin-node": "^7.0.1",
52
51
  "eslint-plugin-promise": "^4.2.1",
53
52
  "eslint-plugin-standard": "^4.0.1",
54
- "exports-loader": "^0.7.0",
55
53
  "expose-loader": "^0.7.5",
56
54
  "express": "^4.17.1",
57
55
  "file-loader": "^2.0.0",
@@ -86,7 +84,7 @@
86
84
  "phantomjs-prebuilt": "^2.1.5",
87
85
  "pug": "^3.0.1",
88
86
  "pug-lint": "^2.4.0",
89
- "pug-loader": "^2.4.0",
87
+ "pug-load": "^3.0.0",
90
88
  "raw-body": "^2.1.6",
91
89
  "resemblejs": "^3.2.4",
92
90
  "semantic-release": "^17.4.3",
@@ -102,9 +100,7 @@
102
100
  "uglifyjs-webpack-plugin": "^1.2.5",
103
101
  "url-loader": "^1.1.2",
104
102
  "webpack": "^3.12.0",
105
- "webpack-cli": "^2.1.3",
106
- "webpack-merge": "^4.2.2",
107
- "webpack-serve": "^1.0.2"
103
+ "webpack-merge": "^4.2.2"
108
104
  },
109
105
  "release": {
110
106
  "plugins": [
package/src/annotation.js CHANGED
@@ -1129,8 +1129,10 @@ function continuousVerticesProcessAction(m_this, evt, name) {
1129
1129
  }
1130
1130
  var cpp = layer.options('continuousPointProximity');
1131
1131
  var cpc = layer.options('continuousPointColinearity');
1132
+ var ccp = layer.options('continuousCloseProximity');
1132
1133
  if (cpp || cpp === 0) {
1133
1134
  var vertices = m_this.options('vertices');
1135
+ var update = false;
1134
1136
  if (!vertices.length) {
1135
1137
  vertices.push(evt.mouse.mapgcs);
1136
1138
  vertices.push(evt.mouse.mapgcs);
@@ -1152,8 +1154,18 @@ function continuousVerticesProcessAction(m_this, evt, name) {
1152
1154
  }
1153
1155
  vertices[vertices.length - 1] = evt.mouse.mapgcs;
1154
1156
  vertices.push(evt.mouse.mapgcs);
1155
- return true;
1157
+ update = true;
1158
+ }
1159
+ if ((ccp || ccp === 0) && evt.event === geo_event.actionup &&
1160
+ (ccp === true || layer.displayDistance(vertices[0], null, evt.mouse.map, 'display') <= cpp)) {
1161
+ if (vertices.length < 3 + (name === 'polygon' ? 1 : 0)) {
1162
+ return 'remove';
1163
+ }
1164
+ vertices.pop();
1165
+ m_this.state(annotationState.done);
1166
+ return 'done';
1156
1167
  }
1168
+ return update;
1157
1169
  }
1158
1170
  }
1159
1171
 
@@ -24,6 +24,10 @@ var textFeature = require('./textFeature');
24
24
  * @property {number} [continuousPointColinearity=1.0deg] The minimum angle
25
25
  * between a series of three points when dragging to not interpret them as
26
26
  * colinear. Only applies if `continuousPointProximity` is not `false`.
27
+ * @property {number} [continuousCloseProximity=10] The minimum distance in
28
+ * display coordinates (pixels) to close a polygon or end drawing a line when
29
+ * dragging to create an annotation. `false` never closes at the end of a
30
+ * drag. `true` is effectively infinite.
27
31
  * @property {number} [finalPointProximity=10] The maximum distance in display
28
32
  * coordinates (pixels) between the starting point and the mouse coordinates
29
33
  * to signal closing a polygon. A value of 0 requires an exact match. A
@@ -133,6 +137,7 @@ var annotationLayer = function (arg) {
133
137
  // in radians, minimum angle between continuous points to interpret them as
134
138
  // being coliner
135
139
  continuousPointColinearity: 1.0 * Math.PI / 180,
140
+ continuousCloseProximity: 10, // in pixels, 0 is exact
136
141
  finalPointProximity: 10, // in pixels, 0 is exact
137
142
  showLabels: true,
138
143
  clickToEdit: false
@@ -39,6 +39,7 @@ var canvas_heatmapFeature = function (arg) {
39
39
  m_heatMapTransform,
40
40
  s_init = this._init,
41
41
  s_update = this._update,
42
+ m_lastRenderDuration,
42
43
  m_renderTime = timestamp();
43
44
 
44
45
  /**
@@ -72,15 +73,22 @@ var canvas_heatmapFeature = function (arg) {
72
73
  };
73
74
 
74
75
  /**
75
- * Create circle for each data point.
76
+ * Create a circle to render at each data point.
76
77
  *
77
78
  * @returns {this}
78
79
  */
79
80
  this._createCircle = function () {
80
- var circle, ctx, r, r2, blur, gaussian;
81
+ var circle, ctx, r, r2, blur, gaussian, scale;
81
82
  r = m_this.style('radius');
82
83
  blur = m_this.style('blurRadius');
83
84
  gaussian = m_this.style('gaussian');
85
+ scale = m_this.style('scaleWithZoom');
86
+ if (scale) {
87
+ let zoom = this.layer().map().zoom();
88
+ scale = Math.pow(2, zoom);
89
+ r *= scale;
90
+ blur *= scale;
91
+ }
84
92
  if (!m_this._circle || m_this._circle.gaussian !== gaussian ||
85
93
  m_this._circle.radius !== r || m_this._circle.blurRadius !== blur) {
86
94
  circle = m_this._circle = document.createElement('canvas');
@@ -298,6 +306,7 @@ var canvas_heatmapFeature = function (arg) {
298
306
  this._renderOnCanvas = function (context2d, map) {
299
307
 
300
308
  if (m_renderTime.timestamp() < m_this.buildTime().timestamp()) {
309
+ let starttime = Date.now();
301
310
  var data = m_this.data() || [],
302
311
  radius = m_this.style('radius') + m_this.style('blurRadius'),
303
312
  binned = m_this.binned(),
@@ -305,9 +314,12 @@ var canvas_heatmapFeature = function (arg) {
305
314
  layer = m_this.layer(),
306
315
  mapSize = map.size();
307
316
 
317
+ if (m_this.style('scaleWithZoom')) {
318
+ radius *= Math.pow(2, map.zoom());
319
+ }
308
320
  /* Determine if we should bin the data */
309
321
  if (binned === true || binned === 'auto') {
310
- binned = Math.max(Math.floor(radius / 8), 3);
322
+ binned = Math.max(Math.floor(radius / 8), Math.max(1.5, Math.min(3, radius / 2.5)));
311
323
  if (m_this.binned() === 'auto') {
312
324
  var numbins = (Math.ceil((mapSize.width + radius * 2) / binned) *
313
325
  Math.ceil((mapSize.height + radius * 2) / binned));
@@ -325,20 +337,22 @@ var canvas_heatmapFeature = function (arg) {
325
337
  context2d.setTransform(1, 0, 0, 1, 0, 0);
326
338
  context2d.clearRect(0, 0, mapSize.width, mapSize.height);
327
339
  m_heatMapTransform = '';
328
- map.scheduleAnimationFrame(m_this._setTransform, false);
329
- layer.canvas().css({transform: ''});
330
-
331
- m_this._createCircle();
332
- m_this._computeGradient();
333
- if (!binned) {
334
- m_this._renderPoints(context2d, map, data, radius);
335
- } else {
336
- m_this._renderBinnedData(context2d, map, data, radius, binned);
340
+ if (radius > 0.5 && radius < 8192) {
341
+ map.scheduleAnimationFrame(m_this._setTransform, false);
342
+ layer.canvas().css({transform: ''});
343
+
344
+ m_this._createCircle();
345
+ m_this._computeGradient();
346
+ if (!binned) {
347
+ m_this._renderPoints(context2d, map, data, radius);
348
+ } else {
349
+ m_this._renderBinnedData(context2d, map, data, radius, binned);
350
+ }
351
+ canvas = layer.canvas()[0];
352
+ pixelArray = context2d.getImageData(0, 0, canvas.width, canvas.height);
353
+ m_this._colorize(pixelArray.data, m_this._grad);
354
+ context2d.putImageData(pixelArray, 0, 0);
337
355
  }
338
- canvas = layer.canvas()[0];
339
- pixelArray = context2d.getImageData(0, 0, canvas.width, canvas.height);
340
- m_this._colorize(pixelArray.data, m_this._grad);
341
- context2d.putImageData(pixelArray, 0, 0);
342
356
 
343
357
  m_heatMapPosition = {
344
358
  zoom: map.zoom(),
@@ -350,6 +364,7 @@ var canvas_heatmapFeature = function (arg) {
350
364
  };
351
365
  m_renderTime.modified();
352
366
  layer.renderer().clearCanvas(false);
367
+ m_lastRenderDuration = Date.now() - starttime;
353
368
  }
354
369
 
355
370
  return m_this;
@@ -440,6 +455,14 @@ var canvas_heatmapFeature = function (arg) {
440
455
  parseFloat((rotation - m_heatMapPosition.rotation).toFixed(4)) !== 0 ||
441
456
  parseFloat(origin.x.toFixed(1)) !== 0 ||
442
457
  parseFloat(origin.y.toFixed(1)) !== 0) {
458
+ let delay = m_this.updateDelay();
459
+ if (delay < 0 && m_lastRenderDuration) {
460
+ delay = m_lastRenderDuration - Math.floor(1000 / 60 * delay);
461
+ } else if (m_lastRenderDuration) {
462
+ delay = m_lastRenderDuration * 2;
463
+ } else {
464
+ delay = 100;
465
+ }
443
466
  m_heatMapPosition.timeout = window.setTimeout(function () {
444
467
  m_heatMapPosition.timeout = undefined;
445
468
  m_this.buildTime().modified();
@@ -19,8 +19,11 @@ var transform = require('./transform');
19
19
  * @property {number} [minIntensity=null] Minimum intensity of the data.
20
20
  * Minimum intensity must be a positive real number and is used to normalize
21
21
  * all intensities within a dataset. If `null`, it is computed.
22
- * @property {number} [updateDelay=1000] Delay in milliseconds after a zoom,
23
- * rotate, or pan event before recomputing the heatmap.
22
+ * @property {number} [updateDelay=-1] Delay in milliseconds after a zoom,
23
+ * rotate, or pan event before recomputing the heatmap. If 0, this is double
24
+ * the last render time. If negative, it is roughly the last render time
25
+ * plus the absolute value of the specified number of refresh intervals.
26
+ * compute a delay based on the last heatmap render time.
24
27
  * @property {boolean|number|'auto'} [binned='auto'] If `true` or a number,
25
28
  * spatially bin data as part of producing the heatmap. If falsy, each
26
29
  * datapoint stands on its own. If `'auto'`, bin data if there are more data
@@ -37,6 +40,11 @@ var transform = require('./transform');
37
40
  * approximation. The total weight of the gaussian area is approximately the
38
41
  * `9/16 r^2`. The sum of `radius + blurRadius` is used as the radius for
39
42
  * the gaussian distribution.
43
+ * @property {boolean} [scaleWithZoom=false] If truthy, the value for radius
44
+ * and blurRadius scale with zoom. In this case, the values for radius and
45
+ * blurRadius are the values at zoom-level zero. If the scaled radius is
46
+ * less than 0.5 or more than 8192 screen pixels, the heatmap will not
47
+ * render.
40
48
  */
41
49
 
42
50
  /**
@@ -76,7 +84,7 @@ var heatmapFeature = function (arg) {
76
84
  m_maxIntensity = arg.maxIntensity !== undefined ? arg.maxIntensity : null;
77
85
  m_minIntensity = arg.minIntensity !== undefined ? arg.minIntensity : null;
78
86
  m_binned = arg.binned !== undefined ? arg.binned : 'auto';
79
- m_updateDelay = arg.updateDelay ? parseInt(arg.updateDelay, 10) : 1000;
87
+ m_updateDelay = (arg.updateDelay || arg.updateDelay === 0) ? parseInt(arg.updateDelay, 10) : -1;
80
88
 
81
89
  /**
82
90
  * Get/Set maxIntensity.
@@ -121,7 +129,9 @@ var heatmapFeature = function (arg) {
121
129
  *
122
130
  * @param {number} [val] If not specified, return the current update delay.
123
131
  * If specified, this is the delay in milliseconds after a zoom, rotate,
124
- * or pan event before recomputing the heatmap.
132
+ * or pan event before recomputing the heatmap. If 0, this is double the
133
+ * last render time. If negative, it is roughly the last render time plus
134
+ * the absolute value of the specified number of refresh intervals.
125
135
  * @returns {number|this}
126
136
  */
127
137
  this.updateDelay = function (val) {
@@ -233,7 +243,8 @@ var heatmapFeature = function (arg) {
233
243
  0.25: {r: 0, g: 0, b: 1, a: 0.5},
234
244
  0.5: {r: 0, g: 1, b: 1, a: 0.6},
235
245
  0.75: {r: 1, g: 1, b: 0, a: 0.7},
236
- 1: {r: 1, g: 0, b: 0, a: 0.8}}
246
+ 1: {r: 1, g: 0, b: 0, a: 0.8}},
247
+ scaleWithZoom: false
237
248
  },
238
249
  arg.style === undefined ? {} : arg.style
239
250
  );
package/src/osmLayer.js CHANGED
@@ -131,6 +131,9 @@ let StamenAttribution = 'Map tiles by <a href="http://stamen.com">Stamen ' +
131
131
  'CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap' +
132
132
  '</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.';
133
133
 
134
+ /* Per Carto's website regarding basemap attribution: https://carto.com/help/working-with-data/attribution/#basemaps */
135
+ let CartoAttribution = '<a href="https://carto.com"> Carto</a> ' + 'Contributors <a href="https://www.openstreetmap.org/"> OpenStreetMap</a>';
136
+
134
137
  /**
135
138
  * This is a list of known tile sources. It can be added to via
136
139
  * `geo.osmLayer.tilesource[<key>] = <object>`, where the object has `url`,
@@ -139,9 +142,24 @@ let StamenAttribution = 'Map tiles by <a href="http://stamen.com">Stamen ' +
139
142
  * @type {object}
140
143
  */
141
144
  osmLayer.tileSources = {
145
+ 'dark-matter-with-labels': {
146
+ url: ' https://{s}.basemaps.cartocdn.com/rastertiles/dark_all/{z}/{x}/{y}.png',
147
+ attribution: CartoAttribution,
148
+ name: 'Carto Dark Matter With Labels',
149
+ minLevel: 0,
150
+ maxLevel: 18
151
+ },
152
+ 'dark-matter-without-labels': {
153
+ url: 'https://{s}.basemaps.cartocdn.com/rastertiles/dark_nolabels/{z}/{x}/{y}.png',
154
+ attribution: CartoAttribution,
155
+ name: 'Carto Dark Matter Without Labels',
156
+ minLevel: 0,
157
+ maxLevel: 18
158
+ },
142
159
  'nationalmap-satellite': {
143
160
  url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}',
144
161
  attribution: 'Tile data from <a href="https://basemap.nationalmap.gov/">USGS</a>',
162
+ name:'National Map Satellite',
145
163
  minLevel: 0,
146
164
  maxLevel: 16
147
165
  },
@@ -149,13 +167,29 @@ osmLayer.tileSources = {
149
167
  url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
150
168
  attribution: 'Tile data &copy; <a href="https://osm.org/copyright">' +
151
169
  'OpenStreetMap</a> contributors',
170
+ name:'OpenStreetMap',
152
171
  subdomains: 'abc',
153
172
  minLevel: 0,
154
173
  maxLevel: 19
155
174
  },
175
+ 'positron-with-labels': {
176
+ url: 'https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png',
177
+ attribution: CartoAttribution,
178
+ name:'Carto Positron With Labels',
179
+ minLevel: 0,
180
+ maxLevel: 18
181
+ },
182
+ 'positron-without-labels': {
183
+ url: 'https://{s}.basemaps.cartocdn.com/rastertiles/light_nolabels/{z}/{x}/{y}.png',
184
+ attribution: CartoAttribution,
185
+ name:'Carto Positron Without Labels',
186
+ minLevel: 0,
187
+ maxLevel: 18
188
+ },
156
189
  'stamen-terrain': {
157
190
  url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png',
158
191
  attribution: StamenAttribution,
192
+ name:'Stamen Terrain',
159
193
  subdomains: 'abcd',
160
194
  minLevel: 0,
161
195
  maxLevel: 14
@@ -163,6 +197,7 @@ osmLayer.tileSources = {
163
197
  'stamen-terrain-background': {
164
198
  url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png',
165
199
  attribution: StamenAttribution,
200
+ name:'Stamen Terrain Background',
166
201
  subdomains: 'abcd',
167
202
  minLevel: 0,
168
203
  maxLevel: 14
@@ -170,6 +205,7 @@ osmLayer.tileSources = {
170
205
  'stamen-toner': {
171
206
  url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png',
172
207
  attribution: StamenAttribution,
208
+ name:'Stamen Toner',
173
209
  subdomains: 'abcd',
174
210
  minLevel: 0,
175
211
  maxLevel: 20
@@ -177,15 +213,24 @@ osmLayer.tileSources = {
177
213
  'stamen-toner-lite': {
178
214
  url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png',
179
215
  attribution: StamenAttribution,
216
+ name:'Stamen Toner Lite',
180
217
  subdomains: 'abcd',
181
218
  minLevel: 0,
182
219
  maxLevel: 20
183
220
  },
184
- 'wikimedia': {
185
- url: 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png',
186
- attribution: '<a href="https://wikimediafoundation.org/wiki/Maps_Terms_of_Use">Wikimedia maps</a> | Map data &copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap contributors</a>',
221
+ 'voyager-with-labels': {
222
+ url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png',
223
+ attribution: CartoAttribution,
224
+ name:'Carto Voyager With Labels',
187
225
  minLevel: 0,
188
- maxLevel: 19
226
+ maxLevel: 18
227
+ },
228
+ 'voyager-without-layers': {
229
+ url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png',
230
+ attribution: CartoAttribution,
231
+ name:'Carto Voyager Without Layers',
232
+ minLevel: 0,
233
+ maxLevel: 18
189
234
  }
190
235
  };
191
236
 
@@ -85,6 +85,7 @@ module.exports.mockWebglRenderer = function mockWebglRenderer(supported) {
85
85
  enable: noop('enable'),
86
86
  enableVertexAttribArray: noop('enableVertexAttribArray'),
87
87
  finish: noop('finish'),
88
+ getError: noop('getError'),
88
89
  getExtension: incID('getExtension'),
89
90
  getParameter: function (key) {
90
91
  count('getParameter');
@@ -361,7 +361,9 @@ var webgl_quadFeature = function (arg) {
361
361
  return;
362
362
  }
363
363
  quad.texture.bind(renderState);
364
-
364
+ if (context.getError() === context.OUT_OF_MEMORY) {
365
+ console.log('Insufficient GPU memory for texture');
366
+ }
365
367
  if (quad.opacity !== opacity) {
366
368
  opacity = quad.opacity;
367
369
  context.uniform1fv(renderState.m_material.shaderProgram()