geojs 1.6.3 → 1.7.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/CHANGELOG.md +31 -1
- package/README.md +14 -9
- package/geo.js +1101 -417
- package/geo.lean.js +1101 -417
- package/geo.lean.min.js +3 -3
- package/geo.min.js +5 -5
- package/package.json +6 -8
- package/src/annotation.js +11 -7
- package/src/annotationLayer.js +7 -7
- package/src/camera.js +5 -5
- package/src/canvas/pixelmapFeature.js +208 -0
- package/src/choroplethFeature.js +1 -1
- package/src/domRenderer.js +2 -1
- package/src/featureLayer.js +1 -1
- package/src/fileReader.js +2 -2
- package/src/imageTile.js +2 -1
- package/src/index.js +1 -0
- package/src/isolineFeature.js +1 -1
- package/src/layer.js +4 -2
- package/src/lineFeature.js +3 -3
- package/src/map.js +17 -15
- package/src/mapInteractor.js +17 -17
- package/src/markerFeature.js +2 -2
- package/src/meshFeature.js +1 -1
- package/src/osmLayer.js +2 -0
- package/src/pixelmapFeature.js +97 -249
- package/src/pixelmapLayer.js +145 -0
- package/src/pointFeature.js +1 -1
- package/src/polygonFeature.js +3 -3
- package/src/quadFeature.js +1 -1
- package/src/registry.js +2 -2
- package/src/svg/svgRenderer.js +3 -3
- package/src/tileCache.js +1 -1
- package/src/tileLayer.js +13 -12
- package/src/trackFeature.js +19 -19
- package/src/transform.js +8 -9
- package/src/typedef.js +2 -0
- package/src/ui/sliderWidget.js +1 -1
- package/src/util/clustering.js +3 -3
- package/src/util/color.js +1 -1
- package/src/util/common.js +7 -7
- package/src/util/throttle.js +1 -1
- package/src/webgl/index.js +2 -0
- package/src/webgl/lookupTable2D.js +122 -0
- package/src/webgl/markerFeature.js +1 -1
- package/src/webgl/pixelmapFeature.frag +47 -0
- package/src/webgl/pixelmapFeature.js +203 -0
- package/src/webgl/pointFeature.js +1 -1
- package/src/webgl/quadFeature.js +35 -2
- package/src/webgl/webglRenderer.js +1 -0
package/src/mapInteractor.js
CHANGED
|
@@ -2037,26 +2037,26 @@ var mapInteractor = function (args) {
|
|
|
2037
2037
|
* map in pixels relative to the map's div.
|
|
2038
2038
|
* @param {geo.screenPosition} [options.center] The position of a touch
|
|
2039
2039
|
* event center relative to the window.
|
|
2040
|
-
* @param {string} [button] One of `left`, `middle`, or `right` for
|
|
2041
|
-
* events.
|
|
2042
|
-
* @param {string} [modifiers] A space-separated list of metakeys
|
|
2043
|
-
* down on mouse events.
|
|
2044
|
-
* @param {geo.screenPosition} [wheelDelta] The amount the wheel
|
|
2045
|
-
* both directions for wheel events. One step is often 20 units
|
|
2046
|
-
*
|
|
2047
|
-
* @param {number} [wheelMode] The wheel delta mode. See
|
|
2040
|
+
* @param {string} [options.button] One of `left`, `middle`, or `right` for
|
|
2041
|
+
* mouse events.
|
|
2042
|
+
* @param {string} [options.modifiers] A space-separated list of metakeys
|
|
2043
|
+
* that are down on mouse events.
|
|
2044
|
+
* @param {geo.screenPosition} [options.wheelDelta] The amount the wheel
|
|
2045
|
+
* moved in both directions for wheel events. One step is often 20 units
|
|
2046
|
+
* of movement.
|
|
2047
|
+
* @param {number} [options.wheelMode] The wheel delta mode. See
|
|
2048
2048
|
* https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent .
|
|
2049
|
-
* @param {boolean} [touch] `truthy` if this is a touch event.
|
|
2050
|
-
* @param {number} [rotation] Touch event rotation in degrees.
|
|
2051
|
-
* @param {number} [scale] Touch event scale. Initial events should
|
|
2052
|
-
* scale of 1; subsequent events should increase or decrease this
|
|
2053
|
-
* simulate spread and pinch actions.
|
|
2054
|
-
* @param {number[]} [pointers] A list of pointer numbers involved in
|
|
2055
|
-
* touch event. Pointers are number from one up, so `[1]` is the first
|
|
2049
|
+
* @param {boolean} [options.touch] `truthy` if this is a touch event.
|
|
2050
|
+
* @param {number} [options.rotation] Touch event rotation in degrees.
|
|
2051
|
+
* @param {number} [options.scale] Touch event scale. Initial events should
|
|
2052
|
+
* have a scale of 1; subsequent events should increase or decrease this
|
|
2053
|
+
* to simulate spread and pinch actions.
|
|
2054
|
+
* @param {number[]} [options.pointers] A list of pointer numbers involved in
|
|
2055
|
+
* a touch event. Pointers are number from one up, so `[1]` is the first
|
|
2056
2056
|
* touch point, `[1, 2]` are two touch points, and `[2]` is when the first
|
|
2057
2057
|
* point was released but the second is still touching.
|
|
2058
|
-
* @param {string} [pointerType] `mouse` if this is a mouse action
|
|
2059
|
-
* than a touch action.
|
|
2058
|
+
* @param {string} [options.pointerType] `mouse` if this is a mouse action
|
|
2059
|
+
* rather than a touch action.
|
|
2060
2060
|
* @returns {mapInteractor}
|
|
2061
2061
|
*/
|
|
2062
2062
|
this.simulateEvent = function (type, options) {
|
package/src/markerFeature.js
CHANGED
|
@@ -442,7 +442,7 @@ markerFeature.primitiveShapes = pointFeature.primitiveShapes;
|
|
|
442
442
|
|
|
443
443
|
/**
|
|
444
444
|
* Marker symbols
|
|
445
|
-
* @enum
|
|
445
|
+
* @enum {number}
|
|
446
446
|
*/
|
|
447
447
|
markerFeature.symbols = {
|
|
448
448
|
// for circle (alias ellipse), the symbolValue is the ratio of the minor to
|
|
@@ -499,7 +499,7 @@ markerFeature.symbols = {
|
|
|
499
499
|
|
|
500
500
|
/**
|
|
501
501
|
* Marker scale modes
|
|
502
|
-
* @enum
|
|
502
|
+
* @enum {number}
|
|
503
503
|
*/
|
|
504
504
|
markerFeature.scaleMode = {
|
|
505
505
|
none: 0,
|
package/src/meshFeature.js
CHANGED
|
@@ -21,7 +21,7 @@ var feature = require('./feature');
|
|
|
21
21
|
* of these properties can be functions, which get passed `data`.
|
|
22
22
|
*
|
|
23
23
|
* @typedef {object} geo.meshFeature.meshSpec
|
|
24
|
-
* @property {number[]|
|
|
24
|
+
* @property {number[]|Array.<number[]>} [elements] If specified, a list of
|
|
25
25
|
* indices into the data array that form elements. If this is an array of
|
|
26
26
|
* arrays, each subarray must have at least either 3 values for triangular
|
|
27
27
|
* elements or 4 values for square elements. If this is a single array,
|
package/src/osmLayer.js
CHANGED
|
@@ -13,6 +13,8 @@ var quadFeature = require('./quadFeature');
|
|
|
13
13
|
* specified, use this as the layer opacity.
|
|
14
14
|
* @property {string} [source] If specified, use the predefined tile source
|
|
15
15
|
* (see {@link geo.osmLayer.tileSources}).
|
|
16
|
+
* @property {string} [crossDomain='anonymous'] Image CORS attribute. This is
|
|
17
|
+
* used for the `crossorigin` property when loading images.
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
/**
|
package/src/pixelmapFeature.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
var $ = require('jquery');
|
|
2
2
|
var inherit = require('./inherit');
|
|
3
3
|
var feature = require('./feature');
|
|
4
|
-
var geo_event = require('./event');
|
|
5
4
|
var util = require('./util');
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -31,25 +30,6 @@ var util = require('./util');
|
|
|
31
30
|
* transformations for those two triangles.
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
|
-
/**
|
|
35
|
-
* Pixelmap feature information record.
|
|
36
|
-
*
|
|
37
|
-
* @typedef {object} geo.pixelmapFeature.info
|
|
38
|
-
* @property {number} width The width of the source image.
|
|
39
|
-
* @property {number} height The width of the source image.
|
|
40
|
-
* @property {context} context The HTMLCanvasElement context used for handling
|
|
41
|
-
* the pixelmap.
|
|
42
|
-
* @property {ImageData} imageData The context's image data.
|
|
43
|
-
* @property {number[]} indices An array, one per pixel, of the index value in
|
|
44
|
-
* the image. This decodes the pixel value to the corresponding integer.
|
|
45
|
-
* @property number} area The number of pixels in the image. This is
|
|
46
|
-
* `width * height`.
|
|
47
|
-
* @property {object[]} mappedColors This has one entry for each distinct index
|
|
48
|
-
* value. Each entry has `first` and `last` with the first and last pixel
|
|
49
|
-
* locations where that index occurs. Note that last is the inclusive value
|
|
50
|
-
* of the location (so its maximum possible value is `size - 1`).
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
33
|
/**
|
|
54
34
|
* Create a new instance of class pixelmapFeature
|
|
55
35
|
*
|
|
@@ -72,12 +52,9 @@ var pixelmapFeature = function (arg) {
|
|
|
72
52
|
* @private
|
|
73
53
|
*/
|
|
74
54
|
var m_this = this,
|
|
75
|
-
m_quadFeature,
|
|
76
|
-
m_srcImage,
|
|
77
|
-
m_info,
|
|
78
55
|
s_update = this._update,
|
|
79
|
-
|
|
80
|
-
|
|
56
|
+
m_modifiedIndexRange,
|
|
57
|
+
s_init = this._init;
|
|
81
58
|
|
|
82
59
|
this.featureType = 'pixelmap';
|
|
83
60
|
|
|
@@ -113,7 +90,7 @@ var pixelmapFeature = function (arg) {
|
|
|
113
90
|
if (val === undefined) {
|
|
114
91
|
return m_this.style('url');
|
|
115
92
|
} else if (val !== m_this.style('url')) {
|
|
116
|
-
m_srcImage = m_info = undefined;
|
|
93
|
+
m_this.m_srcImage = m_this.m_info = undefined;
|
|
117
94
|
m_this.style('url', val);
|
|
118
95
|
m_this.dataTime().modified();
|
|
119
96
|
m_this.modified();
|
|
@@ -121,28 +98,6 @@ var pixelmapFeature = function (arg) {
|
|
|
121
98
|
return m_this;
|
|
122
99
|
};
|
|
123
100
|
|
|
124
|
-
/**
|
|
125
|
-
* Get the maximum index value from the pixelmap. This is a value present in
|
|
126
|
-
* the pixelmap.
|
|
127
|
-
*
|
|
128
|
-
* @returns {number} The maximum index value.
|
|
129
|
-
*/
|
|
130
|
-
this.maxIndex = function () {
|
|
131
|
-
if (m_info) {
|
|
132
|
-
/* This isn't just m_info.mappedColors.length - 1, since there
|
|
133
|
-
* may be more data than actual indices. */
|
|
134
|
-
if (m_info.maxIndex === undefined) {
|
|
135
|
-
m_info.maxIndex = 0;
|
|
136
|
-
for (var idx in m_info.mappedColors) {
|
|
137
|
-
if (m_info.mappedColors.hasOwnProperty(idx)) {
|
|
138
|
-
m_info.maxIndex = Math.max(m_info.maxIndex, idx);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return m_info.maxIndex;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
101
|
/**
|
|
147
102
|
* Get/Set color accessor.
|
|
148
103
|
*
|
|
@@ -162,35 +117,87 @@ var pixelmapFeature = function (arg) {
|
|
|
162
117
|
};
|
|
163
118
|
|
|
164
119
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
120
|
+
* Mark that an index's data value (and hence its color) has changed without
|
|
121
|
+
* marking all of the data array as changed. If this function is called
|
|
122
|
+
* without any parameters, it clears the tracked changes.
|
|
168
123
|
*
|
|
169
|
-
* @param {
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
124
|
+
* @param {number} [idx] The lowest data index that has changed. If
|
|
125
|
+
* `undefined`, return the current tracked changed range.
|
|
126
|
+
* @param {number|'clear'} [idx2] If an index was specified in `idx` and
|
|
127
|
+
* this is specified, the highest index (inclusive) that has changed. If
|
|
128
|
+
* returning the tracked changed range and this is `clear`, clear the
|
|
129
|
+
* tracked range.
|
|
130
|
+
* @returns {this|number[]} When returning a range, this is the lowest and
|
|
131
|
+
* highest index values that have changed (inclusive), so their range is
|
|
132
|
+
* `[0, data.length)`.
|
|
174
133
|
*/
|
|
175
|
-
this.
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
134
|
+
this.indexModified = function (idx, idx2) {
|
|
135
|
+
if (idx === undefined) {
|
|
136
|
+
const range = m_modifiedIndexRange;
|
|
137
|
+
if (idx2 === 'clear') {
|
|
138
|
+
m_modifiedIndexRange = undefined;
|
|
139
|
+
}
|
|
140
|
+
return range;
|
|
141
|
+
}
|
|
142
|
+
m_this.modified();
|
|
143
|
+
if (m_modifiedIndexRange === undefined) {
|
|
144
|
+
m_modifiedIndexRange = [idx, idx];
|
|
145
|
+
}
|
|
146
|
+
if (idx < m_modifiedIndexRange[0]) {
|
|
147
|
+
m_modifiedIndexRange[0] = idx;
|
|
148
|
+
}
|
|
149
|
+
if ((idx2 || idx) > m_modifiedIndexRange[1]) {
|
|
150
|
+
m_modifiedIndexRange[1] = (idx2 || idx);
|
|
151
|
+
}
|
|
152
|
+
return m_this;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Update.
|
|
157
|
+
*
|
|
158
|
+
* @returns {this}
|
|
159
|
+
*/
|
|
160
|
+
this._update = function () {
|
|
161
|
+
s_update.call(m_this);
|
|
162
|
+
if (m_this.buildTime().timestamp() <= m_this.dataTime().timestamp() ||
|
|
163
|
+
m_this.updateTime().timestamp() < m_this.timestamp()) {
|
|
164
|
+
m_this._build();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
m_this.updateTime().modified();
|
|
168
|
+
return m_this;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get the maximum index value from the pixelmap. This is a value present in
|
|
173
|
+
* the pixelmap.
|
|
174
|
+
*
|
|
175
|
+
* @returns {number} The maximum index value.
|
|
176
|
+
*/
|
|
177
|
+
this.maxIndex = function () {
|
|
178
|
+
if (m_this.m_info) {
|
|
179
|
+
/* This isn't just m_info.mappedColors.length - 1, since there
|
|
180
|
+
* may be more data than actual indices. */
|
|
181
|
+
if (m_this.m_info.maxIndex === undefined) {
|
|
182
|
+
m_this.m_info.maxIndex = 0;
|
|
183
|
+
for (var idx in m_this.m_info.mappedColors) {
|
|
184
|
+
if (m_this.m_info.mappedColors.hasOwnProperty(idx)) {
|
|
185
|
+
m_this.m_info.maxIndex = Math.max(m_this.m_info.maxIndex, idx);
|
|
186
|
+
}
|
|
190
187
|
}
|
|
191
188
|
}
|
|
189
|
+
return m_this.m_info.maxIndex;
|
|
192
190
|
}
|
|
193
|
-
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Given the loaded pixelmap image, create a canvas the size of the image.
|
|
195
|
+
* Compute a color for each distinct index and recolor the canvas based on
|
|
196
|
+
* these colors, then draw the resultant image as a quad.
|
|
197
|
+
*
|
|
198
|
+
* @fires geo.event.pixelmap.prepared
|
|
199
|
+
*/
|
|
200
|
+
this._computePixelmap = function () {
|
|
194
201
|
};
|
|
195
202
|
|
|
196
203
|
/**
|
|
@@ -203,43 +210,42 @@ var pixelmapFeature = function (arg) {
|
|
|
203
210
|
* drawing a quad, which can trigger a full layer update, which in turn
|
|
204
211
|
* checks if this feature is built. Setting the build time avoids calling
|
|
205
212
|
* this a second time. */
|
|
206
|
-
m_this.
|
|
207
|
-
if (!m_srcImage) {
|
|
213
|
+
if (!m_this.m_srcImage) {
|
|
208
214
|
var src = m_this.style.get('url')();
|
|
209
215
|
if (util.isReadyImage(src)) {
|
|
210
216
|
/* we have an already loaded image, so we can just use it. */
|
|
211
|
-
m_srcImage = src;
|
|
217
|
+
m_this.m_srcImage = src;
|
|
212
218
|
m_this._computePixelmap();
|
|
213
219
|
} else if (src) {
|
|
214
220
|
var defer = $.Deferred(), prev_onload, prev_onerror;
|
|
215
221
|
if (src instanceof Image) {
|
|
216
222
|
/* we have an unloaded image. Hook to the load and error callbacks
|
|
217
223
|
* so that when it is loaded we can use it. */
|
|
218
|
-
m_srcImage = src;
|
|
224
|
+
m_this.m_srcImage = src;
|
|
219
225
|
prev_onload = src.onload;
|
|
220
226
|
prev_onerror = src.onerror;
|
|
221
227
|
} else {
|
|
222
228
|
/* we were given a url, so construct a new image */
|
|
223
|
-
m_srcImage = new Image();
|
|
229
|
+
m_this.m_srcImage = new Image();
|
|
224
230
|
// Only set the crossOrigin parameter if this is going across origins.
|
|
225
231
|
if (src.indexOf(':') >= 0 &&
|
|
226
232
|
src.indexOf('/') === src.indexOf(':') + 1) {
|
|
227
|
-
m_srcImage.crossOrigin = m_this.style.get('crossDomain')() || 'anonymous';
|
|
233
|
+
m_this.m_srcImage.crossOrigin = m_this.style.get('crossDomain')() || 'anonymous';
|
|
228
234
|
}
|
|
229
235
|
}
|
|
230
|
-
m_srcImage.onload = function () {
|
|
236
|
+
m_this.m_srcImage.onload = function () {
|
|
231
237
|
if (prev_onload) {
|
|
232
238
|
prev_onload.apply(m_this, arguments);
|
|
233
239
|
}
|
|
234
240
|
/* Only use this image if our pixelmap hasn't changed since we
|
|
235
241
|
* attached our handler */
|
|
236
242
|
if (m_this.style.get('url')() === src) {
|
|
237
|
-
m_info = undefined;
|
|
243
|
+
m_this.m_info = undefined;
|
|
238
244
|
m_this._computePixelmap();
|
|
239
245
|
}
|
|
240
246
|
defer.resolve();
|
|
241
247
|
};
|
|
242
|
-
m_srcImage.onerror = function () {
|
|
248
|
+
m_this.m_srcImage.onerror = function () {
|
|
243
249
|
if (prev_onerror) {
|
|
244
250
|
prev_onerror.apply(m_this, arguments);
|
|
245
251
|
}
|
|
@@ -248,177 +254,13 @@ var pixelmapFeature = function (arg) {
|
|
|
248
254
|
defer.promise(m_this);
|
|
249
255
|
m_this.layer().addPromise(m_this);
|
|
250
256
|
if (!(src instanceof Image)) {
|
|
251
|
-
m_srcImage.src = src;
|
|
257
|
+
m_this.m_srcImage.src = src;
|
|
252
258
|
}
|
|
253
259
|
}
|
|
254
|
-
} else if (m_info) {
|
|
260
|
+
} else if (m_this.m_info) {
|
|
255
261
|
m_this._computePixelmap();
|
|
256
262
|
}
|
|
257
|
-
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Compute information for this pixelmap image. It is wasteful to call this
|
|
262
|
-
* if the pixelmap has already been prepared (it is invalidated by a change
|
|
263
|
-
* in the image).
|
|
264
|
-
*
|
|
265
|
-
* @returns {geo.pixelmapFeature.info}
|
|
266
|
-
*/
|
|
267
|
-
this._preparePixelmap = function () {
|
|
268
|
-
var i, idx, pixelData;
|
|
269
|
-
|
|
270
|
-
if (!util.isReadyImage(m_srcImage)) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
m_info = {
|
|
274
|
-
width: m_srcImage.naturalWidth,
|
|
275
|
-
height: m_srcImage.naturalHeight,
|
|
276
|
-
canvas: document.createElement('canvas')
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
m_info.canvas.width = m_info.width;
|
|
280
|
-
m_info.canvas.height = m_info.height;
|
|
281
|
-
m_info.context = m_info.canvas.getContext('2d');
|
|
282
|
-
|
|
283
|
-
m_info.context.drawImage(m_srcImage, 0, 0);
|
|
284
|
-
m_info.imageData = m_info.context.getImageData(
|
|
285
|
-
0, 0, m_info.canvas.width, m_info.canvas.height);
|
|
286
|
-
pixelData = m_info.imageData.data;
|
|
287
|
-
m_info.indices = new Array(pixelData.length / 4);
|
|
288
|
-
m_info.area = pixelData.length / 4;
|
|
289
|
-
|
|
290
|
-
m_info.mappedColors = {};
|
|
291
|
-
for (i = 0; i < pixelData.length; i += 4) {
|
|
292
|
-
idx = pixelData[i] + (pixelData[i + 1] << 8) + (pixelData[i + 2] << 16);
|
|
293
|
-
m_info.indices[i / 4] = idx;
|
|
294
|
-
if (!m_info.mappedColors[idx]) {
|
|
295
|
-
m_info.mappedColors[idx] = {first: i / 4};
|
|
296
|
-
}
|
|
297
|
-
m_info.mappedColors[idx].last = i / 4;
|
|
298
|
-
}
|
|
299
|
-
return m_info;
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Given the loaded pixelmap image, create a canvas the size of the image.
|
|
304
|
-
* Compute a color for each distinct index and recolor the canvas based on
|
|
305
|
-
* these colors, then draw the resultant image as a quad.
|
|
306
|
-
*
|
|
307
|
-
* @fires geo.event.pixelmap.prepared
|
|
308
|
-
*/
|
|
309
|
-
this._computePixelmap = function () {
|
|
310
|
-
var data = m_this.data() || [],
|
|
311
|
-
colorFunc = m_this.style.get('color'),
|
|
312
|
-
i, idx, lastidx, color, pixelData, indices, mappedColors,
|
|
313
|
-
updateFirst, updateLast = -1, update, prepared;
|
|
314
|
-
|
|
315
|
-
if (!m_info) {
|
|
316
|
-
if (!m_this._preparePixelmap()) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
prepared = true;
|
|
320
|
-
}
|
|
321
|
-
mappedColors = m_info.mappedColors;
|
|
322
|
-
updateFirst = m_info.area;
|
|
323
|
-
for (idx in mappedColors) {
|
|
324
|
-
if (mappedColors.hasOwnProperty(idx)) {
|
|
325
|
-
color = colorFunc(data[idx], +idx) || {};
|
|
326
|
-
color = [
|
|
327
|
-
(color.r || 0) * 255,
|
|
328
|
-
(color.g || 0) * 255,
|
|
329
|
-
(color.b || 0) * 255,
|
|
330
|
-
color.a === undefined ? 255 : (color.a * 255)
|
|
331
|
-
];
|
|
332
|
-
mappedColors[idx].update = (
|
|
333
|
-
!mappedColors[idx].color ||
|
|
334
|
-
mappedColors[idx].color[0] !== color[0] ||
|
|
335
|
-
mappedColors[idx].color[1] !== color[1] ||
|
|
336
|
-
mappedColors[idx].color[2] !== color[2] ||
|
|
337
|
-
mappedColors[idx].color[3] !== color[3]);
|
|
338
|
-
if (mappedColors[idx].update) {
|
|
339
|
-
mappedColors[idx].color = color;
|
|
340
|
-
updateFirst = Math.min(mappedColors[idx].first, updateFirst);
|
|
341
|
-
updateLast = Math.max(mappedColors[idx].last, updateLast);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
/* If nothing was updated, we are done */
|
|
346
|
-
if (updateFirst >= updateLast) {
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
/* Update only the extent that has changed */
|
|
350
|
-
pixelData = m_info.imageData.data;
|
|
351
|
-
indices = m_info.indices;
|
|
352
|
-
for (i = updateFirst; i <= updateLast; i += 1) {
|
|
353
|
-
idx = indices[i];
|
|
354
|
-
if (idx !== lastidx) {
|
|
355
|
-
lastidx = idx;
|
|
356
|
-
color = mappedColors[idx].color;
|
|
357
|
-
update = mappedColors[idx].update;
|
|
358
|
-
}
|
|
359
|
-
if (update) {
|
|
360
|
-
pixelData[i * 4] = color[0];
|
|
361
|
-
pixelData[i * 4 + 1] = color[1];
|
|
362
|
-
pixelData[i * 4 + 2] = color[2];
|
|
363
|
-
pixelData[i * 4 + 3] = color[3];
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
/* Place the updated area into the canvas */
|
|
367
|
-
m_info.context.putImageData(
|
|
368
|
-
m_info.imageData, 0, 0, 0, Math.floor(updateFirst / m_info.width),
|
|
369
|
-
m_info.width, Math.ceil((updateLast + 1) / m_info.width));
|
|
370
|
-
|
|
371
|
-
/* If we haven't made a quad feature, make one now. The quad feature needs
|
|
372
|
-
* to have the canvas capability. */
|
|
373
|
-
if (!m_quadFeature) {
|
|
374
|
-
m_quadFeature = m_this.layer().createFeature('quad', {
|
|
375
|
-
selectionAPI: false,
|
|
376
|
-
gcs: m_this.gcs(),
|
|
377
|
-
visible: m_this.visible(undefined, true)
|
|
378
|
-
});
|
|
379
|
-
m_this.dependentFeatures([m_quadFeature]);
|
|
380
|
-
m_quadFeature.style({
|
|
381
|
-
image: m_info.canvas,
|
|
382
|
-
position: m_this.style.get('position')})
|
|
383
|
-
.data([{}])
|
|
384
|
-
.draw();
|
|
385
|
-
}
|
|
386
|
-
/* If we prepared the pixelmap and rendered it, send a prepared event */
|
|
387
|
-
if (prepared) {
|
|
388
|
-
m_this.geoTrigger(geo_event.pixelmap.prepared, {
|
|
389
|
-
pixelmap: m_this
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Update.
|
|
396
|
-
*
|
|
397
|
-
* @returns {this}
|
|
398
|
-
*/
|
|
399
|
-
this._update = function () {
|
|
400
|
-
s_update.call(m_this);
|
|
401
|
-
if (m_this.buildTime().timestamp() <= m_this.dataTime().timestamp() ||
|
|
402
|
-
m_this.updateTime().timestamp() < m_this.timestamp()) {
|
|
403
|
-
m_this._build();
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
m_this.updateTime().modified();
|
|
407
|
-
return m_this;
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Destroy. Deletes the associated quadFeature.
|
|
412
|
-
*
|
|
413
|
-
* @returns {this}
|
|
414
|
-
*/
|
|
415
|
-
this._exit = function () {
|
|
416
|
-
if (m_quadFeature && m_this.layer()) {
|
|
417
|
-
m_this.layer().deleteFeature(m_quadFeature);
|
|
418
|
-
m_quadFeature = null;
|
|
419
|
-
m_this.dependentFeatures([]);
|
|
420
|
-
}
|
|
421
|
-
s_exit();
|
|
263
|
+
m_this.buildTime().modified();
|
|
422
264
|
return m_this;
|
|
423
265
|
};
|
|
424
266
|
|
|
@@ -458,6 +300,10 @@ var pixelmapFeature = function (arg) {
|
|
|
458
300
|
}
|
|
459
301
|
m_this.style(style);
|
|
460
302
|
m_this.dataTime().modified();
|
|
303
|
+
if (arg.quadFeature) {
|
|
304
|
+
m_this.m_srcImage = true;
|
|
305
|
+
m_this._computePixelmap();
|
|
306
|
+
}
|
|
461
307
|
|
|
462
308
|
return m_this;
|
|
463
309
|
};
|
|
@@ -483,7 +329,9 @@ pixelmapFeature.create = function (layer, spec) {
|
|
|
483
329
|
|
|
484
330
|
pixelmapFeature.capabilities = {
|
|
485
331
|
/* core feature name -- support in any manner */
|
|
486
|
-
feature: 'pixelmap'
|
|
332
|
+
feature: 'pixelmap',
|
|
333
|
+
/* support for image-based lookup */
|
|
334
|
+
lookup: 'pixelmap.lookup'
|
|
487
335
|
};
|
|
488
336
|
|
|
489
337
|
inherit(pixelmapFeature, feature);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
var $ = require('jquery');
|
|
2
|
+
var inherit = require('./inherit');
|
|
3
|
+
var tileLayer = require('./tileLayer');
|
|
4
|
+
var registry = require('./registry');
|
|
5
|
+
var quadFeature = require('./quadFeature');
|
|
6
|
+
var pixelmapFeature = require('./pixelmapFeature');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Object specification for a pixelmap layer.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {geo.tileLayer.spec} geo.pixelmapLayer.spec
|
|
12
|
+
* @extends {geo.tileLayer.spec}
|
|
13
|
+
* @property {geo.geoColor|function} [color] The color that should be used
|
|
14
|
+
* for each data element. Data elements correspond to the indices in the
|
|
15
|
+
* pixel map. If an index is larger than the number of data elements, it will
|
|
16
|
+
* be transparent. If there is more data than there are indices, it is
|
|
17
|
+
* ignored.
|
|
18
|
+
* @property {object} [style] An optional style object that could contain
|
|
19
|
+
* `color` or other style values.
|
|
20
|
+
* @property {array} [data] A new data array.
|
|
21
|
+
* @property {string} [crossDomain='anonymous'] Image CORS attribute. This is
|
|
22
|
+
* used for the `crossorigin` property when loading images.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a new instance of pixelmapLayer. This is a {@link geo.tileLayer} with
|
|
27
|
+
* an OSM url and attribution defaults and with the tiles centered on the
|
|
28
|
+
* origin.
|
|
29
|
+
*
|
|
30
|
+
* @class
|
|
31
|
+
* @alias geo.pixelmapLayer
|
|
32
|
+
* @extends geo.tileLayer
|
|
33
|
+
*
|
|
34
|
+
* @param {geo.pixelmapLayer.spec} [arg] Specification for the layer.
|
|
35
|
+
*/
|
|
36
|
+
var pixelmapLayer = function (arg) {
|
|
37
|
+
|
|
38
|
+
var imageTile = require('./imageTile');
|
|
39
|
+
|
|
40
|
+
if (!(this instanceof pixelmapLayer)) {
|
|
41
|
+
return new pixelmapLayer(arg);
|
|
42
|
+
}
|
|
43
|
+
arg = arg || {};
|
|
44
|
+
arg = $.extend(
|
|
45
|
+
true,
|
|
46
|
+
{},
|
|
47
|
+
this.constructor.defaults,
|
|
48
|
+
arg);
|
|
49
|
+
tileLayer.call(this, arg);
|
|
50
|
+
|
|
51
|
+
var s_init = this._init,
|
|
52
|
+
m_pixelmapFeature,
|
|
53
|
+
m_this = this;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns an instantiated imageTile object with the given indices. This
|
|
57
|
+
* method always returns a new tile object. Use `_getTileCached` to use
|
|
58
|
+
* the caching layer.
|
|
59
|
+
*
|
|
60
|
+
* @param {object} index The tile index.
|
|
61
|
+
* @param {number} index.x
|
|
62
|
+
* @param {number} index.y
|
|
63
|
+
* @param {number} index.level
|
|
64
|
+
* @param {object} source The tile index used for constructing the url.
|
|
65
|
+
* @param {number} source.x
|
|
66
|
+
* @param {number} source.y
|
|
67
|
+
* @param {number} source.level
|
|
68
|
+
* @returns {geo.tile}
|
|
69
|
+
*/
|
|
70
|
+
this._getTile = function (index, source) {
|
|
71
|
+
var urlParams = source || index;
|
|
72
|
+
return imageTile({
|
|
73
|
+
index: index,
|
|
74
|
+
size: {x: m_this._options.tileWidth, y: m_this._options.tileHeight},
|
|
75
|
+
queue: m_this._queue,
|
|
76
|
+
overlap: m_this._options.tileOverlap,
|
|
77
|
+
scale: m_this._options.tileScale,
|
|
78
|
+
url: m_this._options.url.call(
|
|
79
|
+
m_this, urlParams.x, urlParams.y, urlParams.level || 0,
|
|
80
|
+
m_this._options.subdomains),
|
|
81
|
+
crossDomain: m_this._options.crossDomain
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Initialize.
|
|
87
|
+
*
|
|
88
|
+
* @returns {this} The current layer.
|
|
89
|
+
*/
|
|
90
|
+
this._init = function () {
|
|
91
|
+
// Call super class init
|
|
92
|
+
s_init.apply(m_this, arguments);
|
|
93
|
+
|
|
94
|
+
const pixelmapArgs = {quadFeature: m_this.features()[0]};
|
|
95
|
+
if (arg.style) {
|
|
96
|
+
pixelmapArgs.style = arg.style;
|
|
97
|
+
}
|
|
98
|
+
if (arg.color) {
|
|
99
|
+
pixelmapArgs.color = arg.color;
|
|
100
|
+
}
|
|
101
|
+
m_pixelmapFeature = m_this.createFeature('pixelmap', pixelmapArgs);
|
|
102
|
+
if (arg.data) {
|
|
103
|
+
m_pixelmapFeature.data(arg.data);
|
|
104
|
+
}
|
|
105
|
+
m_this.style = m_pixelmapFeature.style;
|
|
106
|
+
m_this.data = m_pixelmapFeature.data;
|
|
107
|
+
m_this.indexModified = m_pixelmapFeature.indexModified;
|
|
108
|
+
const s_dataTimeModified = m_this.dataTime().modified;
|
|
109
|
+
m_this.dataTime().modified = () => {
|
|
110
|
+
m_pixelmapFeature.dataTime().modified();
|
|
111
|
+
return s_dataTimeModified();
|
|
112
|
+
};
|
|
113
|
+
['modified', 'geoOn', 'geoOff', 'geoOnce'].forEach((funcName) => {
|
|
114
|
+
const superFunc = m_this[funcName];
|
|
115
|
+
m_this[funcName] = function () {
|
|
116
|
+
m_pixelmapFeature[funcName].apply(this, arguments);
|
|
117
|
+
return superFunc.apply(this, arguments);
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
return m_this;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return m_this;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* This object contains the default options used to initialize the
|
|
128
|
+
* pixelmapLayer.
|
|
129
|
+
*/
|
|
130
|
+
pixelmapLayer.defaults = $.extend({}, tileLayer.defaults, {
|
|
131
|
+
features: [quadFeature.capabilities.image, pixelmapFeature.capabilities.lookup],
|
|
132
|
+
tileOffset : function (level) {
|
|
133
|
+
var s = Math.pow(2, level - 1) * 256;
|
|
134
|
+
return {x: s, y: s};
|
|
135
|
+
},
|
|
136
|
+
url: ''
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
inherit(pixelmapLayer, tileLayer);
|
|
140
|
+
/* By default, ask to support image quads. If the user needs full
|
|
141
|
+
* reprojection, they will need to require the
|
|
142
|
+
* quadFeature.capabilities.imageFull feature */
|
|
143
|
+
registry.registerLayer('pixelmap', pixelmapLayer, [quadFeature.capabilities.image]);
|
|
144
|
+
|
|
145
|
+
module.exports = pixelmapLayer;
|