geojs 1.6.2 → 1.6.6

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.
Files changed (51) hide show
  1. package/.github/workflows/main.yml +1 -1
  2. package/.nvmrc +1 -0
  3. package/CHANGELOG.md +19 -1
  4. package/README.md +14 -9
  5. package/geo.js +821 -395
  6. package/geo.lean.js +820 -394
  7. package/geo.lean.min.js +3 -3
  8. package/geo.min.js +4 -4
  9. package/package.json +8 -10
  10. package/src/annotation.js +11 -7
  11. package/src/annotationLayer.js +13 -9
  12. package/src/camera.js +5 -5
  13. package/src/canvas/pixelmapFeature.js +187 -0
  14. package/src/choroplethFeature.js +1 -1
  15. package/src/domRenderer.js +2 -1
  16. package/src/featureLayer.js +1 -1
  17. package/src/fileReader.js +2 -2
  18. package/src/imageTile.js +2 -1
  19. package/src/isolineFeature.js +1 -1
  20. package/src/layer.js +4 -2
  21. package/src/lineFeature.js +3 -3
  22. package/src/map.js +17 -15
  23. package/src/mapInteractor.js +17 -17
  24. package/src/markerFeature.js +2 -2
  25. package/src/meshFeature.js +1 -1
  26. package/src/osmLayer.js +2 -0
  27. package/src/pixelmapFeature.js +52 -228
  28. package/src/pointFeature.js +1 -1
  29. package/src/polygonFeature.js +3 -3
  30. package/src/quadFeature.js +1 -1
  31. package/src/registry.js +2 -2
  32. package/src/svg/svgRenderer.js +3 -3
  33. package/src/tileCache.js +1 -1
  34. package/src/tileLayer.js +10 -10
  35. package/src/trackFeature.js +19 -19
  36. package/src/transform.js +8 -9
  37. package/src/typedef.js +2 -0
  38. package/src/ui/sliderWidget.js +1 -1
  39. package/src/util/clustering.js +3 -3
  40. package/src/util/color.js +1 -1
  41. package/src/util/common.js +7 -7
  42. package/src/util/throttle.js +1 -1
  43. package/src/vtkjs/pointFeature.js +1 -1
  44. package/src/webgl/index.js +2 -0
  45. package/src/webgl/lookupTable2D.js +122 -0
  46. package/src/webgl/markerFeature.js +1 -1
  47. package/src/webgl/pixelmapFeature.frag +47 -0
  48. package/src/webgl/pixelmapFeature.js +172 -0
  49. package/src/webgl/pointFeature.js +1 -1
  50. package/src/webgl/quadFeature.js +32 -1
  51. package/src/webgl/webglRenderer.js +1 -0
@@ -10,24 +10,24 @@ var util = require('./util');
10
10
  * @extends geo.feature.spec
11
11
  * @property {geo.geoPosition|function} [position] Position of the data.
12
12
  * Default is (data).
13
- * @property {float|function} [time] Time of the data. Default is `(data).t`.
13
+ * @property {number|function} [time] Time of the data. Default is `(data).t`.
14
14
  * @property {object|function} [track] Tracks from the data. Default is
15
15
  * (data). Typically, the data is an array of tracks, each of which is an
16
16
  * array of points, each of which has a position and time. The position and
17
17
  * time functions are called for each point as `position(trackPoint,
18
18
  * pointIndex, trackEntry, trackEntryIndex)`.
19
- * @property {float|null} [startTime=null] Start time. Used for styling. If
19
+ * @property {number|null} [startTime=null] Start time. Used for styling. If
20
20
  * `null`, this is the duration before the end time if `duration` is not
21
21
  * `null` and the minimum time in any track if `duration` is `null`.
22
- * @property {float} [endTime=null] End time. Used for styling and position of
23
- * the track head. If `null` and either of `startTime` or `duration` are
22
+ * @property {number} [endTime=null] End time. Used for styling and position
23
+ * of the track head. If `null` and either of `startTime` or `duration` are
24
24
  * `null`, this is the maximum time in any track.
25
- * @property {float} [duration=null] Duration between start and end times.
25
+ * @property {number} [duration=null] Duration between start and end times.
26
26
  * Ignored if both start and end times are specified.
27
- * @property {float|function} [text] Text to use for the head of the track. If
28
- * specified, the track head is rendered as text. If `undefined` a marker is
29
- * used instead. If `null` or an empty string (`''`), neither a marker nor
30
- * text is used.
27
+ * @property {number|function} [text] Text to use for the head of the track.
28
+ * If specified, the track head is rendered as text. If `undefined` a marker
29
+ * is used instead. If `null` or an empty string (`''`), neither a marker
30
+ * nor text is used.
31
31
  * @property {geo.trackFeature.styleSpec} [style] Style object with default
32
32
  * style options.
33
33
  * @property {geo.lineFeature.styleSpec} [pastStyle] Style object with
@@ -168,7 +168,7 @@ var trackFeature = function (arg) {
168
168
  * Calculate an interpolated position given a time. If the time is outside
169
169
  * the range of a track, the first or last point is returned.
170
170
  *
171
- * @param {float} time The time to compute a position array for.
171
+ * @param {number} time The time to compute a position array for.
172
172
  * @param {string|geo.transform|null} [gcs] `undefined` to use the feature
173
173
  * gcs, `null` to use the map gcs, or any other transform. This transform
174
174
  * is used for the interpolation; the results are still in feature gcs.
@@ -275,8 +275,8 @@ var trackFeature = function (arg) {
275
275
  m_tracks.textFunc = m_this.style.get('text');
276
276
  ['past', 'current', 'future'].forEach(key => {
277
277
  m_lineFeatures[key]
278
- .style(m_this[key + 'Style']())
279
278
  .style(m_this.style())
279
+ .style(m_this[key + 'Style']())
280
280
  .line(m_this.style('track'))
281
281
  .gcs(m_this.gcs())
282
282
  .data(data)
@@ -571,11 +571,11 @@ var trackFeature = function (arg) {
571
571
  /**
572
572
  * Get/Set time accessor.
573
573
  *
574
- * @param {float} [val] If not specified, return the current time accessor.
574
+ * @param {number} [val] If not specified, return the current time accessor.
575
575
  * If specified, use this for the time accessor and return `this`. If a
576
576
  * function is given, this is called with `(vertexElement, vertexIndex,
577
577
  * dataElement, dataIndex)`.
578
- * @returns {float|function|this} The current time or this feature.
578
+ * @returns {number|function|this} The current time or this feature.
579
579
  */
580
580
  this.time = function (val) {
581
581
  if (val === undefined) {
@@ -636,8 +636,8 @@ var trackFeature = function (arg) {
636
636
  /**
637
637
  * Get or set the start time.
638
638
  *
639
- * @param {float|null} [val] If specified, the new start time.
640
- * @returns {float|null|this} If set, the instance. Otherwise, the current
639
+ * @param {number|null} [val] If specified, the new start time.
640
+ * @returns {number|null|this} If set, the instance. Otherwise, the current
641
641
  * start time value.
642
642
  */
643
643
  this.startTime = function (val) {
@@ -654,8 +654,8 @@ var trackFeature = function (arg) {
654
654
  /**
655
655
  * Get or set the end time.
656
656
  *
657
- * @param {float|null} [val] If specified, the new end time.
658
- * @returns {float|null|this} If set, the instance. Otherwise, the current
657
+ * @param {number|null} [val] If specified, the new end time.
658
+ * @returns {number|null|this} If set, the instance. Otherwise, the current
659
659
  * end time value.
660
660
  */
661
661
  this.endTime = function (val) {
@@ -672,8 +672,8 @@ var trackFeature = function (arg) {
672
672
  /**
673
673
  * Get or set the duration.
674
674
  *
675
- * @param {float|null} [val] If specified, the new duration.
676
- * @returns {float|null|this} If set, the instance. Otherwise, the current
675
+ * @param {number|null} [val] If specified, the new duration.
676
+ * @returns {number|null|this} If set, the instance. Otherwise, the current
677
677
  * duration.
678
678
  */
679
679
  this.duration = function (val) {
package/src/transform.js CHANGED
@@ -330,11 +330,12 @@ transform.lookup = function (projection) {
330
330
  *
331
331
  * @param {string} srcPrj The source projection.
332
332
  * @param {string} tgtPrj The destination projection.
333
- * @param {geoPosition|geoPosition[]|number[]} coordinates An array of
334
- * coordinate objects. These may be in object or array form, or a flat
335
- * array.
336
- * @param {number} numberOfComponents For flat arrays, either 2 or 3.
337
- * @returns {geoPosition|geoPosition[]|number[]} The transformed coordinates.
333
+ * @param {geo.geoPosition|geo.geoPosition[]|number[]} coordinates An array of
334
+ * coordinate objects. These may be in object or array form, or a flat
335
+ * array.
336
+ * @param {number} [numberOfComponents] For flat arrays, either 2 or 3.
337
+ * @returns {geo.geoPosition|geo.geoPosition[]|number[]} The transformed
338
+ * coordinates.
338
339
  */
339
340
  transform.transformCoordinates = function (srcPrj, tgtPrj, coordinates, numberOfComponents) {
340
341
  'use strict';
@@ -385,10 +386,10 @@ transform.transformCoordinates = function (srcPrj, tgtPrj, coordinates, numberOf
385
386
  * components per coordinate. The array is modified in place.
386
387
  *
387
388
  * @param {transform} trans The transformation object.
388
- * @param {geoPosition[]|number[]} coordinates An array of coordinate
389
+ * @param {geo.geoPosition[]|number[]} coordinates An array of coordinate
389
390
  * objects or a flat array.
390
391
  * @param {number} numberOfComponents For flat arrays, either 2 or 3.
391
- * @returns {geoPosition[]|number[]} The transformed coordinates
392
+ * @returns {geo.geoPosition[]|number[]} The transformed coordinates
392
393
  */
393
394
  transform.transformCoordinatesArray = function (trans, coordinates, numberOfComponents) {
394
395
  var i, count, offset, xAcc, yAcc, zAcc, writer, output, projPoint,
@@ -654,8 +655,6 @@ transform.affineInverse = function (def, coords) {
654
655
  * @param {object} [ellipsoid=proj4.WGS84] An object with at least `a` and one
655
656
  * of `b`, `f`, or `rf` (1 / `f`) -- this works with proj4 ellipsoid
656
657
  * definitions.
657
- * @param {number} [maxIterations=100] Maximum number of iterations to use
658
- * to test convergence.
659
658
  * @returns {number} The distance in meters (or whatever units the ellipsoid
660
659
  * was specified in.
661
660
  */
package/src/typedef.js CHANGED
@@ -234,3 +234,5 @@
234
234
  *
235
235
  * @typedef {geo.polygonFlat|geo.polygonObject} geo.polygon
236
236
  */
237
+
238
+ module.exports = {};
@@ -203,7 +203,7 @@ var sliderWidget = function (arg) {
203
203
  * Respond to a mouse event on the widget.
204
204
  *
205
205
  * @param {d3Event} evt The event on the widget.
206
- * @param {boolean} trans Truthy for an animated transition.
206
+ * @param {boolean} [trans] Truthy for an animated transition.
207
207
  */
208
208
  function respond(evt, trans) {
209
209
  var z = m_yscale.invert(d3.mouse(svg.node())[1]),
@@ -18,7 +18,7 @@ var $ = require('jquery');
18
18
  *
19
19
  * @param {geo.util.ClusterGroup} group The source cluster group
20
20
  * @param {number} zoom The zoom level of the current node
21
- * @param {object[]} children An array of ClusterTrees or point objects
21
+ * @param {object[]} [children] An array of ClusterTrees or point objects
22
22
  */
23
23
  function ClusterTree(group, zoom, children) {
24
24
  this._group = group;
@@ -136,8 +136,8 @@ ClusterTree.prototype.coords = function () {
136
136
  * @class
137
137
  * @alias geo.util.ClusterGroup
138
138
  * @param {object} opts An options object
139
- * @param {number} maxZoom The maximum zoom level to calculate.
140
- * @param {number} radius Size of clustering at zoom 0 in point gcs.
139
+ * @param {number} [opts.maxZoom] The maximum zoom level to calculate.
140
+ * @param {number} [opts.radius] Size of clustering at zoom 0 in point gcs.
141
141
  */
142
142
  function C(opts) {
143
143
 
package/src/util/color.js CHANGED
@@ -59,7 +59,7 @@ var colorName = require('color-name');
59
59
  /**
60
60
  * @typedef {object} geo.util.cssColorConversionRecord
61
61
  * @property {string} name The name of the color conversion.
62
- * @property {RegEx} regex A regex that, if it matches the color string, will
62
+ * @property {RegExp} regex A regex that, if it matches the color string, will
63
63
  * cause the process function to be invoked.
64
64
  * @property {function} process A function that takes (`color`, `match`) with
65
65
  * the original color string and the results of matching the regex using
@@ -128,7 +128,7 @@ var util = {
128
128
  * Check if an object an HTMLVideoElement element that is loaded.
129
129
  *
130
130
  * @param {object} vid An object that might be an HTMLVideoElement.
131
- * @param {boolean} [allowFailedVideo] If `true`, an viedo element that has
131
+ * @param {boolean} [allowFailedVideo] If `true`, an video element that has
132
132
  * a source and has failed to load is also considered 'ready' in the
133
133
  * sense that it isn't expected to change to a better state.
134
134
  * @returns {boolean} `true` if this is a video that is ready.
@@ -525,7 +525,7 @@ var util = {
525
525
  * var map = geo.map($.extend(results.map, {clampZoom: false}));
526
526
  * map.createLayer('osm', results.layer);
527
527
  *
528
- * @param {string} [node] DOM selector for the map container.
528
+ * @param {string?} node DOM selector for the map container.
529
529
  * @param {number} width Width of the whole map contents in pixels.
530
530
  * @param {number} height Height of the whole map contents in pixels.
531
531
  * @param {number} [tileWidth] If an osm or tile layer is going to be used,
@@ -758,7 +758,7 @@ var util = {
758
758
  /**
759
759
  * Determine if two line segments cross. They are not considered crossing if
760
760
  * they share a vertex. They are crossing if either of one segment's
761
- * vertices are colinear with the other segment.
761
+ * vertices are collinear with the other segment.
762
762
  *
763
763
  * @param {geo.geoPosition} seg1pt1 One endpoint of the first segment.
764
764
  * @param {geo.geoPosition} seg1pt2 The other endpoint of the first segment.
@@ -788,7 +788,7 @@ var util = {
788
788
  }
789
789
  /* If the lines cross, the signed area of the triangles formed between one
790
790
  * segment and the other's vertices will have different signs. By using
791
- * > 0, colinear points are crossing. */
791
+ * > 0, collinear points are crossing. */
792
792
  if (util.triangleTwiceSignedArea2d(seg1pt1, seg1pt2, seg2pt1) *
793
793
  util.triangleTwiceSignedArea2d(seg1pt1, seg1pt2, seg2pt2) > 0 ||
794
794
  util.triangleTwiceSignedArea2d(seg2pt1, seg2pt2, seg1pt1) *
@@ -834,7 +834,7 @@ var util = {
834
834
  * @param {geo.geoPosition[]} pts A list of points forming the line or
835
835
  * polygon.
836
836
  * @param {number} tolerance The maximum variation allowed. A value of zero
837
- * will only remove perfectly colinear points.
837
+ * will only remove perfectly collinear points.
838
838
  * @param {boolean} [closed] If true, this is a polygon rather than an open
839
839
  * line. In this case, it is possible to get back a single point.
840
840
  * @param {Array.<geo.geoPosition[]>?} [noCrossLines] A falsy value to allow
@@ -967,7 +967,7 @@ var util = {
967
967
  */
968
968
  escapeUnicodeHTML: function (text) {
969
969
  return text.replace(/./g, function (k) {
970
- var code = k.charCodeAt();
970
+ var code = k.charCodeAt(0);
971
971
  if (code < 127) {
972
972
  return k;
973
973
  }
@@ -1026,7 +1026,7 @@ var util = {
1026
1026
  * stored as local base64 urls.
1027
1027
  *
1028
1028
  * @param {string} css The css to parse for urls.
1029
- * @param {jQuery.selector|DOMElement} styleElem The element that receivs
1029
+ * @param {jQuery.selector|HTMLElement} styleElem The element that receives
1030
1030
  * the css text after dereferencing or the DOM element that has style
1031
1031
  * that will be updated.
1032
1032
  * @param {jQuery.Deferred} styleDefer A Deferred to resolve once
@@ -43,7 +43,7 @@
43
43
  * unspecified, callback will be executed one final time after the last
44
44
  * throttled-function call. (After the throttled-function has not been
45
45
  * called for `delay` milliseconds, the internal counter is reset)
46
- * @param {function} callback A function to be executed after `delay`
46
+ * @param {function} [callback] A function to be executed after `delay`
47
47
  * milliseconds. The `this` context and all arguments are passed through,
48
48
  * as-is, to `callback` when the throttled-function is executed.
49
49
  * @param {function} [accumulator] A function to be executed (synchronously)
@@ -76,7 +76,7 @@ var vtkjs_pointFeature = function (arg) {
76
76
  */
77
77
  this._init = function () {
78
78
  s_init.call(m_this, arg);
79
- m_this.renderer().contextRenderer().setLayer(1);
79
+ m_this.renderer().contextRenderer().setLayer(0);
80
80
  m_this._createPipeline();
81
81
  };
82
82
 
@@ -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'),
@@ -0,0 +1,122 @@
1
+ var inherit = require('../inherit');
2
+ var timestamp = require('../timestamp');
3
+ var vgl = require('vgl');
4
+
5
+ /**
6
+ * Switch to a specific texture unit.
7
+ *
8
+ * @param {vgl.renderState} renderState An object that contains the context
9
+ * used for drawing.
10
+ * @param {number} textureUnit The number of the texture unit [0-15].
11
+ */
12
+ function activateTextureUnit(renderState, textureUnit) {
13
+ if (textureUnit >= 0 && textureUnit <= 31) {
14
+ renderState.m_context.activeTexture(vgl.GL.TEXTURE0 + textureUnit);
15
+ } else {
16
+ throw Error('[error] Texture unit ' + textureUnit + ' is not supported');
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Create a new instance of class webgl_lookupTable2D.
22
+ *
23
+ * @class
24
+ * @alias geo.webgl.lookupTable2D
25
+ * @param {object} arg Options object.
26
+ * @param {number} [arg.maxWidth] Maximum width to use for the texture. If the
27
+ * number of colors set is less than this, the texture is 1D. If greater, it
28
+ * will be a rectangle of maxWidth x whatever height is necessary.
29
+ * @param {number[]} [arg.colorTable] Initial color table for the texture.
30
+ * This is of the form RGBARGBA... where each value is an integer on the
31
+ * scale [0,255].
32
+ * @extends vgl.texture
33
+ * @returns {geo.webgl.lookupTable2D}
34
+ */
35
+ var webgl_lookupTable2D = function (arg) {
36
+ 'use strict';
37
+
38
+ if (!(this instanceof webgl_lookupTable2D)) {
39
+ return new webgl_lookupTable2D(arg);
40
+ }
41
+ arg = arg || {};
42
+ vgl.texture.call(this);
43
+
44
+ var m_setupTimestamp = timestamp(),
45
+ m_maxWidth = arg.maxWidth || 4096,
46
+ m_colorTable = new Uint8Array([0, 0, 0, 0]),
47
+ m_colorTableOrig,
48
+ m_this = this;
49
+
50
+ /**
51
+ * Create lookup table, initialize parameters, and bind data to it.
52
+ *
53
+ * @param {vgl.renderState} renderState An object that contains the context
54
+ * used for drawing.
55
+ */
56
+ this.setup = function (renderState) {
57
+ activateTextureUnit(renderState, m_this.textureUnit());
58
+
59
+ renderState.m_context.deleteTexture(m_this.m_textureHandle);
60
+ m_this.m_textureHandle = renderState.m_context.createTexture();
61
+ renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, m_this.m_textureHandle);
62
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_MIN_FILTER, vgl.GL.NEAREST);
63
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_MAG_FILTER, vgl.GL.NEAREST);
64
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_WRAP_S, vgl.GL.CLAMP_TO_EDGE);
65
+ renderState.m_context.texParameteri(vgl.GL.TEXTURE_2D, vgl.GL.TEXTURE_WRAP_T, vgl.GL.CLAMP_TO_EDGE);
66
+ renderState.m_context.pixelStorei(vgl.GL.UNPACK_ALIGNMENT, 1);
67
+ renderState.m_context.pixelStorei(vgl.GL.UNPACK_FLIP_Y_WEBGL, true);
68
+
69
+ renderState.m_context.texImage2D(
70
+ vgl.GL.TEXTURE_2D, 0, vgl.GL.RGBA, m_this.width, m_this.height, 0,
71
+ vgl.GL.RGBA, vgl.GL.UNSIGNED_BYTE, m_colorTable);
72
+
73
+ renderState.m_context.bindTexture(vgl.GL.TEXTURE_2D, null);
74
+ m_setupTimestamp.modified();
75
+ };
76
+
77
+ /**
78
+ * Get/set color table.
79
+ *
80
+ * @param {number[]} [val] An array of RGBARGBA... integers on a scale
81
+ * of [0, 255]. `undefined` to get the current value.
82
+ * @returns {number[]|this}
83
+ */
84
+ this.colorTable = function (val) {
85
+ if (val === undefined) {
86
+ return m_colorTableOrig;
87
+ }
88
+ m_colorTableOrig = val;
89
+ if (val.length < 4) {
90
+ val = [0, 0, 0, 0];
91
+ }
92
+ m_this.width = Math.min(m_maxWidth, val.length / 4);
93
+ m_this.height = Math.ceil(val.length / 4 / m_maxWidth);
94
+ if (!(val instanceof Uint8Array) || val.length !== m_this.width * m_this.height * 4) {
95
+ if (val.length < m_this.width * m_this.height * 4) {
96
+ val = val.concat(new Array(m_this.width * m_this.height * 4 - val.length).fill(0));
97
+ }
98
+ m_colorTable = new Uint8Array(val);
99
+ } else {
100
+ m_colorTable = val;
101
+ }
102
+ m_this.modified();
103
+ return m_this;
104
+ };
105
+
106
+ /**
107
+ * Get maxWidth value.
108
+ *
109
+ * @returns {number} The maxWidth of the texture used.
110
+ */
111
+ this.maxWidth = function () {
112
+ return m_maxWidth;
113
+ };
114
+
115
+ this.colorTable(arg.colorTable || []);
116
+
117
+ return this;
118
+ };
119
+
120
+ inherit(webgl_lookupTable2D, vgl.texture);
121
+
122
+ module.exports = webgl_lookupTable2D;
@@ -98,7 +98,7 @@ var webgl_markerFeature = function (arg) {
98
98
  /**
99
99
  * Create and style the data needed to render the markers.
100
100
  *
101
- @param {boolean} onlyStyle if true, use the existing geometry and just
101
+ @param {boolean} [onlyStyle] if true, use the existing geometry and just
102
102
  * recalculate the style.
103
103
  */
104
104
  function createGLMarkers(onlyStyle) {
@@ -0,0 +1,47 @@
1
+ /* pixelmapFeature fragment shader */
2
+
3
+ varying highp vec2 iTextureCoord;
4
+ uniform sampler2D sampler2d;
5
+ uniform sampler2D lutSampler;
6
+ uniform int lutWidth;
7
+ uniform int lutHeight;
8
+ uniform mediump float opacity;
9
+ uniform highp vec2 crop;
10
+
11
+ void main(void) {
12
+ if ((crop.s < 1.0 && iTextureCoord.s > crop.s) || (crop.t < 1.0 && 1.0 - iTextureCoord.t > crop.t)) {
13
+ discard;
14
+ }
15
+ // to add anti-aliasing, we would need to know the current pixel size
16
+ // (probably computed in the vertex shader) and then sample the base image at
17
+ // multiple points, then average the output color.
18
+ highp vec4 lutValue = texture2D(sampler2d, iTextureCoord);
19
+ highp vec2 lutCoord;
20
+ lutCoord.s = (
21
+ mod(
22
+ // add 0.5 to handle float imprecision
23
+ floor(lutValue.r * 255.0 + 0.5) +
24
+ floor(lutValue.g * 255.0 + 0.5) * 256.0,
25
+ float(lutWidth)
26
+ // center in pixel
27
+ ) + 0.5) / float(lutWidth);
28
+ // Our image is top-down, so invert the coordinate
29
+ lutCoord.t = 1.0 - (
30
+ floor(
31
+ (
32
+ // add 0.5 to handle float imprecision
33
+ floor(lutValue.r * 255.0 + 0.5) +
34
+ floor(lutValue.g * 255.0 + 0.5) * 256.0 +
35
+ floor(lutValue.b * 255.0 + 0.5) * 256.0 * 256.0
36
+ // We may want an option to use the alpha channel to allow more indices
37
+ ) / float(lutWidth)
38
+ // center in pixel
39
+ ) + 0.5) / float(lutHeight);
40
+ if (lutCoord.t < 0.0) {
41
+ discard;
42
+ }
43
+ mediump vec4 color = texture2D(lutSampler, lutCoord);
44
+
45
+ color.a *= opacity;
46
+ gl_FragColor = color;
47
+ }
@@ -0,0 +1,172 @@
1
+ var inherit = require('../inherit');
2
+ var registerFeature = require('../registry').registerFeature;
3
+ var pixelmapFeature = require('../pixelmapFeature');
4
+ var lookupTable2D = require('./lookupTable2D');
5
+ var util = require('../util');
6
+
7
+ /**
8
+ * Create a new instance of class webgl.pixelmapFeature.
9
+ *
10
+ * @class
11
+ * @alias geo.webgl.pixelmapFeature
12
+ * @extends geo.pixelmapFeature
13
+ * @param {geo.pixelmapFeature.spec} arg
14
+ * @returns {geo.webgl.pixelmapFeature}
15
+ */
16
+ var webgl_pixelmapFeature = function (arg) {
17
+ 'use strict';
18
+
19
+ if (!(this instanceof webgl_pixelmapFeature)) {
20
+ return new webgl_pixelmapFeature(arg);
21
+ }
22
+ pixelmapFeature.call(this, arg);
23
+
24
+ var object = require('./object');
25
+ object.call(this);
26
+
27
+ const vgl = require('vgl');
28
+ const fragmentShader = require('./pixelmapFeature.frag');
29
+
30
+ var m_quadFeature,
31
+ s_exit = this._exit,
32
+ m_lookupTable,
33
+ m_this = this;
34
+
35
+ /**
36
+ * If the specified coordinates are in the rendered quad, use the basis
37
+ * information from the quad to determine the pixelmap index value so that it
38
+ * can be included in the `found` results.
39
+ *
40
+ * @param {geo.geoPosition} geo Coordinate.
41
+ * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
42
+ * the interface gcs, `null` to use the map gcs, or any other transform.
43
+ * @returns {geo.feature.searchResult} An object with a list of features and
44
+ * feature indices that are located at the specified point.
45
+ */
46
+ this.pointSearch = function (geo, gcs) {
47
+ if (m_quadFeature && m_this.m_info) {
48
+ let result = m_quadFeature.pointSearch(geo, gcs);
49
+ if (result.index.length === 1 &&
50
+ result.extra && result.extra[result.index[0]].basis &&
51
+ result.extra[result.index[0]]._quad &&
52
+ result.extra[result.index[0]]._quad.image) {
53
+ const img = result.extra[result.index[0]]._quad.image;
54
+ const basis = result.extra[result.index[0]].basis;
55
+ const x = Math.floor(basis.x * img.width);
56
+ const y = Math.floor(basis.y * img.height);
57
+ const canvas = document.createElement('canvas');
58
+ canvas.width = canvas.height = 1;
59
+ const context = canvas.getContext('2d');
60
+ context.drawImage(img, x, y, 1, 1, 0, 0, 1, 1);
61
+ const pixel = context.getImageData(0, 0, 1, 1).data;
62
+ const idx = pixel[0] + pixel[1] * 256 + pixel[2] * 256 * 256;
63
+ result = {
64
+ index: [idx],
65
+ found: [m_this.data()[idx]]
66
+ };
67
+ return result;
68
+ }
69
+ }
70
+ return {index: [], found: []};
71
+ };
72
+
73
+ /**
74
+ * Given the loaded pixelmap image, create a texture for the colors and a
75
+ * quad that will use it.
76
+ */
77
+ this._computePixelmap = function () {
78
+ var data = m_this.data() || [],
79
+ colorFunc = m_this.style.get('color');
80
+
81
+ if (!m_lookupTable) {
82
+ m_lookupTable = lookupTable2D();
83
+ m_lookupTable.setTextureUnit(1);
84
+ }
85
+ let clrLen = Math.max(1, data.length);
86
+ const maxWidth = m_lookupTable.maxWidth();
87
+ if (clrLen > maxWidth && clrLen % maxWidth) {
88
+ clrLen += maxWidth - (clrLen % maxWidth);
89
+ }
90
+ const colors = new Uint8Array(clrLen * 4);
91
+ data.forEach((d, i) => {
92
+ const color = util.convertColor(colorFunc.call(m_this, d, i));
93
+ colors[i * 4] = color.r * 255;
94
+ colors[i * 4 + 1] = color.g * 255;
95
+ colors[i * 4 + 2] = color.b * 255;
96
+ colors[i * 4 + 3] = color.a === undefined ? 255 : (color.a * 255);
97
+ });
98
+ m_this.m_info = {colors: colors};
99
+ // check if colors haven't changed
100
+ var oldcolors = m_lookupTable.colorTable();
101
+ if (oldcolors && oldcolors.length === colors.length) {
102
+ let idx = 0;
103
+ for (; idx < colors.length; idx += 1) {
104
+ if (colors[idx] !== oldcolors[idx]) {
105
+ break;
106
+ }
107
+ }
108
+ if (idx === colors.length) {
109
+ return;
110
+ }
111
+ }
112
+ m_lookupTable.colorTable(colors);
113
+ /* If we haven't made a quad feature, make one now */
114
+ if (!m_quadFeature) {
115
+ m_quadFeature = m_this.layer().createFeature('quad', {
116
+ selectionAPI: false,
117
+ gcs: m_this.gcs(),
118
+ visible: m_this.visible(undefined, true)
119
+ });
120
+ m_this.dependentFeatures([m_quadFeature]);
121
+ m_quadFeature.setShader('image_fragment', fragmentShader);
122
+ m_quadFeature._hookBuild = (prog) => {
123
+ const lutSampler = new vgl.uniform(vgl.GL.INT, 'lutSampler');
124
+ lutSampler.set(m_lookupTable.textureUnit());
125
+ prog.addUniform(lutSampler);
126
+ const lutWidth = new vgl.uniform(vgl.GL.INT, 'lutWidth');
127
+ lutWidth.set(m_lookupTable.width);
128
+ prog.addUniform(lutWidth);
129
+ const lutHeight = new vgl.uniform(vgl.GL.INT, 'lutHeight');
130
+ lutHeight.set(m_lookupTable.height);
131
+ prog.addUniform(lutHeight);
132
+ };
133
+ m_quadFeature._hookRenderImageQuads = (renderState, quads) => {
134
+ quads.forEach((quad) => {
135
+ if (quad.image && quad.texture && !quad.texture.nearestPixel()) {
136
+ quad.texture.setNearestPixel(true);
137
+ }
138
+ });
139
+ m_lookupTable.bind(renderState, quads);
140
+ };
141
+ m_quadFeature.style({
142
+ image: m_this.m_srcImage,
143
+ position: m_this.style.get('position')})
144
+ .data([{}])
145
+ .draw();
146
+ }
147
+ };
148
+
149
+ /**
150
+ * Destroy. Deletes the associated quadFeature.
151
+ *
152
+ * @returns {this}
153
+ */
154
+ this._exit = function () {
155
+ if (m_quadFeature && m_this.layer()) {
156
+ m_this.layer().deleteFeature(m_quadFeature);
157
+ m_quadFeature = null;
158
+ m_this.dependentFeatures([]);
159
+ }
160
+ s_exit();
161
+ return m_this;
162
+ };
163
+
164
+ this._init(arg);
165
+ return this;
166
+ };
167
+
168
+ inherit(webgl_pixelmapFeature, pixelmapFeature);
169
+
170
+ // Now register it
171
+ registerFeature('webgl', 'pixelmap', webgl_pixelmapFeature);
172
+ module.exports = webgl_pixelmapFeature;
@@ -78,7 +78,7 @@ var webgl_pointFeature = function (arg) {
78
78
  /**
79
79
  * Create and style the data needed to render the points.
80
80
  *
81
- * @param {boolean} onlyStyle if true, use the existing geometry and just
81
+ * @param {boolean} [onlyStyle] if true, use the existing geometry and just
82
82
  * recalculate the style.
83
83
  */
84
84
  function createGLPoints(onlyStyle) {