geojs 1.6.4 → 1.7.1

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/geo.js CHANGED
@@ -1365,7 +1365,7 @@ function continuousVerticesProcessAction(m_this, evt, name) {
1365
1365
  }
1366
1366
 
1367
1367
  var cpp = layer.options('continuousPointProximity');
1368
- var cpc = layer.options('continuousPointColinearity');
1368
+ var cpc = layer.options('continuousPointCollinearity');
1369
1369
  var ccp = layer.options('continuousCloseProximity');
1370
1370
 
1371
1371
  if (cpp || cpp === 0) {
@@ -1381,7 +1381,7 @@ function continuousVerticesProcessAction(m_this, evt, name) {
1381
1381
  var dist = layer.displayDistance(vertices[vertices.length - 2], null, evt.mouse.map, 'display');
1382
1382
 
1383
1383
  if (dist && dist > cpp) {
1384
- // combine nearly colinear points
1384
+ // combine nearly collinear points
1385
1385
  if (vertices.length >= (m_this._lastClickVertexCount || 1) + 3) {
1386
1386
  var d01 = layer.displayDistance(vertices[vertices.length - 3], null, vertices[vertices.length - 2], null),
1387
1387
  d12 = dist,
@@ -2899,9 +2899,9 @@ var textFeature = __webpack_require__(9757);
2899
2899
  * @property {number} [continuousPointProximity=5] The minimum distance in
2900
2900
  * display coordinates (pixels) between two adjacent points when dragging
2901
2901
  * to create an annotation. `false` disables continuous drawing mode.
2902
- * @property {number} [continuousPointColinearity=1.0deg] The minimum angle
2902
+ * @property {number} [continuousPointCollinearity=1.0deg] The minimum angle
2903
2903
  * between a series of three points when dragging to not interpret them as
2904
- * colinear. Only applies if `continuousPointProximity` is not `false`.
2904
+ * collinear. Only applies if `continuousPointProximity` is not `false`.
2905
2905
  * @property {number} [continuousCloseProximity=10] The minimum distance in
2906
2906
  * display coordinates (pixels) to close a polygon or end drawing a line when
2907
2907
  * dragging to create an annotation. `false` never closes at the end of a
@@ -3053,8 +3053,8 @@ var annotationLayer = function annotationLayer(arg) {
3053
3053
  // continuous drawing modes.
3054
3054
  continuousPointProximity: 5,
3055
3055
  // in radians, minimum angle between continuous points to interpret them as
3056
- // being coliner
3057
- continuousPointColinearity: 1.0 * Math.PI / 180,
3056
+ // being collinear
3057
+ continuousPointCollinearity: 1.0 * Math.PI / 180,
3058
3058
  continuousCloseProximity: 10,
3059
3059
  // in pixels, 0 is exact
3060
3060
  finalPointProximity: 10,
@@ -6360,6 +6360,29 @@ var inherit = __webpack_require__(5699);
6360
6360
  var registerFeature = (__webpack_require__(4647).registerFeature);
6361
6361
 
6362
6362
  var pixelmapFeature = __webpack_require__(6374);
6363
+
6364
+ var geo_event = __webpack_require__(5108);
6365
+
6366
+ var util = __webpack_require__(4634);
6367
+ /**
6368
+ * Pixelmap feature information record.
6369
+ *
6370
+ * @typedef {object} geo.pixelmapFeature.info
6371
+ * @property {number} width The width of the source image.
6372
+ * @property {number} height The width of the source image.
6373
+ * @property {CanvasRenderingContext2D} context The HTMLCanvasElement context
6374
+ * used for handling the pixelmap.
6375
+ * @property {ImageData} imageData The context's image data.
6376
+ * @property {number[]} indices An array, one per pixel, of the index value in
6377
+ * the image. This decodes the pixel value to the corresponding integer.
6378
+ * @property number} area The number of pixels in the image. This is
6379
+ * `width * height`.
6380
+ * @property {object[]} mappedColors This has one entry for each distinct index
6381
+ * value. Each entry has `first` and `last` with the first and last pixel
6382
+ * locations where that index occurs. Note that last is the inclusive value
6383
+ * of the location (so its maximum possible value is `size - 1`).
6384
+ */
6385
+
6363
6386
  /**
6364
6387
  * Create a new instance of class pixelmapFeature.
6365
6388
  *
@@ -6383,6 +6406,219 @@ var canvas_pixelmapFeature = function canvas_pixelmapFeature(arg) {
6383
6406
  var object = __webpack_require__(3160);
6384
6407
 
6385
6408
  object.call(this);
6409
+ var m_quadFeature,
6410
+ s_exit = this._exit,
6411
+ m_this = this;
6412
+ /**
6413
+ * If the specified coordinates are in the rendered quad, use the basis
6414
+ * information from the quad to determine the pixelmap index value so that it
6415
+ * can be included in the `found` results.
6416
+ *
6417
+ * @param {geo.geoPosition} geo Coordinate.
6418
+ * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
6419
+ * the interface gcs, `null` to use the map gcs, or any other transform.
6420
+ * @returns {geo.feature.searchResult} An object with a list of features and
6421
+ * feature indices that are located at the specified point.
6422
+ */
6423
+
6424
+ this.pointSearch = function (geo, gcs) {
6425
+ if (m_quadFeature && m_this.m_info) {
6426
+ var result = m_quadFeature.pointSearch(geo, gcs);
6427
+
6428
+ if (result.index.length === 1 && result.extra && result.extra[result.index[0]].basis) {
6429
+ var basis = result.extra[result.index[0]].basis,
6430
+ x,
6431
+ y,
6432
+ idx;
6433
+ x = Math.floor(basis.x * m_this.m_info.width);
6434
+ y = Math.floor(basis.y * m_this.m_info.height);
6435
+
6436
+ if (x >= 0 && x < m_this.m_info.width && y >= 0 && y < m_this.m_info.height) {
6437
+ idx = m_this.m_info.indices[y * m_this.m_info.width + x];
6438
+ result = {
6439
+ index: [idx],
6440
+ found: [m_this.data()[idx]]
6441
+ };
6442
+ return result;
6443
+ }
6444
+ }
6445
+ }
6446
+
6447
+ return {
6448
+ index: [],
6449
+ found: []
6450
+ };
6451
+ };
6452
+ /**
6453
+ * Compute information for this pixelmap image. It is wasteful to call this
6454
+ * if the pixelmap has already been prepared (it is invalidated by a change
6455
+ * in the image).
6456
+ *
6457
+ * @returns {geo.pixelmapFeature.info}
6458
+ */
6459
+
6460
+
6461
+ this._preparePixelmap = function () {
6462
+ var i, idx, pixelData;
6463
+
6464
+ if (!util.isReadyImage(m_this.m_srcImage)) {
6465
+ return;
6466
+ }
6467
+
6468
+ m_this.m_info = {
6469
+ width: m_this.m_srcImage.naturalWidth,
6470
+ height: m_this.m_srcImage.naturalHeight,
6471
+ canvas: document.createElement('canvas')
6472
+ };
6473
+ m_this.m_info.canvas.width = m_this.m_info.width;
6474
+ m_this.m_info.canvas.height = m_this.m_info.height;
6475
+ m_this.m_info.context = m_this.m_info.canvas.getContext('2d');
6476
+ m_this.m_info.context.drawImage(m_this.m_srcImage, 0, 0);
6477
+ m_this.m_info.imageData = m_this.m_info.context.getImageData(0, 0, m_this.m_info.canvas.width, m_this.m_info.canvas.height);
6478
+ pixelData = m_this.m_info.imageData.data;
6479
+ m_this.m_info.indices = new Array(pixelData.length / 4);
6480
+ m_this.m_info.area = pixelData.length / 4;
6481
+ m_this.m_info.mappedColors = {};
6482
+
6483
+ for (i = 0; i < pixelData.length; i += 4) {
6484
+ idx = pixelData[i] + (pixelData[i + 1] << 8) + (pixelData[i + 2] << 16);
6485
+ m_this.m_info.indices[i / 4] = idx;
6486
+
6487
+ if (!m_this.m_info.mappedColors[idx]) {
6488
+ m_this.m_info.mappedColors[idx] = {
6489
+ first: i / 4
6490
+ };
6491
+ }
6492
+
6493
+ m_this.m_info.mappedColors[idx].last = i / 4;
6494
+ }
6495
+
6496
+ return m_this.m_info;
6497
+ };
6498
+ /**
6499
+ * Given the loaded pixelmap image, create a canvas the size of the image.
6500
+ * Compute a color for each distinct index and recolor the canvas based on
6501
+ * these colors, then draw the resultant image as a quad.
6502
+ *
6503
+ * @fires geo.event.pixelmap.prepared
6504
+ */
6505
+
6506
+
6507
+ this._computePixelmap = function () {
6508
+ var data = m_this.data() || [],
6509
+ colorFunc = m_this.style.get('color'),
6510
+ i,
6511
+ idx,
6512
+ lastidx,
6513
+ color,
6514
+ pixelData,
6515
+ indices,
6516
+ mappedColors,
6517
+ updateFirst,
6518
+ updateLast = -1,
6519
+ update,
6520
+ prepared;
6521
+
6522
+ if (!m_this.m_info) {
6523
+ m_this.indexModified(undefined, 'clear');
6524
+
6525
+ if (!m_this._preparePixelmap()) {
6526
+ return;
6527
+ }
6528
+
6529
+ prepared = true;
6530
+ }
6531
+
6532
+ m_this.indexModified(undefined, 'clear');
6533
+ mappedColors = m_this.m_info.mappedColors;
6534
+ updateFirst = m_this.m_info.area;
6535
+
6536
+ for (idx in mappedColors) {
6537
+ if (mappedColors.hasOwnProperty(idx)) {
6538
+ color = colorFunc(data[idx], +idx) || {};
6539
+ color = [(color.r || 0) * 255, (color.g || 0) * 255, (color.b || 0) * 255, color.a === undefined ? 255 : color.a * 255];
6540
+ mappedColors[idx].update = !mappedColors[idx].color || mappedColors[idx].color[0] !== color[0] || mappedColors[idx].color[1] !== color[1] || mappedColors[idx].color[2] !== color[2] || mappedColors[idx].color[3] !== color[3];
6541
+
6542
+ if (mappedColors[idx].update) {
6543
+ mappedColors[idx].color = color;
6544
+ updateFirst = Math.min(mappedColors[idx].first, updateFirst);
6545
+ updateLast = Math.max(mappedColors[idx].last, updateLast);
6546
+ }
6547
+ }
6548
+ }
6549
+ /* If nothing was updated, we are done */
6550
+
6551
+
6552
+ if (updateFirst >= updateLast) {
6553
+ return;
6554
+ }
6555
+ /* Update only the extent that has changed */
6556
+
6557
+
6558
+ pixelData = m_this.m_info.imageData.data;
6559
+ indices = m_this.m_info.indices;
6560
+
6561
+ for (i = updateFirst; i <= updateLast; i += 1) {
6562
+ idx = indices[i];
6563
+
6564
+ if (idx !== lastidx) {
6565
+ lastidx = idx;
6566
+ color = mappedColors[idx].color;
6567
+ update = mappedColors[idx].update;
6568
+ }
6569
+
6570
+ if (update) {
6571
+ pixelData[i * 4] = color[0];
6572
+ pixelData[i * 4 + 1] = color[1];
6573
+ pixelData[i * 4 + 2] = color[2];
6574
+ pixelData[i * 4 + 3] = color[3];
6575
+ }
6576
+ }
6577
+ /* Place the updated area into the canvas */
6578
+
6579
+
6580
+ m_this.m_info.context.putImageData(m_this.m_info.imageData, 0, 0, 0, Math.floor(updateFirst / m_this.m_info.width), m_this.m_info.width, Math.ceil((updateLast + 1) / m_this.m_info.width));
6581
+ /* If we haven't made a quad feature, make one now. The quad feature needs
6582
+ * to have the canvas capability. */
6583
+
6584
+ if (!m_quadFeature) {
6585
+ m_quadFeature = m_this.layer().createFeature('quad', {
6586
+ selectionAPI: false,
6587
+ gcs: m_this.gcs(),
6588
+ visible: m_this.visible(undefined, true)
6589
+ });
6590
+ m_this.dependentFeatures([m_quadFeature]);
6591
+ m_quadFeature.style({
6592
+ image: m_this.m_info.canvas,
6593
+ position: m_this.style.get('position')
6594
+ }).data([{}]).draw();
6595
+ }
6596
+ /* If we prepared the pixelmap and rendered it, send a prepared event */
6597
+
6598
+
6599
+ if (prepared) {
6600
+ m_this.geoTrigger(geo_event.pixelmap.prepared, {
6601
+ pixelmap: m_this
6602
+ });
6603
+ }
6604
+ };
6605
+ /**
6606
+ * Destroy. Deletes the associated quadFeature.
6607
+ *
6608
+ * @returns {this}
6609
+ */
6610
+
6611
+
6612
+ this._exit = function () {
6613
+ if (m_quadFeature && m_this.layer()) {
6614
+ m_this.layer().deleteFeature(m_quadFeature);
6615
+ m_quadFeature = null;
6616
+ m_this.dependentFeatures([]);
6617
+ }
6618
+
6619
+ s_exit();
6620
+ return m_this;
6621
+ };
6386
6622
 
6387
6623
  this._init(arg);
6388
6624
 
@@ -12038,6 +12274,7 @@ module.exports = $.extend({
12038
12274
  polygonFeature: __webpack_require__(4343),
12039
12275
  quadFeature: __webpack_require__(5017),
12040
12276
  pixelmapFeature: __webpack_require__(6374),
12277
+ pixelmapLayer: __webpack_require__(809),
12041
12278
  renderer: __webpack_require__(3234),
12042
12279
  sceneObject: __webpack_require__(5358),
12043
12280
  textFeature: __webpack_require__(9757),
@@ -14626,9 +14863,9 @@ var lineFeature = function lineFeature(arg) {
14626
14863
  *
14627
14864
  * @param {array} data A new data array.
14628
14865
  * @param {number} [tolerance] The maximum variation allowed in map.gcs
14629
- * units. A value of zero will only remove perfectly colinear points. If
14630
- * not specified, this is set to a half display pixel at the map's current
14631
- * zoom level.
14866
+ * units. A value of zero will only remove perfectly collinear points.
14867
+ * If not specified, this is set to a half display pixel at the map's
14868
+ * current zoom level.
14632
14869
  * @param {function} [posFunc=this.style.get('position')] The function to
14633
14870
  * get the position of each vertex.
14634
14871
  * @param {function} [lineFunc=this.style.get('line')] The function to get
@@ -21986,8 +22223,6 @@ var inherit = __webpack_require__(5699);
21986
22223
 
21987
22224
  var feature = __webpack_require__(6837);
21988
22225
 
21989
- var geo_event = __webpack_require__(5108);
21990
-
21991
22226
  var util = __webpack_require__(4634);
21992
22227
  /**
21993
22228
  * Pixelmap feature specification.
@@ -22016,25 +22251,6 @@ var util = __webpack_require__(4634);
22016
22251
  * transformations for those two triangles.
22017
22252
  */
22018
22253
 
22019
- /**
22020
- * Pixelmap feature information record.
22021
- *
22022
- * @typedef {object} geo.pixelmapFeature.info
22023
- * @property {number} width The width of the source image.
22024
- * @property {number} height The width of the source image.
22025
- * @property {context} context The HTMLCanvasElement context used for handling
22026
- * the pixelmap.
22027
- * @property {ImageData} imageData The context's image data.
22028
- * @property {number[]} indices An array, one per pixel, of the index value in
22029
- * the image. This decodes the pixel value to the corresponding integer.
22030
- * @property number} area The number of pixels in the image. This is
22031
- * `width * height`.
22032
- * @property {object[]} mappedColors This has one entry for each distinct index
22033
- * value. Each entry has `first` and `last` with the first and last pixel
22034
- * locations where that index occurs. Note that last is the inclusive value
22035
- * of the location (so its maximum possible value is `size - 1`).
22036
- */
22037
-
22038
22254
  /**
22039
22255
  * Create a new instance of class pixelmapFeature
22040
22256
  *
@@ -22060,12 +22276,9 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22060
22276
  */
22061
22277
 
22062
22278
  var m_this = this,
22063
- m_quadFeature,
22064
- m_srcImage,
22065
- m_info,
22066
22279
  s_update = this._update,
22067
- s_init = this._init,
22068
- s_exit = this._exit;
22280
+ m_modifiedIndexRange,
22281
+ s_init = this._init;
22069
22282
  this.featureType = 'pixelmap';
22070
22283
  /**
22071
22284
  * Get/Set position accessor.
@@ -22102,7 +22315,7 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22102
22315
  if (val === undefined) {
22103
22316
  return m_this.style('url');
22104
22317
  } else if (val !== m_this.style('url')) {
22105
- m_srcImage = m_info = undefined;
22318
+ m_this.m_srcImage = m_this.m_info = undefined;
22106
22319
  m_this.style('url', val);
22107
22320
  m_this.dataTime().modified();
22108
22321
  m_this.modified();
@@ -22110,31 +22323,6 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22110
22323
 
22111
22324
  return m_this;
22112
22325
  };
22113
- /**
22114
- * Get the maximum index value from the pixelmap. This is a value present in
22115
- * the pixelmap.
22116
- *
22117
- * @returns {number} The maximum index value.
22118
- */
22119
-
22120
-
22121
- this.maxIndex = function () {
22122
- if (m_info) {
22123
- /* This isn't just m_info.mappedColors.length - 1, since there
22124
- * may be more data than actual indices. */
22125
- if (m_info.maxIndex === undefined) {
22126
- m_info.maxIndex = 0;
22127
-
22128
- for (var idx in m_info.mappedColors) {
22129
- if (m_info.mappedColors.hasOwnProperty(idx)) {
22130
- m_info.maxIndex = Math.max(m_info.maxIndex, idx);
22131
- }
22132
- }
22133
- }
22134
-
22135
- return m_info.maxIndex;
22136
- }
22137
- };
22138
22326
  /**
22139
22327
  * Get/Set color accessor.
22140
22328
  *
@@ -22156,46 +22344,101 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22156
22344
  return m_this;
22157
22345
  };
22158
22346
  /**
22159
- * If the specified coordinates are in the rendered quad, use the basis
22160
- * information from the quad to determine the pixelmap index value so that it
22161
- * can be included in the `found` results.
22347
+ * Mark that an index's data value (and hence its color) has changed without
22348
+ * marking all of the data array as changed. If this function is called
22349
+ * without any parameters, it clears the tracked changes.
22162
22350
  *
22163
- * @param {geo.geoPosition} geo Coordinate.
22164
- * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
22165
- * the interface gcs, `null` to use the map gcs, or any other transform.
22166
- * @returns {geo.feature.searchResult} An object with a list of features and
22167
- * feature indices that are located at the specified point.
22351
+ * @param {number} [idx] The lowest data index that has changed. If
22352
+ * `undefined`, return the current tracked changed range.
22353
+ * @param {number|'clear'} [idx2] If an index was specified in `idx` and
22354
+ * this is specified, the highest index (inclusive) that has changed. If
22355
+ * returning the tracked changed range and this is `clear`, clear the
22356
+ * tracked range.
22357
+ * @returns {this|number[]} When returning a range, this is the lowest and
22358
+ * highest index values that have changed (inclusive), so their range is
22359
+ * `[0, data.length)`.
22168
22360
  */
22169
22361
 
22170
22362
 
22171
- this.pointSearch = function (geo, gcs) {
22172
- if (m_quadFeature && m_info) {
22173
- var result = m_quadFeature.pointSearch(geo, gcs);
22363
+ this.indexModified = function (idx, idx2) {
22364
+ if (idx === undefined) {
22365
+ var range = m_modifiedIndexRange;
22174
22366
 
22175
- if (result.index.length === 1 && result.extra && result.extra[result.index[0]].basis) {
22176
- var basis = result.extra[result.index[0]].basis,
22177
- x,
22178
- y,
22179
- idx;
22180
- x = Math.floor(basis.x * m_info.width);
22181
- y = Math.floor(basis.y * m_info.height);
22367
+ if (idx2 === 'clear') {
22368
+ m_modifiedIndexRange = undefined;
22369
+ }
22182
22370
 
22183
- if (x >= 0 && x < m_info.width && y >= 0 && y < m_info.height) {
22184
- idx = m_info.indices[y * m_info.width + x];
22185
- result = {
22186
- index: [idx],
22187
- found: [m_this.data()[idx]]
22188
- };
22189
- return result;
22371
+ return range;
22372
+ }
22373
+
22374
+ m_this.modified();
22375
+
22376
+ if (m_modifiedIndexRange === undefined) {
22377
+ m_modifiedIndexRange = [idx, idx];
22378
+ }
22379
+
22380
+ if (idx < m_modifiedIndexRange[0]) {
22381
+ m_modifiedIndexRange[0] = idx;
22382
+ }
22383
+
22384
+ if ((idx2 || idx) > m_modifiedIndexRange[1]) {
22385
+ m_modifiedIndexRange[1] = idx2 || idx;
22386
+ }
22387
+
22388
+ return m_this;
22389
+ };
22390
+ /**
22391
+ * Update.
22392
+ *
22393
+ * @returns {this}
22394
+ */
22395
+
22396
+
22397
+ this._update = function () {
22398
+ s_update.call(m_this);
22399
+
22400
+ if (m_this.buildTime().timestamp() <= m_this.dataTime().timestamp() || m_this.updateTime().timestamp() < m_this.timestamp()) {
22401
+ m_this._build();
22402
+ }
22403
+
22404
+ m_this.updateTime().modified();
22405
+ return m_this;
22406
+ };
22407
+ /**
22408
+ * Get the maximum index value from the pixelmap. This is a value present in
22409
+ * the pixelmap.
22410
+ *
22411
+ * @returns {number} The maximum index value.
22412
+ */
22413
+
22414
+
22415
+ this.maxIndex = function () {
22416
+ if (m_this.m_info) {
22417
+ /* This isn't just m_info.mappedColors.length - 1, since there
22418
+ * may be more data than actual indices. */
22419
+ if (m_this.m_info.maxIndex === undefined) {
22420
+ m_this.m_info.maxIndex = 0;
22421
+
22422
+ for (var idx in m_this.m_info.mappedColors) {
22423
+ if (m_this.m_info.mappedColors.hasOwnProperty(idx)) {
22424
+ m_this.m_info.maxIndex = Math.max(m_this.m_info.maxIndex, idx);
22425
+ }
22190
22426
  }
22191
22427
  }
22192
- }
22193
22428
 
22194
- return {
22195
- index: [],
22196
- found: []
22197
- };
22429
+ return m_this.m_info.maxIndex;
22430
+ }
22198
22431
  };
22432
+ /**
22433
+ * Given the loaded pixelmap image, create a canvas the size of the image.
22434
+ * Compute a color for each distinct index and recolor the canvas based on
22435
+ * these colors, then draw the resultant image as a quad.
22436
+ *
22437
+ * @fires geo.event.pixelmap.prepared
22438
+ */
22439
+
22440
+
22441
+ this._computePixelmap = function () {};
22199
22442
  /**
22200
22443
  * Build. Fetches the image if necessary.
22201
22444
  *
@@ -22208,14 +22451,12 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22208
22451
  * drawing a quad, which can trigger a full layer update, which in turn
22209
22452
  * checks if this feature is built. Setting the build time avoids calling
22210
22453
  * this a second time. */
22211
- m_this.buildTime().modified();
22212
-
22213
- if (!m_srcImage) {
22454
+ if (!m_this.m_srcImage) {
22214
22455
  var src = m_this.style.get('url')();
22215
22456
 
22216
22457
  if (util.isReadyImage(src)) {
22217
22458
  /* we have an already loaded image, so we can just use it. */
22218
- m_srcImage = src;
22459
+ m_this.m_srcImage = src;
22219
22460
 
22220
22461
  m_this._computePixelmap();
22221
22462
  } else if (src) {
@@ -22226,19 +22467,19 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22226
22467
  if (src instanceof Image) {
22227
22468
  /* we have an unloaded image. Hook to the load and error callbacks
22228
22469
  * so that when it is loaded we can use it. */
22229
- m_srcImage = src;
22470
+ m_this.m_srcImage = src;
22230
22471
  prev_onload = src.onload;
22231
22472
  prev_onerror = src.onerror;
22232
22473
  } else {
22233
22474
  /* we were given a url, so construct a new image */
22234
- m_srcImage = new Image(); // Only set the crossOrigin parameter if this is going across origins.
22475
+ m_this.m_srcImage = new Image(); // Only set the crossOrigin parameter if this is going across origins.
22235
22476
 
22236
22477
  if (src.indexOf(':') >= 0 && src.indexOf('/') === src.indexOf(':') + 1) {
22237
- m_srcImage.crossOrigin = m_this.style.get('crossDomain')() || 'anonymous';
22478
+ m_this.m_srcImage.crossOrigin = m_this.style.get('crossDomain')() || 'anonymous';
22238
22479
  }
22239
22480
  }
22240
22481
 
22241
- m_srcImage.onload = function () {
22482
+ m_this.m_srcImage.onload = function () {
22242
22483
  if (prev_onload) {
22243
22484
  prev_onload.apply(m_this, arguments);
22244
22485
  }
@@ -22247,7 +22488,7 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22247
22488
 
22248
22489
 
22249
22490
  if (m_this.style.get('url')() === src) {
22250
- m_info = undefined;
22491
+ m_this.m_info = undefined;
22251
22492
 
22252
22493
  m_this._computePixelmap();
22253
22494
  }
@@ -22255,7 +22496,7 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22255
22496
  defer.resolve();
22256
22497
  };
22257
22498
 
22258
- m_srcImage.onerror = function () {
22499
+ m_this.m_srcImage.onerror = function () {
22259
22500
  if (prev_onerror) {
22260
22501
  prev_onerror.apply(m_this, arguments);
22261
22502
  }
@@ -22267,197 +22508,14 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22267
22508
  m_this.layer().addPromise(m_this);
22268
22509
 
22269
22510
  if (!(src instanceof Image)) {
22270
- m_srcImage.src = src;
22511
+ m_this.m_srcImage.src = src;
22271
22512
  }
22272
22513
  }
22273
- } else if (m_info) {
22514
+ } else if (m_this.m_info) {
22274
22515
  m_this._computePixelmap();
22275
22516
  }
22276
22517
 
22277
- return m_this;
22278
- };
22279
- /**
22280
- * Compute information for this pixelmap image. It is wasteful to call this
22281
- * if the pixelmap has already been prepared (it is invalidated by a change
22282
- * in the image).
22283
- *
22284
- * @returns {geo.pixelmapFeature.info}
22285
- */
22286
-
22287
-
22288
- this._preparePixelmap = function () {
22289
- var i, idx, pixelData;
22290
-
22291
- if (!util.isReadyImage(m_srcImage)) {
22292
- return;
22293
- }
22294
-
22295
- m_info = {
22296
- width: m_srcImage.naturalWidth,
22297
- height: m_srcImage.naturalHeight,
22298
- canvas: document.createElement('canvas')
22299
- };
22300
- m_info.canvas.width = m_info.width;
22301
- m_info.canvas.height = m_info.height;
22302
- m_info.context = m_info.canvas.getContext('2d');
22303
- m_info.context.drawImage(m_srcImage, 0, 0);
22304
- m_info.imageData = m_info.context.getImageData(0, 0, m_info.canvas.width, m_info.canvas.height);
22305
- pixelData = m_info.imageData.data;
22306
- m_info.indices = new Array(pixelData.length / 4);
22307
- m_info.area = pixelData.length / 4;
22308
- m_info.mappedColors = {};
22309
-
22310
- for (i = 0; i < pixelData.length; i += 4) {
22311
- idx = pixelData[i] + (pixelData[i + 1] << 8) + (pixelData[i + 2] << 16);
22312
- m_info.indices[i / 4] = idx;
22313
-
22314
- if (!m_info.mappedColors[idx]) {
22315
- m_info.mappedColors[idx] = {
22316
- first: i / 4
22317
- };
22318
- }
22319
-
22320
- m_info.mappedColors[idx].last = i / 4;
22321
- }
22322
-
22323
- return m_info;
22324
- };
22325
- /**
22326
- * Given the loaded pixelmap image, create a canvas the size of the image.
22327
- * Compute a color for each distinct index and recolor the canvas based on
22328
- * these colors, then draw the resultant image as a quad.
22329
- *
22330
- * @fires geo.event.pixelmap.prepared
22331
- */
22332
-
22333
-
22334
- this._computePixelmap = function () {
22335
- var data = m_this.data() || [],
22336
- colorFunc = m_this.style.get('color'),
22337
- i,
22338
- idx,
22339
- lastidx,
22340
- color,
22341
- pixelData,
22342
- indices,
22343
- mappedColors,
22344
- updateFirst,
22345
- updateLast = -1,
22346
- update,
22347
- prepared;
22348
-
22349
- if (!m_info) {
22350
- if (!m_this._preparePixelmap()) {
22351
- return;
22352
- }
22353
-
22354
- prepared = true;
22355
- }
22356
-
22357
- mappedColors = m_info.mappedColors;
22358
- updateFirst = m_info.area;
22359
-
22360
- for (idx in mappedColors) {
22361
- if (mappedColors.hasOwnProperty(idx)) {
22362
- color = colorFunc(data[idx], +idx) || {};
22363
- color = [(color.r || 0) * 255, (color.g || 0) * 255, (color.b || 0) * 255, color.a === undefined ? 255 : color.a * 255];
22364
- mappedColors[idx].update = !mappedColors[idx].color || mappedColors[idx].color[0] !== color[0] || mappedColors[idx].color[1] !== color[1] || mappedColors[idx].color[2] !== color[2] || mappedColors[idx].color[3] !== color[3];
22365
-
22366
- if (mappedColors[idx].update) {
22367
- mappedColors[idx].color = color;
22368
- updateFirst = Math.min(mappedColors[idx].first, updateFirst);
22369
- updateLast = Math.max(mappedColors[idx].last, updateLast);
22370
- }
22371
- }
22372
- }
22373
- /* If nothing was updated, we are done */
22374
-
22375
-
22376
- if (updateFirst >= updateLast) {
22377
- return;
22378
- }
22379
- /* Update only the extent that has changed */
22380
-
22381
-
22382
- pixelData = m_info.imageData.data;
22383
- indices = m_info.indices;
22384
-
22385
- for (i = updateFirst; i <= updateLast; i += 1) {
22386
- idx = indices[i];
22387
-
22388
- if (idx !== lastidx) {
22389
- lastidx = idx;
22390
- color = mappedColors[idx].color;
22391
- update = mappedColors[idx].update;
22392
- }
22393
-
22394
- if (update) {
22395
- pixelData[i * 4] = color[0];
22396
- pixelData[i * 4 + 1] = color[1];
22397
- pixelData[i * 4 + 2] = color[2];
22398
- pixelData[i * 4 + 3] = color[3];
22399
- }
22400
- }
22401
- /* Place the updated area into the canvas */
22402
-
22403
-
22404
- m_info.context.putImageData(m_info.imageData, 0, 0, 0, Math.floor(updateFirst / m_info.width), m_info.width, Math.ceil((updateLast + 1) / m_info.width));
22405
- /* If we haven't made a quad feature, make one now. The quad feature needs
22406
- * to have the canvas capability. */
22407
-
22408
- if (!m_quadFeature) {
22409
- m_quadFeature = m_this.layer().createFeature('quad', {
22410
- selectionAPI: false,
22411
- gcs: m_this.gcs(),
22412
- visible: m_this.visible(undefined, true)
22413
- });
22414
- m_this.dependentFeatures([m_quadFeature]);
22415
- m_quadFeature.style({
22416
- image: m_info.canvas,
22417
- position: m_this.style.get('position')
22418
- }).data([{}]).draw();
22419
- }
22420
- /* If we prepared the pixelmap and rendered it, send a prepared event */
22421
-
22422
-
22423
- if (prepared) {
22424
- m_this.geoTrigger(geo_event.pixelmap.prepared, {
22425
- pixelmap: m_this
22426
- });
22427
- }
22428
- };
22429
- /**
22430
- * Update.
22431
- *
22432
- * @returns {this}
22433
- */
22434
-
22435
-
22436
- this._update = function () {
22437
- s_update.call(m_this);
22438
-
22439
- if (m_this.buildTime().timestamp() <= m_this.dataTime().timestamp() || m_this.updateTime().timestamp() < m_this.timestamp()) {
22440
- m_this._build();
22441
- }
22442
-
22443
- m_this.updateTime().modified();
22444
- return m_this;
22445
- };
22446
- /**
22447
- * Destroy. Deletes the associated quadFeature.
22448
- *
22449
- * @returns {this}
22450
- */
22451
-
22452
-
22453
- this._exit = function () {
22454
- if (m_quadFeature && m_this.layer()) {
22455
- m_this.layer().deleteFeature(m_quadFeature);
22456
- m_quadFeature = null;
22457
- m_this.dependentFeatures([]);
22458
- }
22459
-
22460
- s_exit();
22518
+ m_this.buildTime().modified();
22461
22519
  return m_this;
22462
22520
  };
22463
22521
  /**
@@ -22499,6 +22557,13 @@ var pixelmapFeature = function pixelmapFeature(arg) {
22499
22557
 
22500
22558
  m_this.style(style);
22501
22559
  m_this.dataTime().modified();
22560
+
22561
+ if (arg.quadFeature) {
22562
+ m_this.m_srcImage = true;
22563
+
22564
+ m_this._computePixelmap();
22565
+ }
22566
+
22502
22567
  return m_this;
22503
22568
  };
22504
22569
 
@@ -22524,13 +22589,182 @@ pixelmapFeature.create = function (layer, spec) {
22524
22589
 
22525
22590
  pixelmapFeature.capabilities = {
22526
22591
  /* core feature name -- support in any manner */
22527
- feature: 'pixelmap'
22592
+ feature: 'pixelmap',
22593
+
22594
+ /* support for image-based lookup */
22595
+ lookup: 'pixelmap.lookup'
22528
22596
  };
22529
22597
  inherit(pixelmapFeature, feature);
22530
22598
  module.exports = pixelmapFeature;
22531
22599
 
22532
22600
  /***/ }),
22533
22601
 
22602
+ /***/ 809:
22603
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
22604
+
22605
+ var $ = __webpack_require__(5638);
22606
+
22607
+ var inherit = __webpack_require__(5699);
22608
+
22609
+ var tileLayer = __webpack_require__(1940);
22610
+
22611
+ var registry = __webpack_require__(4647);
22612
+
22613
+ var quadFeature = __webpack_require__(5017);
22614
+
22615
+ var pixelmapFeature = __webpack_require__(6374);
22616
+ /**
22617
+ * Object specification for a pixelmap layer.
22618
+ *
22619
+ * @typedef {geo.tileLayer.spec} geo.pixelmapLayer.spec
22620
+ * @extends {geo.tileLayer.spec}
22621
+ * @property {geo.geoColor|function} [color] The color that should be used
22622
+ * for each data element. Data elements correspond to the indices in the
22623
+ * pixel map. If an index is larger than the number of data elements, it will
22624
+ * be transparent. If there is more data than there are indices, it is
22625
+ * ignored.
22626
+ * @property {object} [style] An optional style object that could contain
22627
+ * `color` or other style values.
22628
+ * @property {array} [data] A new data array.
22629
+ * @property {string} [crossDomain='anonymous'] Image CORS attribute. This is
22630
+ * used for the `crossorigin` property when loading images.
22631
+ */
22632
+
22633
+ /**
22634
+ * Create a new instance of pixelmapLayer. This is a {@link geo.tileLayer} with
22635
+ * an OSM url and attribution defaults and with the tiles centered on the
22636
+ * origin.
22637
+ *
22638
+ * @class
22639
+ * @alias geo.pixelmapLayer
22640
+ * @extends geo.tileLayer
22641
+ *
22642
+ * @param {geo.pixelmapLayer.spec} [arg] Specification for the layer.
22643
+ */
22644
+
22645
+
22646
+ var pixelmapLayer = function pixelmapLayer(arg) {
22647
+ var imageTile = __webpack_require__(4665);
22648
+
22649
+ if (!(this instanceof pixelmapLayer)) {
22650
+ return new pixelmapLayer(arg);
22651
+ }
22652
+
22653
+ arg = arg || {};
22654
+ arg = $.extend(true, {}, this.constructor.defaults, arg);
22655
+ tileLayer.call(this, arg);
22656
+ var s_init = this._init,
22657
+ m_pixelmapFeature,
22658
+ m_this = this;
22659
+ /**
22660
+ * Returns an instantiated imageTile object with the given indices. This
22661
+ * method always returns a new tile object. Use `_getTileCached` to use
22662
+ * the caching layer.
22663
+ *
22664
+ * @param {object} index The tile index.
22665
+ * @param {number} index.x
22666
+ * @param {number} index.y
22667
+ * @param {number} index.level
22668
+ * @param {object} source The tile index used for constructing the url.
22669
+ * @param {number} source.x
22670
+ * @param {number} source.y
22671
+ * @param {number} source.level
22672
+ * @returns {geo.tile}
22673
+ */
22674
+
22675
+ this._getTile = function (index, source) {
22676
+ var urlParams = source || index;
22677
+ return imageTile({
22678
+ index: index,
22679
+ size: {
22680
+ x: m_this._options.tileWidth,
22681
+ y: m_this._options.tileHeight
22682
+ },
22683
+ queue: m_this._queue,
22684
+ overlap: m_this._options.tileOverlap,
22685
+ scale: m_this._options.tileScale,
22686
+ url: m_this._options.url.call(m_this, urlParams.x, urlParams.y, urlParams.level || 0, m_this._options.subdomains),
22687
+ crossDomain: m_this._options.crossDomain
22688
+ });
22689
+ };
22690
+ /**
22691
+ * Initialize.
22692
+ *
22693
+ * @returns {this} The current layer.
22694
+ */
22695
+
22696
+
22697
+ this._init = function () {
22698
+ // Call super class init
22699
+ s_init.apply(m_this, arguments);
22700
+ var pixelmapArgs = {
22701
+ quadFeature: m_this.features()[0]
22702
+ };
22703
+
22704
+ if (arg.style) {
22705
+ pixelmapArgs.style = arg.style;
22706
+ }
22707
+
22708
+ if (arg.color) {
22709
+ pixelmapArgs.color = arg.color;
22710
+ }
22711
+
22712
+ m_pixelmapFeature = m_this.createFeature('pixelmap', pixelmapArgs);
22713
+
22714
+ if (arg.data) {
22715
+ m_pixelmapFeature.data(arg.data);
22716
+ }
22717
+
22718
+ m_this.style = m_pixelmapFeature.style;
22719
+ m_this.data = m_pixelmapFeature.data;
22720
+ m_this.indexModified = m_pixelmapFeature.indexModified;
22721
+ var s_dataTimeModified = m_this.dataTime().modified;
22722
+
22723
+ m_this.dataTime().modified = function () {
22724
+ m_pixelmapFeature.dataTime().modified();
22725
+ return s_dataTimeModified();
22726
+ };
22727
+
22728
+ ['modified', 'geoOn', 'geoOff', 'geoOnce'].forEach(function (funcName) {
22729
+ var superFunc = m_this[funcName];
22730
+
22731
+ m_this[funcName] = function () {
22732
+ m_pixelmapFeature[funcName].apply(this, arguments);
22733
+ return superFunc.apply(this, arguments);
22734
+ };
22735
+ });
22736
+ return m_this;
22737
+ };
22738
+
22739
+ return m_this;
22740
+ };
22741
+ /**
22742
+ * This object contains the default options used to initialize the
22743
+ * pixelmapLayer.
22744
+ */
22745
+
22746
+
22747
+ pixelmapLayer.defaults = $.extend({}, tileLayer.defaults, {
22748
+ features: [quadFeature.capabilities.image, pixelmapFeature.capabilities.lookup],
22749
+ tileOffset: function tileOffset(level) {
22750
+ var s = Math.pow(2, level - 1) * 256;
22751
+ return {
22752
+ x: s,
22753
+ y: s
22754
+ };
22755
+ },
22756
+ url: ''
22757
+ });
22758
+ inherit(pixelmapLayer, tileLayer);
22759
+ /* By default, ask to support image quads. If the user needs full
22760
+ * reprojection, they will need to require the
22761
+ * quadFeature.capabilities.imageFull feature */
22762
+
22763
+ registry.registerLayer('pixelmap', pixelmapLayer, [quadFeature.capabilities.image]);
22764
+ module.exports = pixelmapLayer;
22765
+
22766
+ /***/ }),
22767
+
22534
22768
  /***/ 2557:
22535
22769
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
22536
22770
 
@@ -23916,9 +24150,9 @@ var polygonFeature = function polygonFeature(arg) {
23916
24150
  *
23917
24151
  * @param {array} data A new data array.
23918
24152
  * @param {number} [tolerance] The maximum variation allowed in map.gcs
23919
- * units. A value of zero will only remove perfectly colinear points. If
23920
- * not specified, this is set to a half display pixel at the map's current
23921
- * zoom level.
24153
+ * units. A value of zero will only remove perfectly collinear points.
24154
+ * If not specified, this is set to a half display pixel at the map's
24155
+ * current zoom level.
23922
24156
  * @param {function} [posFunc=this.style.get('position')] The function to
23923
24157
  * get the position of each vertex.
23924
24158
  * @param {function} [polyFunc=this.style.get('polygon')] The function to
@@ -24419,7 +24653,8 @@ var quadFeature = function quadFeature(arg) {
24419
24653
 
24420
24654
  if (coordbasis) {
24421
24655
  extra[quad.idx] = {
24422
- basis: coordbasis
24656
+ basis: coordbasis,
24657
+ _quad: quad
24423
24658
  };
24424
24659
  }
24425
24660
  }
@@ -26017,7 +26252,7 @@ module.exports = sceneObject;
26017
26252
  * @constant
26018
26253
  * @type {string}
26019
26254
  */
26020
- module.exports = "6670a9640d46540bbf80aaa643d96617642bd23d";
26255
+ module.exports = "03cedc56b8ea2e6582a37ce935e354bae0a9b411";
26021
26256
 
26022
26257
  /***/ }),
26023
26258
 
@@ -29612,7 +29847,7 @@ var tileLayer = function tileLayer(arg) {
29612
29847
  changed = false,
29613
29848
  old,
29614
29849
  level,
29615
- minLevel = m_this._options.keepLower ? m_this._options.minLevel : maxLevel;
29850
+ minLevel = m_this._options.keepLower ? m_this._options.minLevel : Math.max(maxLevel, m_this._options.minLevel);
29616
29851
 
29617
29852
  if (maxLevel < minLevel) {
29618
29853
  maxLevel = minLevel;
@@ -30552,7 +30787,7 @@ var tileLayer = function tileLayer(arg) {
30552
30787
  /* For tile layers that should only keep one layer, if loading is
30553
30788
  * finished, purge all but the current layer. This is important for
30554
30789
  * semi-transparent layers. */
30555
- if ((doneLoading || m_this._isCovered(tile)) && zoom !== tile.index.level) {
30790
+ if ((doneLoading || m_this._isCovered(tile)) && zoom !== tile.index.level && (zoom >= m_this._options.minLevel || tile.index.level !== m_this._options.minLevel)) {
30556
30791
  return true;
30557
30792
  }
30558
30793
  }
@@ -36750,7 +36985,7 @@ var util = {
36750
36985
  /**
36751
36986
  * Determine if two line segments cross. They are not considered crossing if
36752
36987
  * they share a vertex. They are crossing if either of one segment's
36753
- * vertices are colinear with the other segment.
36988
+ * vertices are collinear with the other segment.
36754
36989
  *
36755
36990
  * @param {geo.geoPosition} seg1pt1 One endpoint of the first segment.
36756
36991
  * @param {geo.geoPosition} seg1pt2 The other endpoint of the first segment.
@@ -36772,7 +37007,7 @@ var util = {
36772
37007
  }
36773
37008
  /* If the lines cross, the signed area of the triangles formed between one
36774
37009
  * segment and the other's vertices will have different signs. By using
36775
- * > 0, colinear points are crossing. */
37010
+ * > 0, collinear points are crossing. */
36776
37011
 
36777
37012
 
36778
37013
  if (util.triangleTwiceSignedArea2d(seg1pt1, seg1pt2, seg2pt1) * util.triangleTwiceSignedArea2d(seg1pt1, seg1pt2, seg2pt2) > 0 || util.triangleTwiceSignedArea2d(seg2pt1, seg2pt2, seg1pt1) * util.triangleTwiceSignedArea2d(seg2pt1, seg2pt2, seg1pt2) > 0) {
@@ -36819,7 +37054,7 @@ var util = {
36819
37054
  * @param {geo.geoPosition[]} pts A list of points forming the line or
36820
37055
  * polygon.
36821
37056
  * @param {number} tolerance The maximum variation allowed. A value of zero
36822
- * will only remove perfectly colinear points.
37057
+ * will only remove perfectly collinear points.
36823
37058
  * @param {boolean} [closed] If true, this is a polygon rather than an open
36824
37059
  * line. In this case, it is possible to get back a single point.
36825
37060
  * @param {Array.<geo.geoPosition[]>?} [noCrossLines] A falsy value to allow
@@ -38481,7 +38716,7 @@ module.exports = vectorFeature;
38481
38716
  * @constant
38482
38717
  * @type {string}
38483
38718
  */
38484
- module.exports = "1.6.4";
38719
+ module.exports = "1.7.1";
38485
38720
 
38486
38721
  /***/ }),
38487
38722
 
@@ -39244,8 +39479,10 @@ module.exports = {
39244
39479
  isolineFeature: __webpack_require__(9752),
39245
39480
  layer: __webpack_require__(5389),
39246
39481
  lineFeature: __webpack_require__(7390),
39482
+ lookupTable2D: __webpack_require__(8672),
39247
39483
  markerFeature: __webpack_require__(1848),
39248
39484
  meshColored: __webpack_require__(5651),
39485
+ pixelmapFeature: __webpack_require__(9685),
39249
39486
  pointFeature: __webpack_require__(5675),
39250
39487
  polygonFeature: __webpack_require__(2890),
39251
39488
  quadFeature: __webpack_require__(2182),
@@ -40195,6 +40432,139 @@ module.exports = webgl_lineFeature;
40195
40432
 
40196
40433
  /***/ }),
40197
40434
 
40435
+ /***/ 8672:
40436
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
40437
+
40438
+ var inherit = __webpack_require__(5699);
40439
+
40440
+ var timestamp = __webpack_require__(6618);
40441
+
40442
+ var vgl = __webpack_require__(320);
40443
+ /**
40444
+ * Switch to a specific texture unit.
40445
+ *
40446
+ * @param {vgl.renderState} renderState An object that contains the context
40447
+ * used for drawing.
40448
+ * @param {number} textureUnit The number of the texture unit [0-15].
40449
+ */
40450
+
40451
+
40452
+ function activateTextureUnit(renderState, textureUnit) {
40453
+ if (textureUnit >= 0 && textureUnit <= 31) {
40454
+ renderState.m_context.activeTexture(vgl.GL.TEXTURE0 + textureUnit);
40455
+ } else {
40456
+ throw Error('[error] Texture unit ' + textureUnit + ' is not supported');
40457
+ }
40458
+ }
40459
+ /**
40460
+ * Create a new instance of class webgl_lookupTable2D.
40461
+ *
40462
+ * @class
40463
+ * @alias geo.webgl.lookupTable2D
40464
+ * @param {object} arg Options object.
40465
+ * @param {number} [arg.maxWidth] Maximum width to use for the texture. If the
40466
+ * number of colors set is less than this, the texture is 1D. If greater, it
40467
+ * will be a rectangle of maxWidth x whatever height is necessary.
40468
+ * @param {number[]} [arg.colorTable] Initial color table for the texture.
40469
+ * This is of the form RGBARGBA... where each value is an integer on the
40470
+ * scale [0,255].
40471
+ * @extends vgl.texture
40472
+ * @returns {geo.webgl.lookupTable2D}
40473
+ */
40474
+
40475
+
40476
+ var webgl_lookupTable2D = function webgl_lookupTable2D(arg) {
40477
+ 'use strict';
40478
+
40479
+ if (!(this instanceof webgl_lookupTable2D)) {
40480
+ return new webgl_lookupTable2D(arg);
40481
+ }
40482
+
40483
+ arg = arg || {};
40484
+ vgl.texture.call(this);
40485
+ var m_setupTimestamp = timestamp(),
40486
+ m_maxWidth = arg.maxWidth || 4096,
40487
+ m_colorTable = new Uint8Array([0, 0, 0, 0]),
40488
+ m_colorTableOrig,
40489
+ m_this = this;
40490
+ /**
40491
+ * Create lookup table, initialize parameters, and bind data to it.
40492
+ *
40493
+ * @param {vgl.renderState} renderState An object that contains the context
40494
+ * used for drawing.
40495
+ */
40496
+
40497
+ this.setup = function (renderState) {
40498
+ activateTextureUnit(renderState, m_this.textureUnit());
40499
+ renderState.m_context.deleteTexture(m_this.m_textureHandle);
40500
+ m_this.m_textureHandle = renderState.m_context.createTexture();
40501
+ renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, m_this.m_textureHandle);
40502
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_MIN_FILTER, vgl.GL.NEAREST);
40503
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_MAG_FILTER, vgl.GL.NEAREST);
40504
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_WRAP_S, vgl.GL.CLAMP_TO_EDGE);
40505
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_WRAP_T, vgl.GL.CLAMP_TO_EDGE);
40506
+ renderState.m_context.pixelStorei(vgl.GL.UNPACK_ALIGNMENT, 1);
40507
+ renderState.m_context.pixelStorei(vgl.GL.UNPACK_FLIP_Y_WEBGL, true);
40508
+ renderState.m_context.texImage2D(vgl.GL.TEXTURE_2D, 0, vgl.GL.RGBA, m_this.width, m_this.height, 0, vgl.GL.RGBA, vgl.GL.UNSIGNED_BYTE, m_colorTable);
40509
+ renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, null);
40510
+ m_setupTimestamp.modified();
40511
+ };
40512
+ /**
40513
+ * Get/set color table.
40514
+ *
40515
+ * @param {number[]} [val] An array of RGBARGBA... integers on a scale
40516
+ * of [0, 255]. `undefined` to get the current value.
40517
+ * @returns {number[]|this}
40518
+ */
40519
+
40520
+
40521
+ this.colorTable = function (val) {
40522
+ if (val === undefined) {
40523
+ return m_colorTableOrig;
40524
+ }
40525
+
40526
+ m_colorTableOrig = val;
40527
+
40528
+ if (val.length < 4) {
40529
+ val = [0, 0, 0, 0];
40530
+ }
40531
+
40532
+ m_this.width = Math.min(m_maxWidth, val.length / 4);
40533
+ m_this.height = Math.ceil(val.length / 4 / m_maxWidth);
40534
+
40535
+ if (!(val instanceof Uint8Array) || val.length !== m_this.width * m_this.height * 4) {
40536
+ if (val.length < m_this.width * m_this.height * 4) {
40537
+ val = val.concat(new Array(m_this.width * m_this.height * 4 - val.length).fill(0));
40538
+ }
40539
+
40540
+ m_colorTable = new Uint8Array(val);
40541
+ } else {
40542
+ m_colorTable = val;
40543
+ }
40544
+
40545
+ m_this.modified();
40546
+ return m_this;
40547
+ };
40548
+ /**
40549
+ * Get maxWidth value.
40550
+ *
40551
+ * @returns {number} The maxWidth of the texture used.
40552
+ */
40553
+
40554
+
40555
+ this.maxWidth = function () {
40556
+ return m_maxWidth;
40557
+ };
40558
+
40559
+ this.colorTable(arg.colorTable || []);
40560
+ return this;
40561
+ };
40562
+
40563
+ inherit(webgl_lookupTable2D, vgl.texture);
40564
+ module.exports = webgl_lookupTable2D;
40565
+
40566
+ /***/ }),
40567
+
40198
40568
  /***/ 1848:
40199
40569
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
40200
40570
 
@@ -41134,6 +41504,247 @@ module.exports = webgl_object;
41134
41504
 
41135
41505
  /***/ }),
41136
41506
 
41507
+ /***/ 9685:
41508
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
41509
+
41510
+ var inherit = __webpack_require__(5699);
41511
+
41512
+ var registerFeature = (__webpack_require__(4647).registerFeature);
41513
+
41514
+ var pixelmapFeature = __webpack_require__(6374);
41515
+
41516
+ var lookupTable2D = __webpack_require__(8672);
41517
+
41518
+ var util = __webpack_require__(4634);
41519
+ /**
41520
+ * Create a new instance of class webgl.pixelmapFeature.
41521
+ *
41522
+ * @class
41523
+ * @alias geo.webgl.pixelmapFeature
41524
+ * @extends geo.pixelmapFeature
41525
+ * @param {geo.pixelmapFeature.spec} arg
41526
+ * @returns {geo.webgl.pixelmapFeature}
41527
+ */
41528
+
41529
+
41530
+ var webgl_pixelmapFeature = function webgl_pixelmapFeature(arg) {
41531
+ 'use strict';
41532
+
41533
+ if (!(this instanceof webgl_pixelmapFeature)) {
41534
+ return new webgl_pixelmapFeature(arg);
41535
+ }
41536
+
41537
+ pixelmapFeature.call(this, arg);
41538
+
41539
+ var object = __webpack_require__(7719);
41540
+
41541
+ object.call(this);
41542
+
41543
+ var vgl = __webpack_require__(320);
41544
+
41545
+ var fragmentShader = __webpack_require__(3953);
41546
+
41547
+ var m_quadFeature,
41548
+ m_quadFeatureInit,
41549
+ s_exit = this._exit,
41550
+ m_lookupTable,
41551
+ m_this = this;
41552
+ /**
41553
+ * If the specified coordinates are in the rendered quad, use the basis
41554
+ * information from the quad to determine the pixelmap index value so that it
41555
+ * can be included in the `found` results.
41556
+ *
41557
+ * @param {geo.geoPosition} geo Coordinate.
41558
+ * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
41559
+ * the interface gcs, `null` to use the map gcs, or any other transform.
41560
+ * @returns {geo.feature.searchResult} An object with a list of features and
41561
+ * feature indices that are located at the specified point.
41562
+ */
41563
+
41564
+ this.pointSearch = function (geo, gcs) {
41565
+ if (m_quadFeature && m_this.m_info) {
41566
+ var result = m_quadFeature.pointSearch(geo, gcs); // use the last index by preference, since for tile layers, this is the
41567
+ // topmosttile
41568
+
41569
+ var idxIdx = result.index.length - 1;
41570
+
41571
+ for (; idxIdx >= 0; idxIdx -= 1) {
41572
+ if (result.extra[result.index[idxIdx]]._quad && result.extra[result.index[idxIdx]]._quad.image) {
41573
+ var img = result.extra[result.index[idxIdx]]._quad.image;
41574
+ var basis = result.extra[result.index[idxIdx]].basis;
41575
+ var x = Math.floor(basis.x * img.width);
41576
+ var y = Math.floor(basis.y * img.height);
41577
+ var canvas = document.createElement('canvas');
41578
+ canvas.width = canvas.height = 1;
41579
+ var context = canvas.getContext('2d');
41580
+ context.drawImage(img, x, y, 1, 1, 0, 0, 1, 1);
41581
+ var pixel = context.getImageData(0, 0, 1, 1).data;
41582
+ var idx = pixel[0] + pixel[1] * 256 + pixel[2] * 256 * 256;
41583
+ result = {
41584
+ index: [idx],
41585
+ found: [m_this.data()[idx]]
41586
+ };
41587
+ return result;
41588
+ }
41589
+ }
41590
+ }
41591
+
41592
+ return {
41593
+ index: [],
41594
+ found: []
41595
+ };
41596
+ };
41597
+ /**
41598
+ * Given the loaded pixelmap image, create a texture for the colors and a
41599
+ * quad that will use it.
41600
+ */
41601
+
41602
+
41603
+ this._computePixelmap = function () {
41604
+ var data = m_this.data() || [],
41605
+ colorFunc = m_this.style.get('color');
41606
+ var indexRange = m_this.indexModified(undefined, 'clear');
41607
+ var fullUpdate = m_this.dataTime().timestamp() >= m_this.buildTime().timestamp() || indexRange === undefined;
41608
+
41609
+ if (!m_lookupTable) {
41610
+ m_lookupTable = lookupTable2D();
41611
+ m_lookupTable.setTextureUnit(1);
41612
+ fullUpdate = true;
41613
+ }
41614
+
41615
+ var clrLen = Math.max(1, data.length);
41616
+ var maxWidth = m_lookupTable.maxWidth();
41617
+
41618
+ if (clrLen > maxWidth && clrLen % maxWidth) {
41619
+ clrLen += maxWidth - clrLen % maxWidth;
41620
+ }
41621
+
41622
+ var colors;
41623
+
41624
+ if (!fullUpdate) {
41625
+ colors = m_lookupTable.colorTable();
41626
+ fullUpdate = colors.length !== clrLen * 4;
41627
+ indexRange[0] = Math.max(0, indexRange[0]);
41628
+ indexRange[1] = Math.min(data.length, indexRange[1] + 1);
41629
+ }
41630
+
41631
+ if (fullUpdate) {
41632
+ colors = new Uint8Array(clrLen * 4);
41633
+ indexRange = [0, data.length];
41634
+ }
41635
+
41636
+ for (var i = indexRange[0]; i < indexRange[1]; i += 1) {
41637
+ var d = data[i];
41638
+ var color = util.convertColor(colorFunc.call(m_this, d, i));
41639
+ colors[i * 4] = color.r * 255;
41640
+ colors[i * 4 + 1] = color.g * 255;
41641
+ colors[i * 4 + 2] = color.b * 255;
41642
+ colors[i * 4 + 3] = color.a === undefined ? 255 : color.a * 255;
41643
+ }
41644
+
41645
+ m_this.m_info = {
41646
+ colors: colors
41647
+ }; // check if colors haven't changed
41648
+
41649
+ var oldcolors = m_lookupTable.colorTable();
41650
+
41651
+ if (oldcolors && oldcolors.length === colors.length) {
41652
+ var idx = indexRange[0] * 4;
41653
+
41654
+ for (; idx < indexRange[1] * 4; idx += 1) {
41655
+ if (colors[idx] !== oldcolors[idx]) {
41656
+ break;
41657
+ }
41658
+ }
41659
+
41660
+ if (idx === indexRange[1] * 4) {
41661
+ return;
41662
+ }
41663
+ }
41664
+
41665
+ m_lookupTable.colorTable(colors);
41666
+ /* If we haven't made a quad feature, make one now */
41667
+
41668
+ if (!m_quadFeature) {
41669
+ m_quadFeature = m_this.layer().createFeature('quad', {
41670
+ selectionAPI: false,
41671
+ gcs: m_this.gcs(),
41672
+ visible: m_this.visible(undefined, true)
41673
+ });
41674
+ m_quadFeatureInit = false;
41675
+ }
41676
+
41677
+ if (!m_quadFeatureInit) {
41678
+ m_this.dependentFeatures([m_quadFeature]);
41679
+ m_quadFeature.setShader('image_fragment', fragmentShader);
41680
+
41681
+ m_quadFeature._hookBuild = function (prog) {
41682
+ var lutSampler = new vgl.uniform(vgl.GL.INT, 'lutSampler');
41683
+ lutSampler.set(m_lookupTable.textureUnit());
41684
+ prog.addUniform(lutSampler);
41685
+ var lutWidth = new vgl.uniform(vgl.GL.INT, 'lutWidth');
41686
+ lutWidth.set(m_lookupTable.width);
41687
+ prog.addUniform(lutWidth);
41688
+ var lutHeight = new vgl.uniform(vgl.GL.INT, 'lutHeight');
41689
+ lutHeight.set(m_lookupTable.height);
41690
+ prog.addUniform(lutHeight);
41691
+ };
41692
+
41693
+ m_quadFeature._hookRenderImageQuads = function (renderState, quads) {
41694
+ quads.forEach(function (quad) {
41695
+ if (quad.image && quad.texture && !quad.texture.nearestPixel()) {
41696
+ quad.texture.setNearestPixel(true);
41697
+ }
41698
+ });
41699
+ m_lookupTable.bind(renderState, quads);
41700
+ };
41701
+
41702
+ if (m_quadFeatureInit === false) {
41703
+ m_quadFeature.style({
41704
+ image: m_this.m_srcImage,
41705
+ position: m_this.style.get('position')
41706
+ }).data([{}]).draw();
41707
+ }
41708
+
41709
+ m_quadFeatureInit = true;
41710
+ }
41711
+ };
41712
+ /**
41713
+ * Destroy. Deletes the associated quadFeature.
41714
+ *
41715
+ * @returns {this}
41716
+ */
41717
+
41718
+
41719
+ this._exit = function () {
41720
+ if (m_quadFeature && m_this.layer()) {
41721
+ m_this.layer().deleteFeature(m_quadFeature);
41722
+ m_quadFeature = null;
41723
+ m_this.dependentFeatures([]);
41724
+ }
41725
+
41726
+ s_exit();
41727
+ return m_this;
41728
+ };
41729
+
41730
+ if (arg.quadFeature) {
41731
+ m_quadFeature = arg.quadFeature;
41732
+ }
41733
+
41734
+ this._init(arg);
41735
+
41736
+ return this;
41737
+ };
41738
+
41739
+ inherit(webgl_pixelmapFeature, pixelmapFeature); // Now register it
41740
+
41741
+ var capabilities = {};
41742
+ capabilities[pixelmapFeature.capabilities.lookup] = true;
41743
+ registerFeature('webgl', 'pixelmap', webgl_pixelmapFeature, capabilities);
41744
+ module.exports = webgl_pixelmapFeature;
41745
+
41746
+ /***/ }),
41747
+
41137
41748
  /***/ 5675:
41138
41749
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
41139
41750
 
@@ -42315,6 +42926,8 @@ var registerFeature = (__webpack_require__(4647).registerFeature);
42315
42926
  var quadFeature = __webpack_require__(5017);
42316
42927
 
42317
42928
  var timestamp = __webpack_require__(6618);
42929
+
42930
+ var _memoryCheckLargestTested = 4096 * 4096;
42318
42931
  /**
42319
42932
  * Create a new instance of class quadFeature.
42320
42933
  *
@@ -42498,7 +43111,7 @@ var webgl_quadFeature = function webgl_quadFeature(arg) {
42498
43111
 
42499
43112
 
42500
43113
  this._build = function () {
42501
- var mapper, mat, prog, srctex, unicrop, unicropsource, geom, context;
43114
+ var mapper, mat, prog, srctex, unicrop, unicropsource, geom, context, sampler2d;
42502
43115
 
42503
43116
  if (!m_this.position()) {
42504
43117
  return;
@@ -42523,6 +43136,11 @@ var webgl_quadFeature = function webgl_quadFeature(arg) {
42523
43136
  prog.addUniform(new vgl.projectionUniform('projectionMatrix'));
42524
43137
  prog.addUniform(new vgl.floatUniform('opacity', 1.0));
42525
43138
  prog.addUniform(new vgl.floatUniform('zOffset', 0.0));
43139
+ /* Use texture unit 0 */
43140
+
43141
+ sampler2d = new vgl.uniform(vgl.GL.INT, 'sampler2d');
43142
+ sampler2d.set(0);
43143
+ prog.addUniform(sampler2d);
42526
43144
  context = m_this.renderer()._glContext();
42527
43145
  unicrop = new vgl.uniform(context.FLOAT_VEC2, 'crop');
42528
43146
  unicrop.set([1.0, 1.0]);
@@ -42532,6 +43150,11 @@ var webgl_quadFeature = function webgl_quadFeature(arg) {
42532
43150
  prog.addUniform(unicropsource);
42533
43151
  prog.addShader(vgl.getCachedShader(context.VERTEX_SHADER, context, vertexShaderImage));
42534
43152
  prog.addShader(vgl.getCachedShader(context.FRAGMENT_SHADER, context, fragmentShaderImage));
43153
+
43154
+ if (m_this._hookBuild) {
43155
+ m_this._hookBuild(prog);
43156
+ }
43157
+
42535
43158
  mat.addAttribute(prog);
42536
43159
  mat.addAttribute(new vgl.blend());
42537
43160
  /* This is similar to vgl.planeSource */
@@ -42708,16 +43331,26 @@ var webgl_quadFeature = function webgl_quadFeature(arg) {
42708
43331
  h,
42709
43332
  quadw,
42710
43333
  quadh;
43334
+
43335
+ if (m_this._hookRenderImageQuads) {
43336
+ m_this._hookRenderImageQuads(renderState, m_quads.imgQuads);
43337
+ }
43338
+
42711
43339
  context.bindBuffer(context.ARRAY_BUFFER, m_glBuffers.imgQuadsPosition);
42712
43340
  $.each(m_quads.imgQuads, function (idx, quad) {
42713
43341
  if (!quad.image) {
42714
43342
  return;
42715
43343
  }
42716
43344
 
42717
- quad.texture.bind(renderState);
43345
+ quad.texture.bind(renderState); // only check if the context is out of memory when using modestly large
43346
+ // textures. The check is slow.
42718
43347
 
42719
- if (context.getError() === context.OUT_OF_MEMORY) {
42720
- console.log('Insufficient GPU memory for texture');
43348
+ if (quad.image.width * quad.image.height > _memoryCheckLargestTested) {
43349
+ _memoryCheckLargestTested = quad.image.width * quad.image.height;
43350
+
43351
+ if (context.getError() === context.OUT_OF_MEMORY) {
43352
+ console.log('Insufficient GPU memory for texture');
43353
+ }
42721
43354
  }
42722
43355
 
42723
43356
  if (quad.opacity !== opacity) {
@@ -42824,6 +43457,41 @@ var webgl_quadFeature = function webgl_quadFeature(arg) {
42824
43457
 
42825
43458
  m_this.modified();
42826
43459
  };
43460
+ /**
43461
+ * Set the image or color vertex or fragment shader.
43462
+ *
43463
+ * @param {string} shaderType One of `image_vertex`, `image_fragment`,
43464
+ * `color_vertex`, or `color_fragment`.
43465
+ * @param {string} shaderCode The shader program.
43466
+ * @returns {this} The class instance on success, undefined in an unknown
43467
+ * shaderType was specified.
43468
+ */
43469
+
43470
+
43471
+ this.setShader = function (shaderType, shaderCode) {
43472
+ switch (shaderType) {
43473
+ case 'image_vertex':
43474
+ vertexShaderImage = shaderCode;
43475
+ break;
43476
+
43477
+ case 'image_fragment':
43478
+ fragmentShaderImage = shaderCode;
43479
+ break;
43480
+
43481
+ case 'color_vertex':
43482
+ vertexShaderColor = shaderCode;
43483
+ break;
43484
+
43485
+ case 'color_fragment':
43486
+ fragmentShaderColor = shaderCode;
43487
+ break;
43488
+
43489
+ default:
43490
+ return;
43491
+ }
43492
+
43493
+ return m_this;
43494
+ };
42827
43495
  /**
42828
43496
  * Destroy.
42829
43497
  */
@@ -93906,6 +94574,13 @@ module.exports = "/* contourFeature vertex shader */\n\n#ifdef GL_ES\n precisio
93906
94574
 
93907
94575
  /***/ }),
93908
94576
 
94577
+ /***/ 3953:
94578
+ /***/ (function(module) {
94579
+
94580
+ module.exports = "/* pixelmapFeature fragment shader */\n\nvarying highp vec2 iTextureCoord;\nuniform sampler2D sampler2d;\nuniform sampler2D lutSampler;\nuniform int lutWidth;\nuniform int lutHeight;\nuniform mediump float opacity;\nuniform highp vec2 crop;\n\nvoid main(void) {\n if ((crop.s < 1.0 && iTextureCoord.s > crop.s) || (crop.t < 1.0 && 1.0 - iTextureCoord.t > crop.t)) {\n discard;\n }\n // to add anti-aliasing, we would need to know the current pixel size\n // (probably computed in the vertex shader) and then sample the base image at\n // multiple points, then average the output color.\n highp vec4 lutValue = texture2D(sampler2d, iTextureCoord);\n highp vec2 lutCoord;\n lutCoord.s = (\n mod(\n // add 0.5 to handle float imprecision\n floor(lutValue.r * 255.0 + 0.5) +\n floor(lutValue.g * 255.0 + 0.5) * 256.0,\n float(lutWidth)\n // center in pixel\n ) + 0.5) / float(lutWidth);\n // Our image is top-down, so invert the coordinate\n lutCoord.t = 1.0 - (\n floor(\n (\n // add 0.5 to handle float imprecision\n floor(lutValue.r * 255.0 + 0.5) +\n floor(lutValue.g * 255.0 + 0.5) * 256.0 +\n floor(lutValue.b * 255.0 + 0.5) * 256.0 * 256.0\n // We may want an option to use the alpha channel to allow more indices\n ) / float(lutWidth)\n // center in pixel\n ) + 0.5) / float(lutHeight);\n if (lutCoord.t < 0.0) {\n discard;\n }\n mediump vec4 color = texture2D(lutSampler, lutCoord);\n\n color.a *= opacity;\n gl_FragColor = color;\n}\n"
94581
+
94582
+ /***/ }),
94583
+
93909
94584
  /***/ 1815:
93910
94585
  /***/ (function(module) {
93911
94586