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.
- package/.github/workflows/main.yml +1 -1
- package/.nvmrc +1 -0
- package/CHANGELOG.md +19 -1
- package/README.md +14 -9
- package/geo.js +821 -395
- package/geo.lean.js +820 -394
- package/geo.lean.min.js +3 -3
- package/geo.min.js +4 -4
- package/package.json +8 -10
- package/src/annotation.js +11 -7
- package/src/annotationLayer.js +13 -9
- package/src/camera.js +5 -5
- package/src/canvas/pixelmapFeature.js +187 -0
- package/src/choroplethFeature.js +1 -1
- package/src/domRenderer.js +2 -1
- package/src/featureLayer.js +1 -1
- package/src/fileReader.js +2 -2
- package/src/imageTile.js +2 -1
- package/src/isolineFeature.js +1 -1
- package/src/layer.js +4 -2
- package/src/lineFeature.js +3 -3
- package/src/map.js +17 -15
- package/src/mapInteractor.js +17 -17
- package/src/markerFeature.js +2 -2
- package/src/meshFeature.js +1 -1
- package/src/osmLayer.js +2 -0
- package/src/pixelmapFeature.js +52 -228
- package/src/pointFeature.js +1 -1
- package/src/polygonFeature.js +3 -3
- package/src/quadFeature.js +1 -1
- package/src/registry.js +2 -2
- package/src/svg/svgRenderer.js +3 -3
- package/src/tileCache.js +1 -1
- package/src/tileLayer.js +10 -10
- package/src/trackFeature.js +19 -19
- package/src/transform.js +8 -9
- package/src/typedef.js +2 -0
- package/src/ui/sliderWidget.js +1 -1
- package/src/util/clustering.js +3 -3
- package/src/util/color.js +1 -1
- package/src/util/common.js +7 -7
- package/src/util/throttle.js +1 -1
- package/src/vtkjs/pointFeature.js +1 -1
- package/src/webgl/index.js +2 -0
- package/src/webgl/lookupTable2D.js +122 -0
- package/src/webgl/markerFeature.js +1 -1
- package/src/webgl/pixelmapFeature.frag +47 -0
- package/src/webgl/pixelmapFeature.js +172 -0
- package/src/webgl/pointFeature.js +1 -1
- package/src/webgl/quadFeature.js +32 -1
- package/src/webgl/webglRenderer.js +1 -0
package/src/trackFeature.js
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
25
|
+
* @property {number} [duration=null] Duration between start and end times.
|
|
26
26
|
* Ignored if both start and end times are specified.
|
|
27
|
-
* @property {
|
|
28
|
-
* specified, the track head is rendered as text. If `undefined` a marker
|
|
29
|
-
* used instead. If `null` or an empty string (`''`), neither a marker
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
640
|
-
* @returns {
|
|
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 {
|
|
658
|
-
* @returns {
|
|
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 {
|
|
676
|
-
* @returns {
|
|
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
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* @param {number} numberOfComponents For flat arrays, either 2 or 3.
|
|
337
|
-
* @returns {geoPosition|geoPosition[]|number[]} The transformed
|
|
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
package/src/ui/sliderWidget.js
CHANGED
|
@@ -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]),
|
package/src/util/clustering.js
CHANGED
|
@@ -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 {
|
|
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
|
package/src/util/common.js
CHANGED
|
@@ -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
|
|
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}
|
|
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
|
|
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,
|
|
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
|
|
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|
|
|
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
|
package/src/util/throttle.js
CHANGED
|
@@ -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)
|
package/src/webgl/index.js
CHANGED
|
@@ -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) {
|