@longline/aqua-ui 1.0.339 → 1.0.340
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/containers/Anchor/Anchor.d.ts +5 -0
- package/containers/Anchor/Anchor.js +20 -8
- package/containers/Dock/Dock.d.ts +5 -0
- package/containers/Dock/Dock.js +1 -1
- package/containers/Dock/Dockable.d.ts +5 -0
- package/containers/Dock/Dockable.js +20 -12
- package/containers/DragBar/DragBar.d.ts +5 -0
- package/containers/DragBar/DragBar.js +16 -5
- package/containers/Form/Field.d.ts +0 -3
- package/containers/Form/Field.js +3 -6
- package/containers/Form/Form.js +5 -36
- package/containers/Form/Validation.d.ts +1 -1
- package/containers/Form/Validation.js +6 -6
- package/containers/Form/context/FormContext.d.ts +1 -2
- package/containers/Form/context/useForm.d.ts +1 -1
- package/containers/Form/elements/BoxWrapper.js +2 -0
- package/containers/GlassPane/GlassPane.d.ts +7 -2
- package/containers/GlassPane/GlassPane.js +3 -3
- package/containers/InfoBox/InfoBox.d.ts +5 -0
- package/containers/InfoBox/InfoBox.js +1 -1
- package/containers/List/List.d.ts +5 -0
- package/containers/List/List.js +1 -1
- package/containers/List/ListCell.d.ts +5 -0
- package/containers/List/ListCell.js +1 -1
- package/containers/List/ListRow.d.ts +7 -2
- package/containers/List/ListRow.js +1 -1
- package/containers/Message/Error.d.ts +2 -0
- package/containers/Message/Error.js +1 -1
- package/containers/Message/Message.d.ts +5 -0
- package/containers/Message/Message.js +1 -1
- package/containers/Message/NoData.d.ts +2 -0
- package/containers/Message/NoData.js +1 -1
- package/containers/Message/NoFilteredData.d.ts +2 -0
- package/containers/Message/NoFilteredData.js +1 -1
- package/containers/Openable/Openable.d.ts +5 -0
- package/containers/Openable/Openable.js +8 -8
- package/containers/PublicRoute/PublicRoute.d.ts +9 -1
- package/containers/PublicRoute/PublicRoute.js +3 -7
- package/containers/Tabs/Pane.d.ts +5 -0
- package/containers/Tabs/Pane.js +3 -3
- package/containers/Tabs/Tabs.d.ts +5 -0
- package/containers/Tabs/Tabs.js +3 -3
- package/controls/Chip/Chip.d.ts +15 -3
- package/controls/Chip/Chip.js +7 -6
- package/controls/CircularProgress/CircularProgress.d.ts +11 -0
- package/controls/CircularProgress/CircularProgress.js +19 -11
- package/controls/Dropzone/Dropzone.d.ts +11 -1
- package/controls/Dropzone/Dropzone.js +18 -7
- package/controls/Fab/Fab.d.ts +14 -6
- package/controls/Fab/Fab.js +7 -20
- package/controls/Ghost/Ghost.js +3 -3
- package/controls/Gradient/Gradient.d.ts +5 -0
- package/controls/Gradient/Gradient.js +7 -4
- package/controls/Histogram/Histogram.d.ts +8 -2
- package/controls/Histogram/Histogram.js +9 -9
- package/controls/Histogram/HistogramBar.d.ts +2 -2
- package/controls/Icon/Icon.d.ts +10 -4
- package/controls/Icon/Icon.js +23 -6
- package/controls/Key/Key.d.ts +5 -0
- package/controls/Key/Key.js +2 -5
- package/controls/LinearChart/LinearChart.d.ts +9 -0
- package/controls/LinearChart/LinearChart.js +11 -6
- package/controls/ListButton/ListButton.d.ts +46 -3
- package/controls/ListButton/ListButton.js +70 -9
- package/controls/ListView/ColumnsManager/ColumnDraggable.js +11 -5
- package/controls/ListView/ColumnsManager/SourceColumns.js +1 -1
- package/controls/ListView/IListViewProps.d.ts +9 -2
- package/controls/ListView/ListView.js +13 -12
- package/controls/ListView/defaults.d.ts +3 -0
- package/controls/ListView/defaults.js +6 -0
- package/controls/ListView/elements/Body.d.ts +1 -1
- package/controls/ListView/elements/Body.js +23 -12
- package/controls/ListView/elements/Ghost.js +3 -2
- package/controls/ListView/elements/Header.js +3 -2
- package/controls/ListView/elements/HeaderCell.js +3 -3
- package/controls/ListView/elements/Table.js +16 -10
- package/controls/Mouse/Mouse.d.ts +6 -4
- package/controls/Mouse/Mouse.js +15 -8
- package/controls/PrimaryButton/PrimaryButton.d.ts +9 -3
- package/controls/PrimaryButton/PrimaryButton.js +5 -5
- package/controls/Progress/Progress.d.ts +9 -0
- package/controls/Progress/Progress.js +12 -8
- package/controls/SecondaryButton/SecondaryButton.d.ts +8 -3
- package/controls/SecondaryButton/SecondaryButton.js +1 -1
- package/controls/SpeechRecognizer/EditorRegistry.js +1 -2
- package/controls/SpeechRecognizer/SpeechRecognizer.d.ts +9 -1
- package/controls/SpeechRecognizer/SpeechRecognizer.js +16 -9
- package/controls/TabBar/TabBar.d.ts +5 -0
- package/controls/TabBar/TabBar.js +14 -6
- package/controls/TabBar/Underliner.js +1 -1
- package/controls/TertiaryButton/TertiaryButton.d.ts +9 -3
- package/controls/TertiaryButton/TertiaryButton.js +5 -3
- package/controls/ToggleButton/ToggleButton.d.ts +8 -2
- package/controls/ToggleButton/ToggleButton.js +1 -1
- package/controls/View/View.d.ts +5 -0
- package/controls/View/View.js +1 -1
- package/formatters/CountryFormatter/CountryFormatter.d.ts +3 -2
- package/formatters/CountryFormatter/CountryUtil.d.ts +3 -3
- package/formatters/DateTimeFormatter/DateTimeFormatter.d.ts +11 -10
- package/formatters/DateTimeFormatter/elements/Custom.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/DistanceDate.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/LongDate.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/LongDateTime.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/LongTime.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/Month.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/ShortDate.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/ShortDateTime.d.ts +1 -1
- package/formatters/DateTimeFormatter/elements/ShortTime.d.ts +1 -1
- package/formatters/DivisionFormatter/DivisionFormatter.d.ts +2 -2
- package/formatters/DivisionFormatter/DivisionFormatter.js +1 -1
- package/formatters/DivisionFormatter/DivisionUtil.d.ts +1 -1
- package/formatters/DivisionFormatter/DivisionUtil.js +5 -3
- package/formatters/FilesizeFormatter/FilesizeFormatter.d.ts +3 -3
- package/formatters/GIS/CoordinateFormatter.d.ts +2 -2
- package/formatters/GIS/LatitudeFormatter.d.ts +2 -2
- package/formatters/GIS/LongitudeFormatter.d.ts +2 -2
- package/formatters/HumanFormatter/HumanFormatter.d.ts +3 -3
- package/formatters/NumberFormatter/NumberFormatter.d.ts +3 -3
- package/formatters/PhoneFormatter/PhoneFormatter.d.ts +3 -3
- package/formatters/StringFormatter/StringFormatter.d.ts +3 -3
- package/formatters/StringFormatter/StringFormatter.js +1 -4
- package/helper/DMS.d.ts +1 -1
- package/helper/DMS.js +2 -2
- package/hooks/useOutsideClose/useOutsideClose.js +20 -11
- package/hooks/useSpeechAIRecorder/useSpeechAIRecorder.js +10 -7
- package/index.js +1 -0
- package/inputs/DateInput/Body.d.ts +2 -2
- package/inputs/DateInput/Body.js +11 -7
- package/inputs/DateInput/Calendar.d.ts +1 -1
- package/inputs/DateInput/Calendar.js +3 -5
- package/inputs/DateInput/DateInput.d.ts +11 -3
- package/inputs/DateInput/DateInput.js +11 -3
- package/inputs/DateInput/Day.d.ts +1 -1
- package/inputs/DateInput/InfiniteList.js +6 -3
- package/inputs/DateInput/Navbar.js +3 -2
- package/inputs/DateInput/NumericInput.js +3 -0
- package/inputs/DateInput/Selector.d.ts +1 -1
- package/inputs/DateInput/Selector.js +9 -6
- package/inputs/Dropdown/Body.d.ts +2 -2
- package/inputs/Dropdown/Column.d.ts +1 -1
- package/inputs/Dropdown/Dropdown.d.ts +5 -0
- package/inputs/Dropdown/Dropdown.js +36 -63
- package/inputs/Dropdown/Pill.js +1 -1
- package/inputs/Dropdown/Selection.js +1 -1
- package/inputs/Editor/Editor.d.ts +5 -0
- package/inputs/Editor/Editor.js +16 -6
- package/inputs/Editor/buttons/SpeechAIButton.js +2 -0
- package/inputs/Editor/buttons/TextAIButton.d.ts +0 -13
- package/inputs/Editor/buttons/TextAIButton.js +30 -14
- package/inputs/Editor/buttons/TextAIMenu.js +1 -1
- package/inputs/Editor/menu/MenuBar.d.ts +1 -1
- package/inputs/Editor/menu/MenuBar.js +1 -1
- package/inputs/Editor/menu/MenuButton.js +1 -1
- package/inputs/Input/Clear.js +1 -1
- package/inputs/Input/Input.d.ts +5 -0
- package/inputs/Input/Input.js +8 -6
- package/inputs/Input/InputWrapper.d.ts +2 -0
- package/inputs/Input/InputWrapper.js +1 -1
- package/inputs/Input/Reveal.js +1 -1
- package/inputs/MonthRange/Body.d.ts +1 -1
- package/inputs/MonthRange/Calendar.d.ts +2 -2
- package/inputs/MonthRange/Calendar.js +6 -9
- package/inputs/MonthRange/MonthRange.d.ts +7 -1
- package/inputs/MonthRange/MonthRange.js +14 -6
- package/inputs/MonthRange/Selector.d.ts +1 -1
- package/inputs/MonthRange/Selector.js +12 -11
- package/inputs/PhoneInput/PhoneInput.d.ts +5 -0
- package/inputs/PhoneInput/PhoneInput.js +2 -2
- package/inputs/Selector/Selector.d.ts +5 -0
- package/inputs/Selector/Selector.js +4 -1
- package/inputs/Slider/Slider.d.ts +75 -22
- package/inputs/Slider/Slider.js +104 -22
- package/inputs/Textarea/Textarea.d.ts +5 -5
- package/inputs/Textarea/Textarea.js +3 -2
- package/map/Map/Map.d.ts +2 -2
- package/map/Map/Map.js +20 -14
- package/map/PositionsManager/PositionBox.js +7 -3
- package/map/PositionsManager/PositionsManager.js +33 -13
- package/map/controls/CompassButton/CompassButton.js +1 -1
- package/map/controls/FullscreenButton/FullscreenButton.js +1 -1
- package/map/controls/Geocoder/Geocoder.js +28 -14
- package/map/controls/Geocoder/GeocoderApi.js +2 -0
- package/map/controls/Geocoder/GeocoderSelector.js +1 -1
- package/map/controls/Graticule/Graticule.js +1 -5
- package/map/controls/MapLoader/MapLoader.js +1 -1
- package/map/controls/ScaleControl/ScaleControl.js +1 -1
- package/map/controls/ZoomInButton/ZoomInButton.js +1 -1
- package/map/controls/ZoomOutButton/ZoomOutButton.d.ts +1 -1
- package/map/controls/ZoomOutButton/ZoomOutButton.js +2 -2
- package/map/controls/base/MapButton/MapButton.d.ts +8 -2
- package/map/controls/base/MapButton/MapButton.js +11 -2
- package/map/controls/base/MapControl/MapControl.d.ts +5 -0
- package/map/controls/base/MapControl/MapControl.js +10 -7
- package/map/layers/ClusterLayer/ClusterLayer.d.ts +1 -1
- package/map/layers/ClusterLayer/ClusterLayer.js +7 -3
- package/map/layers/HtmlMarkerLayer/HtmlMarkerLayer.js +8 -4
- package/map/layers/IdwBlendLayer/IdwBlendLayer.js +9 -4
- package/map/layers/IdwLayer/IdwLayer.d.ts +2 -1
- package/map/layers/IdwLayer/IdwLayer.js +271 -215
- package/map/layers/InterpolationLayer/ContoursFragmentShader.d.ts +1 -1
- package/map/layers/InterpolationLayer/ContoursFragmentShader.js +1 -1
- package/map/layers/InterpolationLayer/InterpolationLayer.d.ts +4 -3
- package/map/layers/InterpolationLayer/InterpolationLayer.js +362 -275
- package/map/layers/ParticlesLayer/ParticlesLayer.d.ts +8 -7
- package/map/layers/ParticlesLayer/ParticlesLayer.js +528 -404
- package/map/markers/ClusterMarker/ClusterMarker.d.ts +6 -1
- package/map/markers/ClusterMarker/ClusterMarker.js +15 -6
- package/map/markers/RiskMarker/RiskMarker.d.ts +5 -1
- package/map/markers/RiskMarker/RiskMarker.js +4 -4
- package/modules/CountryDropdown/CountryDropdown.js +10 -1
- package/modules/Filter/Filter.d.ts +5 -0
- package/modules/Filter/Filter.js +10 -6
- package/modules/Globe/Globe.d.ts +5 -0
- package/modules/Globe/Globe.js +4 -4
- package/modules/MainMenu/Item.d.ts +9 -2
- package/modules/MainMenu/Item.js +8 -5
- package/modules/MainMenu/MainMenu.d.ts +5 -0
- package/modules/MainMenu/MainMenu.js +1 -1
- package/modules/ParticleGlobe/GL.d.ts +1 -1
- package/modules/ParticleGlobe/ParticleGlobe.d.ts +5 -0
- package/modules/ParticleGlobe/ParticleGlobe.js +69 -40
- package/modules/Public/Public.d.ts +5 -0
- package/modules/Public/Public.js +3 -3
- package/package.json +1 -1
- package/services/Auth/Auth.js +13 -7
- package/services/Auth/AuthContext.js +9 -1
- package/services/Dialog/Dialog.d.ts +7 -2
- package/services/Dialog/Dialog.js +7 -6
- package/services/Dialog/DialogWindow.d.ts +3 -1
- package/services/Dialog/DialogWindow.js +1 -1
- package/services/Dialog/XhrDialog.d.ts +1 -1
- package/services/Toast/Toast.js +5 -3
- package/services/Toast/ToastContainer.js +3 -1
- package/services/Toast/ToastContext.d.ts +1 -1
- package/services/Toast/ToastProvider.js +2 -0
- package/map/layers/HtmlMarkerLayer/HtmlMarkerLayer copy.d.ts +0 -35
- package/map/layers/HtmlMarkerLayer/HtmlMarkerLayer copy.js +0 -176
- package/modules/Root/Content.d.ts +0 -16
- package/modules/Root/Content.js +0 -25
- package/modules/Root/Overlay.d.ts +0 -23
- package/modules/Root/Overlay.js +0 -33
- package/modules/Root/Root.d.ts +0 -10
- package/modules/Root/Root.js +0 -46
- package/modules/Root/Shader.d.ts +0 -15
- package/modules/Root/Shader.js +0 -24
- package/modules/Root/Sidebar.d.ts +0 -13
- package/modules/Root/Sidebar.js +0 -24
- package/modules/Root/index.d.ts +0 -1
- package/modules/Root/index.js +0 -1
- package/modules/Root/stories/SampleContent.d.ts +0 -7
- package/modules/Root/stories/SampleContent.js +0 -44
|
@@ -43,415 +43,544 @@ import { PositionComputeFragmentShader } from './PositionComputeFragmentShader';
|
|
|
43
43
|
import { RgbColor } from '../../../helper/RgbColor';
|
|
44
44
|
var TEXTURE_WIDTH = 1024;
|
|
45
45
|
var TEXTURE_HEIGHT = 1024;
|
|
46
|
+
// Default prop values, referenced both by the ParticlesLayerBase fallbacks and
|
|
47
|
+
// the ParticlesLayer wrapper below.
|
|
48
|
+
var DEFAULT_PARTICLES = 80;
|
|
49
|
+
var DEFAULT_DENSITY = 40;
|
|
50
|
+
var DEFAULT_DELAY = 0;
|
|
51
|
+
var DEFAULT_POINT_SIZE = 1.0;
|
|
52
|
+
var DEFAULT_MIN_ZOOM = 0;
|
|
53
|
+
var DEFAULT_MAX_ZOOM = 99;
|
|
54
|
+
var DEFAULT_MIN_SPEED = 0.02;
|
|
55
|
+
var DEFAULT_MAX_SPEED = 0.15;
|
|
56
|
+
// Accepted ranges, shared by the component clamps and the story sliders.
|
|
57
|
+
var MIN_PARTICLES = 1;
|
|
58
|
+
var MAX_PARTICLES = 200;
|
|
59
|
+
var MIN_DENSITY = 2; // >= 2 also avoids the density-1 divide-by-zero in the grid.
|
|
60
|
+
var MAX_DENSITY = 100;
|
|
61
|
+
var MAX_DELAY = 10;
|
|
62
|
+
var MIN_POINT_SIZE = 1;
|
|
63
|
+
var MAX_POINT_SIZE = 10;
|
|
64
|
+
var MIN_SPEED = 0;
|
|
65
|
+
var MAX_SPEED = 1;
|
|
66
|
+
var DEFAULT_GRADIENT_STOPS = [
|
|
67
|
+
{ pos: 0.0, color: '#ffffffff' },
|
|
68
|
+
{ pos: 0.25, color: '#5c5cffff' },
|
|
69
|
+
{ pos: 0.5, color: '#5c5cff00' },
|
|
70
|
+
{ pos: 1.0, color: '#5c5cff00' }, // transparent blue
|
|
71
|
+
];
|
|
72
|
+
//
|
|
73
|
+
// Convert a hex color (e.g. #ff0022) to an [r,g,b,a] array,
|
|
74
|
+
// where r,g,b,a are in the 0.0-1.0 range.
|
|
75
|
+
//
|
|
76
|
+
var colorToRGBA = function (color) {
|
|
77
|
+
var rgb = RgbColor.FromString(color);
|
|
78
|
+
return [rgb.red / 255.0, rgb.green / 255.0, rgb.blue / 255.0, rgb.alpha];
|
|
79
|
+
};
|
|
80
|
+
//
|
|
81
|
+
// Coerce a control value (which may be "" while typing, undefined, or invalid)
|
|
82
|
+
// to a number, or NaN when it is empty/invalid. Note Number("") is 0, so empty
|
|
83
|
+
// strings are handled explicitly rather than silently becoming zero.
|
|
84
|
+
//
|
|
85
|
+
var toNumber = function (value) {
|
|
86
|
+
if (value === '' || value === null || value === undefined)
|
|
87
|
+
return NaN;
|
|
88
|
+
var n = Number(value);
|
|
89
|
+
return Number.isFinite(n) ? n : NaN;
|
|
90
|
+
};
|
|
91
|
+
//
|
|
92
|
+
// Clamp to an integer in [min, max], falling back to `fallback` on empty/invalid
|
|
93
|
+
// input. Guards buffer/texture sizing and the animation modulo against
|
|
94
|
+
// NaN/degenerate values.
|
|
95
|
+
//
|
|
96
|
+
var clampInt = function (value, fallback, min, max) {
|
|
97
|
+
var n = toNumber(value);
|
|
98
|
+
if (Number.isNaN(n))
|
|
99
|
+
return fallback;
|
|
100
|
+
return Math.max(min, Math.min(max, Math.floor(n)));
|
|
101
|
+
};
|
|
102
|
+
//
|
|
103
|
+
// Clamp to a (possibly fractional) number in [min, max], falling back to
|
|
104
|
+
// `fallback` on empty/invalid input.
|
|
105
|
+
//
|
|
106
|
+
var clampFloat = function (value, fallback, min, max) {
|
|
107
|
+
var n = toNumber(value);
|
|
108
|
+
if (Number.isNaN(n))
|
|
109
|
+
return fallback;
|
|
110
|
+
return Math.max(min, Math.min(max, n));
|
|
111
|
+
};
|
|
112
|
+
//
|
|
113
|
+
// Convert an IPoint array to triangles for one field (u or v). Each triangle
|
|
114
|
+
// gets properties a,b,c with the field value at each vertex. Returns the value
|
|
115
|
+
// range and a flat [x,y,value, ...] coordinate array.
|
|
116
|
+
//
|
|
117
|
+
var buildGeometry = function (data, field) {
|
|
118
|
+
var points = featureCollection((data !== null && data !== void 0 ? data : [])
|
|
119
|
+
.filter(function (dp) { return !isNaN(dp[field]); }) // Filter out any NaN values.
|
|
120
|
+
.map(function (dp) { return point([dp.longitude, dp.latitude], { 'v': dp[field] }); }));
|
|
121
|
+
var polys = tin(points, 'v');
|
|
122
|
+
// Find min and max values in GeoJSON:
|
|
123
|
+
var minValue = Infinity;
|
|
124
|
+
var maxValue = -Infinity;
|
|
125
|
+
var len = polys.features.length;
|
|
126
|
+
while (len--) {
|
|
127
|
+
var properties = polys.features[len].properties;
|
|
128
|
+
// Each triangle carries three vertex values (a, b, c). A data point may
|
|
129
|
+
// only ever appear as b or c, so scan all three to find the true range;
|
|
130
|
+
// otherwise out-of-range vertices normalize outside 0..1 and get clamped
|
|
131
|
+
// when written to the byte texture.
|
|
132
|
+
for (var _i = 0, _a = ['a', 'b', 'c']; _i < _a.length; _i++) {
|
|
133
|
+
var key = _a[_i];
|
|
134
|
+
var value = properties[key];
|
|
135
|
+
minValue = value < minValue ? value : minValue;
|
|
136
|
+
maxValue = value > maxValue ? value : maxValue;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Convert dataset to triangle geometry.
|
|
140
|
+
// Result is a list of v1,v2,v3, v1,v2,v3, ...
|
|
141
|
+
// where each vector has (x,y,value).
|
|
142
|
+
var coords = [];
|
|
143
|
+
var LAT = 1;
|
|
144
|
+
var LON = 0;
|
|
145
|
+
// Avoid a 0/0 = NaN normalization when all values are equal.
|
|
146
|
+
var deltaValue = (maxValue - minValue) || 1;
|
|
147
|
+
polys.features.map(function (feature) {
|
|
148
|
+
var coord = MercatorCoordinate.fromLngLat({ lng: feature.geometry.coordinates[0][0][LON], lat: feature.geometry.coordinates[0][0][LAT] });
|
|
149
|
+
coords.push(coord.x, coord.y, (feature.properties['a'] - minValue) / deltaValue);
|
|
150
|
+
coord = MercatorCoordinate.fromLngLat({ lng: feature.geometry.coordinates[0][1][LON], lat: feature.geometry.coordinates[0][1][LAT] });
|
|
151
|
+
coords.push(coord.x, coord.y, (feature.properties['b'] - minValue) / deltaValue);
|
|
152
|
+
coord = MercatorCoordinate.fromLngLat({ lng: feature.geometry.coordinates[0][2][LON], lat: feature.geometry.coordinates[0][2][LAT] });
|
|
153
|
+
coords.push(coord.x, coord.y, (feature.properties['c'] - minValue) / deltaValue);
|
|
154
|
+
});
|
|
155
|
+
return [minValue, maxValue, coords];
|
|
156
|
+
};
|
|
157
|
+
//
|
|
158
|
+
// Check if two matrices are equal.
|
|
159
|
+
//
|
|
160
|
+
var matricesEqual = function (a, b) {
|
|
161
|
+
if (!a || !b)
|
|
162
|
+
return false;
|
|
163
|
+
for (var i = 0; i < 16; i++) {
|
|
164
|
+
if (a[i] !== b[i])
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
};
|
|
46
169
|
var ParticlesLayerBase = function (props) {
|
|
47
170
|
var map = useMap();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
var numTrianglesV = React.useRef(null);
|
|
55
|
-
var minU = React.useRef(0);
|
|
56
|
-
var maxU = React.useRef(0);
|
|
57
|
-
var minV = React.useRef(0);
|
|
58
|
-
var maxV = React.useRef(0);
|
|
59
|
-
// Combined UV texture: U in R channel, V in G channel, alpha indicates valid data
|
|
60
|
-
var textureUV = React.useRef(null);
|
|
61
|
-
var fboUV = React.useRef(null);
|
|
62
|
-
// Position texture: stores pre-computed particle positions (X in RG, Y in BA)
|
|
63
|
-
var positionProgram = React.useRef(null);
|
|
64
|
-
var texturePosition = React.useRef(null);
|
|
65
|
-
var fboPosition = React.useRef(null);
|
|
66
|
-
var bufferQuad = React.useRef(null);
|
|
67
|
-
// Dynamic position texture dimensions (computed based on density * density * particles)
|
|
68
|
-
var posTexWidth = React.useRef(0);
|
|
69
|
-
var posTexHeight = React.useRef(0);
|
|
171
|
+
// The custom-layer callbacks are captured by Mapbox at add-time, so render
|
|
172
|
+
// reads live prop values through this ref rather than a stale closure.
|
|
173
|
+
var propsRef = React.useRef(props);
|
|
174
|
+
propsRef.current = props;
|
|
175
|
+
// Animation state is a component-level (not per-generation) concern: it tracks
|
|
176
|
+
// time, and render reads the current frame each draw.
|
|
70
177
|
var frame = React.useRef(0);
|
|
71
178
|
var skip = React.useRef(0);
|
|
72
|
-
// requestAnimationFrame ID:
|
|
73
179
|
var animation = React.useRef(null);
|
|
74
|
-
//
|
|
75
|
-
var lastMatrix = React.useRef(null);
|
|
76
|
-
// Current time is used to force component rerender when props change:
|
|
77
|
-
var _a = React.useState(0), time = _a[0], setTime = _a[1];
|
|
78
|
-
// Force component rerender when props change:
|
|
180
|
+
// Animation loop: advance the particle frame (respecting delay) and repaint.
|
|
79
181
|
React.useEffect(function () {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
182
|
+
var draw = function () {
|
|
183
|
+
var _a;
|
|
184
|
+
var p = propsRef.current;
|
|
185
|
+
var particles = clampInt(p.particles, DEFAULT_PARTICLES, MIN_PARTICLES, MAX_PARTICLES);
|
|
186
|
+
var delay = clampInt(p.delay, DEFAULT_DELAY, 0, MAX_DELAY);
|
|
187
|
+
if (!Number.isFinite(frame.current))
|
|
188
|
+
frame.current = 0; // Recover from any bad state.
|
|
189
|
+
skip.current++;
|
|
190
|
+
if (skip.current > delay) {
|
|
191
|
+
skip.current = 0;
|
|
192
|
+
frame.current = (frame.current + 1) % particles;
|
|
193
|
+
(_a = map.current) === null || _a === void 0 ? void 0 : _a.triggerRepaint();
|
|
194
|
+
}
|
|
195
|
+
animation.current = window.requestAnimationFrame(draw);
|
|
196
|
+
};
|
|
94
197
|
animation.current = window.requestAnimationFrame(draw);
|
|
95
|
-
};
|
|
96
|
-
React.useEffect(function () {
|
|
97
198
|
return function () {
|
|
98
|
-
|
|
199
|
+
if (animation.current !== null)
|
|
200
|
+
window.cancelAnimationFrame(animation.current);
|
|
99
201
|
};
|
|
100
|
-
}, []);
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
var
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
var
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
var
|
|
127
|
-
var
|
|
128
|
-
var
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
var
|
|
138
|
-
var
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
gl
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
var
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
for (var y = 0; y < props.density; y++) {
|
|
259
|
-
for (var x = 0; x < props.density; x++) {
|
|
260
|
-
var offset = Math.floor(Math.random() * props.particles);
|
|
261
|
-
// Each point has a number of particles:
|
|
262
|
-
for (var i = 0; i < props.particles; i++) {
|
|
263
|
-
coords.push(x * 1.98 / (props.density - 1) - 0.99);
|
|
264
|
-
coords.push(y * 1.98 / (props.density - 1) - 0.99);
|
|
265
|
-
// Each point has an instance index
|
|
266
|
-
coords.push(i);
|
|
267
|
-
// Each point has a frame offset.
|
|
268
|
-
coords.push(offset);
|
|
202
|
+
}, [map]);
|
|
203
|
+
// Triangulation only depends on data; keep it memoized so tweaking density,
|
|
204
|
+
// particle count or speed does not re-run the (expensive) tin() pass.
|
|
205
|
+
var geometry = React.useMemo(function () { return ({
|
|
206
|
+
u: buildGeometry(props.data, 'u'),
|
|
207
|
+
v: buildGeometry(props.data, 'v'),
|
|
208
|
+
}); }, [props.data]);
|
|
209
|
+
// Build a fresh custom layer — with its own private WebGL resource holder —
|
|
210
|
+
// whenever an input that requires re-initialising GL state changes (geometry,
|
|
211
|
+
// density, particle count, or the speed remapping baked into the position
|
|
212
|
+
// texture). Each generation owns its resources and frees only those in its own
|
|
213
|
+
// onRemove, so the overlapping add/remove during a react-map-gl remount never
|
|
214
|
+
// clobbers the live generation.
|
|
215
|
+
var layer = React.useMemo(function () {
|
|
216
|
+
// Unique id per generation so the old and new layers coexist cleanly during
|
|
217
|
+
// the remount (old removeLayer + new addLayer both run).
|
|
218
|
+
var id = 'particles-' + Math.random().toString(36).slice(2);
|
|
219
|
+
// Private per-generation GL resources.
|
|
220
|
+
var uvProgram = null;
|
|
221
|
+
var particlesProgram = null;
|
|
222
|
+
var positionProgram = null;
|
|
223
|
+
var bufferU = null;
|
|
224
|
+
var bufferV = null;
|
|
225
|
+
var bufferScreen = null;
|
|
226
|
+
var bufferQuad = null;
|
|
227
|
+
var textureUV = null;
|
|
228
|
+
var fboUV = null;
|
|
229
|
+
var texturePosition = null;
|
|
230
|
+
var fboPosition = null;
|
|
231
|
+
var numTrianglesU = 0;
|
|
232
|
+
var numTrianglesV = 0;
|
|
233
|
+
var minU = 0;
|
|
234
|
+
var maxU = 0;
|
|
235
|
+
var minV = 0;
|
|
236
|
+
var maxV = 0;
|
|
237
|
+
var posTexWidth = 0;
|
|
238
|
+
var posTexHeight = 0;
|
|
239
|
+
var lastMatrix = null;
|
|
240
|
+
var removed = false;
|
|
241
|
+
// Grid parameters are baked into the buffers/textures below, so they are
|
|
242
|
+
// fixed for this generation (a change rebuilds a new generation). Clamped
|
|
243
|
+
// so a transient empty/invalid value never produces degenerate GL state.
|
|
244
|
+
var particles = clampInt(props.particles, DEFAULT_PARTICLES, MIN_PARTICLES, MAX_PARTICLES);
|
|
245
|
+
var density = clampInt(props.density, DEFAULT_DENSITY, MIN_DENSITY, MAX_DENSITY);
|
|
246
|
+
var createUVProgram = function (gl) {
|
|
247
|
+
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
248
|
+
gl.shaderSource(vertexShader, UVVertexShader);
|
|
249
|
+
gl.compileShader(vertexShader);
|
|
250
|
+
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
251
|
+
gl.shaderSource(fragmentShader, UVFragmentShader);
|
|
252
|
+
gl.compileShader(fragmentShader);
|
|
253
|
+
uvProgram = gl.createProgram();
|
|
254
|
+
gl.attachShader(uvProgram, vertexShader);
|
|
255
|
+
gl.attachShader(uvProgram, fragmentShader);
|
|
256
|
+
gl.linkProgram(uvProgram);
|
|
257
|
+
// Shaders are linked into the program now; flag them for deletion.
|
|
258
|
+
gl.deleteShader(vertexShader);
|
|
259
|
+
gl.deleteShader(fragmentShader);
|
|
260
|
+
};
|
|
261
|
+
var createParticlesProgram = function (gl) {
|
|
262
|
+
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
263
|
+
gl.shaderSource(vertexShader, ParticlesVertexShader);
|
|
264
|
+
gl.compileShader(vertexShader);
|
|
265
|
+
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
266
|
+
gl.shaderSource(fragmentShader, ParticlesFragmentShader);
|
|
267
|
+
gl.compileShader(fragmentShader);
|
|
268
|
+
particlesProgram = gl.createProgram();
|
|
269
|
+
gl.attachShader(particlesProgram, vertexShader);
|
|
270
|
+
gl.attachShader(particlesProgram, fragmentShader);
|
|
271
|
+
gl.linkProgram(particlesProgram);
|
|
272
|
+
// Shaders are linked into the program now; flag them for deletion.
|
|
273
|
+
gl.deleteShader(vertexShader);
|
|
274
|
+
gl.deleteShader(fragmentShader);
|
|
275
|
+
};
|
|
276
|
+
var createPositionComputeProgram = function (gl) {
|
|
277
|
+
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
278
|
+
gl.shaderSource(vertexShader, PositionComputeVertexShader);
|
|
279
|
+
gl.compileShader(vertexShader);
|
|
280
|
+
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
281
|
+
gl.shaderSource(fragmentShader, PositionComputeFragmentShader);
|
|
282
|
+
gl.compileShader(fragmentShader);
|
|
283
|
+
positionProgram = gl.createProgram();
|
|
284
|
+
gl.attachShader(positionProgram, vertexShader);
|
|
285
|
+
gl.attachShader(positionProgram, fragmentShader);
|
|
286
|
+
gl.linkProgram(positionProgram);
|
|
287
|
+
// Shaders are linked into the program now; flag them for deletion.
|
|
288
|
+
gl.deleteShader(vertexShader);
|
|
289
|
+
gl.deleteShader(fragmentShader);
|
|
290
|
+
};
|
|
291
|
+
var createPositionTexture = function (gl) {
|
|
292
|
+
// Compute texture dimensions to fit all particles.
|
|
293
|
+
// Total particles = density * density * particles
|
|
294
|
+
var totalParticles = density * density * particles;
|
|
295
|
+
// Find suitable texture dimensions (width should be power of 2).
|
|
296
|
+
var width = 256;
|
|
297
|
+
while (width * width < totalParticles) {
|
|
298
|
+
width *= 2;
|
|
299
|
+
}
|
|
300
|
+
var height = Math.ceil(totalParticles / width);
|
|
301
|
+
posTexWidth = width;
|
|
302
|
+
posTexHeight = height;
|
|
303
|
+
var texture = gl.createTexture();
|
|
304
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
305
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
306
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
307
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
308
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
309
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
310
|
+
return texture;
|
|
311
|
+
};
|
|
312
|
+
var createQuadBuffer = function (gl) {
|
|
313
|
+
// Full-screen quad (two triangles covering clip space)
|
|
314
|
+
bufferQuad = gl.createBuffer();
|
|
315
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferQuad);
|
|
316
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
317
|
+
-1, -1,
|
|
318
|
+
1, -1,
|
|
319
|
+
-1, 1,
|
|
320
|
+
-1, 1,
|
|
321
|
+
1, -1,
|
|
322
|
+
1, 1
|
|
323
|
+
]), gl.STATIC_DRAW);
|
|
324
|
+
};
|
|
325
|
+
var createBufferU = function (gl) {
|
|
326
|
+
var _a = geometry.u, min = _a[0], max = _a[1], geo = _a[2];
|
|
327
|
+
minU = min;
|
|
328
|
+
maxU = max;
|
|
329
|
+
numTrianglesU = geo.length / 9;
|
|
330
|
+
bufferU = gl.createBuffer();
|
|
331
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferU);
|
|
332
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(geo), gl.STATIC_DRAW);
|
|
333
|
+
};
|
|
334
|
+
var createBufferV = function (gl) {
|
|
335
|
+
var _a = geometry.v, min = _a[0], max = _a[1], geo = _a[2];
|
|
336
|
+
minV = min;
|
|
337
|
+
maxV = max;
|
|
338
|
+
numTrianglesV = geo.length / 9;
|
|
339
|
+
bufferV = gl.createBuffer();
|
|
340
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferV);
|
|
341
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(geo), gl.STATIC_DRAW);
|
|
342
|
+
};
|
|
343
|
+
var createBufferScreen = function (gl) {
|
|
344
|
+
bufferScreen = gl.createBuffer();
|
|
345
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferScreen);
|
|
346
|
+
// Each point has a screen coordinate in range [-1..1]
|
|
347
|
+
var coords = [];
|
|
348
|
+
for (var y = 0; y < density; y++) {
|
|
349
|
+
for (var x = 0; x < density; x++) {
|
|
350
|
+
var offset = Math.floor(Math.random() * particles);
|
|
351
|
+
// Each point has a number of particles:
|
|
352
|
+
for (var i = 0; i < particles; i++) {
|
|
353
|
+
coords.push(x * 1.98 / (density - 1) - 0.99);
|
|
354
|
+
coords.push(y * 1.98 / (density - 1) - 0.99);
|
|
355
|
+
// Each point has an instance index
|
|
356
|
+
coords.push(i);
|
|
357
|
+
// Each point has a frame offset.
|
|
358
|
+
coords.push(offset);
|
|
359
|
+
}
|
|
269
360
|
}
|
|
270
361
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
362
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), gl.STATIC_DRAW);
|
|
363
|
+
};
|
|
364
|
+
var createTexture = function (gl) {
|
|
365
|
+
var texture = gl.createTexture();
|
|
366
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
367
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
368
|
+
// Set filtering to NEAREST so there's no interpolation:
|
|
369
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
370
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
371
|
+
return texture;
|
|
372
|
+
};
|
|
373
|
+
var createFrameBuffer = function (gl, texture) {
|
|
374
|
+
var fbo = gl.createFramebuffer();
|
|
375
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
376
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
377
|
+
return fbo;
|
|
378
|
+
};
|
|
379
|
+
var onAdd = function (mbMap, gl) {
|
|
380
|
+
createBufferU(gl);
|
|
381
|
+
createBufferV(gl);
|
|
382
|
+
createBufferScreen(gl);
|
|
383
|
+
createQuadBuffer(gl);
|
|
384
|
+
createUVProgram(gl);
|
|
385
|
+
createParticlesProgram(gl);
|
|
386
|
+
createPositionComputeProgram(gl);
|
|
387
|
+
// Single combined texture for both U and V (U in R, V in G)
|
|
388
|
+
textureUV = createTexture(gl);
|
|
389
|
+
fboUV = createFrameBuffer(gl, textureUV);
|
|
390
|
+
// Position texture for pre-computed particle positions
|
|
391
|
+
texturePosition = createPositionTexture(gl);
|
|
392
|
+
fboPosition = createFrameBuffer(gl, texturePosition);
|
|
393
|
+
// The map is idle after a prop-driven remount, so force a repaint to draw
|
|
394
|
+
// the freshly-added layer (the animation loop will keep it going).
|
|
395
|
+
mbMap.triggerRepaint();
|
|
396
|
+
};
|
|
397
|
+
var renderSpeedBuffer = function (gl, matrix, buffer, numTriangles) {
|
|
398
|
+
var program = uvProgram;
|
|
399
|
+
gl.useProgram(program);
|
|
400
|
+
// Pass a matrix uniform in:
|
|
401
|
+
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'u_matrix'), false, matrix);
|
|
402
|
+
// Vertices:
|
|
403
|
+
var aPos = gl.getAttribLocation(program, 'a_pos');
|
|
404
|
+
var aValue = gl.getAttribLocation(program, 'a_value');
|
|
405
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
406
|
+
gl.enableVertexAttribArray(aPos);
|
|
407
|
+
gl.enableVertexAttribArray(aValue);
|
|
408
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 12, 0);
|
|
409
|
+
gl.vertexAttribPointer(aValue, 1, gl.FLOAT, false, 12, 8);
|
|
410
|
+
gl.enable(gl.BLEND);
|
|
411
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
412
|
+
gl.drawArrays(gl.TRIANGLES, 0, numTriangles * 3);
|
|
413
|
+
// Attribute-array enable state is global in WebGL1; disable what we
|
|
414
|
+
// enabled so a later draw with fewer attributes can't reference a
|
|
415
|
+
// stale (freed) buffer left bound to a still-enabled index.
|
|
416
|
+
gl.disableVertexAttribArray(aPos);
|
|
417
|
+
gl.disableVertexAttribArray(aValue);
|
|
418
|
+
};
|
|
419
|
+
//
|
|
420
|
+
// Render particle positions to the position texture.
|
|
421
|
+
// This moves the expensive trace loop from the particle vertex shader
|
|
422
|
+
// to a one-time-per-view-change fragment shader pass.
|
|
423
|
+
//
|
|
424
|
+
var renderPositionTexture = function (gl) {
|
|
425
|
+
var p = propsRef.current;
|
|
426
|
+
var program = positionProgram;
|
|
427
|
+
gl.useProgram(program);
|
|
428
|
+
// Bind position framebuffer
|
|
429
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fboPosition);
|
|
430
|
+
gl.viewport(0, 0, posTexWidth, posTexHeight);
|
|
431
|
+
gl.clearColor(0, 0, 0, 0);
|
|
432
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
433
|
+
// Disable blending for position computation
|
|
434
|
+
gl.disable(gl.BLEND);
|
|
435
|
+
// UV texture (already rendered)
|
|
436
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
437
|
+
gl.bindTexture(gl.TEXTURE_2D, textureUV);
|
|
438
|
+
gl.uniform1i(gl.getUniformLocation(program, 'uvTexture'), 0);
|
|
439
|
+
// UV range uniforms
|
|
440
|
+
gl.uniform1f(gl.getUniformLocation(program, 'minU'), minU);
|
|
441
|
+
gl.uniform1f(gl.getUniformLocation(program, 'maxU'), maxU);
|
|
442
|
+
gl.uniform1f(gl.getUniformLocation(program, 'minV'), minV);
|
|
443
|
+
gl.uniform1f(gl.getUniformLocation(program, 'maxV'), maxV);
|
|
444
|
+
// Grid parameters
|
|
445
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_density'), density);
|
|
446
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_particles'), particles);
|
|
447
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_texWidth'), posTexWidth);
|
|
448
|
+
// Velocity magnitude remapping parameters
|
|
449
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_minVisMag'), clampFloat(p.minSpeed, DEFAULT_MIN_SPEED, MIN_SPEED, MAX_SPEED));
|
|
450
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_maxVisMag'), clampFloat(p.maxSpeed, DEFAULT_MAX_SPEED, MIN_SPEED, MAX_SPEED));
|
|
451
|
+
// Render full-screen quad
|
|
452
|
+
var aPos = gl.getAttribLocation(program, 'a_pos');
|
|
453
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferQuad);
|
|
454
|
+
gl.enableVertexAttribArray(aPos);
|
|
455
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
|
|
456
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
457
|
+
gl.disableVertexAttribArray(aPos);
|
|
458
|
+
};
|
|
459
|
+
var renderParticles = function (gl, matrix) {
|
|
460
|
+
var _a;
|
|
461
|
+
var p = propsRef.current;
|
|
462
|
+
var program = particlesProgram;
|
|
463
|
+
gl.useProgram(program);
|
|
464
|
+
// Matrix:
|
|
465
|
+
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'u_matrix'), false, matrix);
|
|
466
|
+
// Stops - fill up to 12 stops by using values > 1 for filler stops.
|
|
467
|
+
// e.g. [0.0, 0.5, 1.0, 2.0....] means that only the first 3 stops are used.
|
|
468
|
+
var gradientStops = (_a = p.gradientStops) !== null && _a !== void 0 ? _a : DEFAULT_GRADIENT_STOPS;
|
|
469
|
+
var stops = __spreadArray([], gradientStops.map(function (s) { return s.pos; }), true);
|
|
470
|
+
while (stops.length < 12)
|
|
471
|
+
stops.push(2.0);
|
|
472
|
+
gl.uniform1fv(gl.getUniformLocation(program, 'u_gradientStops'), new Float32Array(stops));
|
|
473
|
+
var colors = gradientStops.map(function (s) { return colorToRGBA(s.color); }).flat();
|
|
474
|
+
gl.uniform4fv(gl.getUniformLocation(program, 'u_gradientColors'), new Float32Array(colors));
|
|
475
|
+
// Current animation frame:
|
|
476
|
+
gl.uniform1i(gl.getUniformLocation(program, 'u_frame'), Math.floor(frame.current));
|
|
477
|
+
// Number of point instances - this is the length of each curve:
|
|
478
|
+
gl.uniform1i(gl.getUniformLocation(program, 'u_num_instances'), particles);
|
|
479
|
+
// Size of points to be drawn (in pixels).
|
|
480
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_point_size'), clampFloat(p.pointSize, DEFAULT_POINT_SIZE, MIN_POINT_SIZE, MAX_POINT_SIZE));
|
|
481
|
+
// Position texture (pre-computed particle positions):
|
|
482
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
483
|
+
gl.bindTexture(gl.TEXTURE_2D, texturePosition);
|
|
484
|
+
gl.uniform1i(gl.getUniformLocation(program, 'positionTexture'), 0);
|
|
485
|
+
// Position texture dimensions and grid parameters for coordinate lookup:
|
|
486
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_posTexWidth'), posTexWidth);
|
|
487
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_posTexHeight'), posTexHeight);
|
|
488
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_density'), density);
|
|
489
|
+
// Vertices:
|
|
490
|
+
var aPos = gl.getAttribLocation(program, 'a_pos'); // on-screen position [-1..1]
|
|
491
|
+
var aIdx = gl.getAttribLocation(program, 'a_idx'); // particle index
|
|
492
|
+
var aOffset = gl.getAttribLocation(program, 'a_offset'); // animation offset (into index)
|
|
493
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, bufferScreen);
|
|
494
|
+
gl.enableVertexAttribArray(aPos);
|
|
495
|
+
gl.enableVertexAttribArray(aIdx);
|
|
496
|
+
gl.enableVertexAttribArray(aOffset);
|
|
497
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
498
|
+
gl.vertexAttribPointer(aIdx, 1, gl.FLOAT, false, 16, 8);
|
|
499
|
+
gl.vertexAttribPointer(aOffset, 1, gl.FLOAT, false, 16, 12);
|
|
500
|
+
gl.enable(gl.BLEND);
|
|
501
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
502
|
+
gl.drawArrays(gl.POINTS, 0, density * density * particles);
|
|
503
|
+
gl.disableVertexAttribArray(aPos);
|
|
504
|
+
gl.disableVertexAttribArray(aIdx);
|
|
505
|
+
gl.disableVertexAttribArray(aOffset);
|
|
506
|
+
};
|
|
507
|
+
var render = function (gl, matrix) {
|
|
508
|
+
var _a, _b;
|
|
509
|
+
if (removed)
|
|
510
|
+
return; // Resources freed; ignore any trailing frame.
|
|
511
|
+
var m = map.current;
|
|
512
|
+
if (!m)
|
|
513
|
+
return;
|
|
514
|
+
var p = propsRef.current;
|
|
515
|
+
var zoom = m.getZoom();
|
|
516
|
+
if (zoom < ((_a = p.minZoom) !== null && _a !== void 0 ? _a : DEFAULT_MIN_ZOOM))
|
|
517
|
+
return;
|
|
518
|
+
if (zoom > ((_b = p.maxZoom) !== null && _b !== void 0 ? _b : DEFAULT_MAX_ZOOM))
|
|
519
|
+
return;
|
|
520
|
+
var width = m.getContainer().clientWidth;
|
|
521
|
+
var height = m.getContainer().clientHeight;
|
|
522
|
+
// Only re-render UV textures when the matrix changes (i.e., when the map
|
|
523
|
+
// view changes due to panning or zooming). This is a significant
|
|
524
|
+
// performance optimization since UV texture rendering involves expensive
|
|
525
|
+
// draw calls.
|
|
526
|
+
var matrixChanged = !matricesEqual(matrix, lastMatrix);
|
|
527
|
+
if (matrixChanged) {
|
|
528
|
+
lastMatrix = __spreadArray([], matrix, true);
|
|
529
|
+
gl.useProgram(uvProgram);
|
|
530
|
+
// Render to combined UV texture (U in R channel, V in G channel)
|
|
531
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fboUV);
|
|
532
|
+
gl.viewport(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
|
533
|
+
gl.clearColor(0, 0, 0, 0); // clear to transparent
|
|
534
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
535
|
+
// Render U to R channel and A channel (alpha indicates valid data)
|
|
536
|
+
gl.colorMask(true, false, false, true);
|
|
537
|
+
renderSpeedBuffer(gl, matrix, bufferU, numTrianglesU);
|
|
538
|
+
// Render V to G channel only (preserve R and A from U pass)
|
|
539
|
+
gl.colorMask(false, true, false, false);
|
|
540
|
+
renderSpeedBuffer(gl, matrix, bufferV, numTrianglesV);
|
|
541
|
+
// Reset color mask to default
|
|
542
|
+
gl.colorMask(true, true, true, true);
|
|
543
|
+
// Compute particle positions (moves expensive loop from vertex shader)
|
|
544
|
+
renderPositionTexture(gl);
|
|
545
|
+
}
|
|
546
|
+
// Unbind framebuffer so we're rendering to the screen:
|
|
547
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
548
|
+
// Reset the viewport size to equal the map size:
|
|
549
|
+
gl.viewport(0, 0, width * window.devicePixelRatio, height * window.devicePixelRatio);
|
|
550
|
+
// Render particles:
|
|
551
|
+
renderParticles(gl, matrix);
|
|
552
|
+
};
|
|
553
|
+
// Free all WebGL resources when this generation's layer is removed (Mapbox
|
|
554
|
+
// calls this on removeLayer). gl.deleteX(null) is a safe no-op.
|
|
555
|
+
var onRemove = function (_mbMap, gl) {
|
|
556
|
+
removed = true;
|
|
557
|
+
gl.deleteProgram(uvProgram);
|
|
558
|
+
gl.deleteProgram(particlesProgram);
|
|
559
|
+
gl.deleteProgram(positionProgram);
|
|
560
|
+
gl.deleteBuffer(bufferU);
|
|
561
|
+
gl.deleteBuffer(bufferV);
|
|
562
|
+
gl.deleteBuffer(bufferScreen);
|
|
563
|
+
gl.deleteBuffer(bufferQuad);
|
|
564
|
+
gl.deleteTexture(textureUV);
|
|
565
|
+
gl.deleteTexture(texturePosition);
|
|
566
|
+
gl.deleteFramebuffer(fboUV);
|
|
567
|
+
gl.deleteFramebuffer(fboPosition);
|
|
568
|
+
uvProgram = null;
|
|
569
|
+
particlesProgram = null;
|
|
570
|
+
positionProgram = null;
|
|
571
|
+
bufferU = null;
|
|
572
|
+
bufferV = null;
|
|
573
|
+
bufferScreen = null;
|
|
574
|
+
bufferQuad = null;
|
|
575
|
+
textureUV = null;
|
|
576
|
+
texturePosition = null;
|
|
577
|
+
fboUV = null;
|
|
578
|
+
fboPosition = null;
|
|
579
|
+
};
|
|
580
|
+
return { id: id, onAdd: onAdd, render: render, onRemove: onRemove };
|
|
581
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
582
|
+
}, [geometry, props.density, props.particles, props.minSpeed, props.maxSpeed]);
|
|
583
|
+
return (React.createElement(Layer, { id: layer.id, key: layer.id, type: "custom", beforeId: "overlay", onAdd: layer.onAdd, onRemove: layer.onRemove, render: layer.render }));
|
|
455
584
|
};
|
|
456
585
|
/**
|
|
457
586
|
* A WebGL-based Mapbox GL custom layer that visualizes vector flow fields (such as
|
|
@@ -538,12 +667,7 @@ var ParticlesLayerBase = function (props) {
|
|
|
538
667
|
* - Changing props triggers a full re-initialization of the WebGL resources
|
|
539
668
|
*/
|
|
540
669
|
var ParticlesLayer = function (_a) {
|
|
541
|
-
var _b = _a.particles, particles = _b === void 0 ?
|
|
542
|
-
{ pos: 0.0, color: '#ffffffff' },
|
|
543
|
-
{ pos: 0.25, color: '#5c5cffff' },
|
|
544
|
-
{ pos: 0.5, color: '#5c5cff00' },
|
|
545
|
-
{ pos: 1.0, color: '#5c5cff00' }, // transparent blue
|
|
546
|
-
] : _e, _f = _a.minZoom, minZoom = _f === void 0 ? 0 : _f, _g = _a.maxZoom, maxZoom = _g === void 0 ? 99 : _g, _h = _a.minSpeed, minSpeed = _h === void 0 ? 0.02 : _h, _j = _a.maxSpeed, maxSpeed = _j === void 0 ? 0.15 : _j, props = __rest(_a, ["particles", "density", "delay", "gradientStops", "minZoom", "maxZoom", "minSpeed", "maxSpeed"]);
|
|
670
|
+
var _b = _a.particles, particles = _b === void 0 ? DEFAULT_PARTICLES : _b, _c = _a.density, density = _c === void 0 ? DEFAULT_DENSITY : _c, _d = _a.delay, delay = _d === void 0 ? DEFAULT_DELAY : _d, _e = _a.gradientStops, gradientStops = _e === void 0 ? DEFAULT_GRADIENT_STOPS : _e, _f = _a.minZoom, minZoom = _f === void 0 ? DEFAULT_MIN_ZOOM : _f, _g = _a.maxZoom, maxZoom = _g === void 0 ? DEFAULT_MAX_ZOOM : _g, _h = _a.minSpeed, minSpeed = _h === void 0 ? DEFAULT_MIN_SPEED : _h, _j = _a.maxSpeed, maxSpeed = _j === void 0 ? DEFAULT_MAX_SPEED : _j, props = __rest(_a, ["particles", "density", "delay", "gradientStops", "minZoom", "maxZoom", "minSpeed", "maxSpeed"]);
|
|
547
671
|
return React.createElement(ParticlesLayerBase, __assign({ particles: particles, density: density, gradientStops: gradientStops, delay: delay, minZoom: minZoom, maxZoom: maxZoom, minSpeed: minSpeed, maxSpeed: maxSpeed }, props));
|
|
548
672
|
};
|
|
549
673
|
ParticlesLayer.displayName = 'ParticlesLayer';
|