geojs 1.6.5 → 1.7.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.
@@ -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
- s_init = this._init,
80
- s_exit = this._exit;
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
- * If the specified coordinates are in the rendered quad, use the basis
166
- * information from the quad to determine the pixelmap index value so that it
167
- * can be included in the `found` results.
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 {geo.geoPosition} geo Coordinate.
170
- * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
171
- * the interface gcs, `null` to use the map gcs, or any other transform.
172
- * @returns {geo.feature.searchResult} An object with a list of features and
173
- * feature indices that are located at the specified point.
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.pointSearch = function (geo, gcs) {
176
- if (m_quadFeature && m_info) {
177
- var result = m_quadFeature.pointSearch(geo, gcs);
178
- if (result.index.length === 1 && result.extra && result.extra[result.index[0]].basis) {
179
- var basis = result.extra[result.index[0]].basis, x, y, idx;
180
- x = Math.floor(basis.x * m_info.width);
181
- y = Math.floor(basis.y * m_info.height);
182
- if (x >= 0 && x < m_info.width &&
183
- y >= 0 && y < m_info.height) {
184
- idx = m_info.indices[y * m_info.width + x];
185
- result = {
186
- index: [idx],
187
- found: [m_this.data()[idx]]
188
- };
189
- return result;
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
- return {index: [], found: []};
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.buildTime().modified();
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
- return m_this;
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;
@@ -232,7 +232,7 @@ var quadFeature = function (arg) {
232
232
  coordbasis.y = 1 - coordbasis.y;
233
233
  }
234
234
  if (coordbasis) {
235
- extra[quad.idx] = {basis: coordbasis};
235
+ extra[quad.idx] = {basis: coordbasis, _quad: quad};
236
236
  }
237
237
  }
238
238
  });
package/src/tileLayer.js CHANGED
@@ -676,7 +676,10 @@ var tileLayer = function (arg) {
676
676
  this._getTiles = function (maxLevel, bounds, sorted, onlyIfChanged) {
677
677
  var i, j, tiles = [], index, nTilesLevel,
678
678
  start, end, indexRange, source, center, changed = false, old, level,
679
- minLevel = (m_this._options.keepLower ? m_this._options.minLevel : maxLevel);
679
+ minLevel = (
680
+ m_this._options.keepLower ?
681
+ m_this._options.minLevel :
682
+ Math.min(Math.max(maxLevel, m_this._options.minLevel), m_this._options.maxLevel));
680
683
  if (maxLevel < minLevel) {
681
684
  maxLevel = minLevel;
682
685
  }
@@ -1532,7 +1535,10 @@ var tileLayer = function (arg) {
1532
1535
  * finished, purge all but the current layer. This is important for
1533
1536
  * semi-transparent layers. */
1534
1537
  if ((doneLoading || m_this._isCovered(tile)) &&
1535
- zoom !== tile.index.level) {
1538
+ zoom !== tile.index.level &&
1539
+ (zoom >= m_this._options.minLevel || tile.index.level !== m_this._options.minLevel) &&
1540
+ (zoom < m_this._options.maxLevel || tile.index.level !== m_this._options.maxLevel)
1541
+ ) {
1536
1542
  return true;
1537
1543
  }
1538
1544
  }
@@ -8,8 +8,10 @@ module.exports = {
8
8
  isolineFeature: require('./isolineFeature'),
9
9
  layer: require('./layer'),
10
10
  lineFeature: require('./lineFeature'),
11
+ lookupTable2D: require('./lookupTable2D'),
11
12
  markerFeature: require('./markerFeature'),
12
13
  meshColored: require('./meshColored'),
14
+ pixelmapFeature: require('./pixelmapFeature'),
13
15
  pointFeature: require('./pointFeature'),
14
16
  polygonFeature: require('./polygonFeature'),
15
17
  quadFeature: require('./quadFeature'),