gridviz 3.0.41 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -15
- package/dist/gridviz.js +3227 -1941
- package/dist/gridviz.min.js +1 -1
- package/package.json +6 -4
- package/src/button/Button.js +77 -68
- package/src/button/FullscreenButton.js +123 -123
- package/src/button/ZoomButtons.js +109 -104
- package/src/core/Drawable.js +25 -3
- package/src/core/GeoCanvas.js +15 -0
- package/src/core/Legend.js +267 -245
- package/src/core/Map.js +180 -30
- package/src/core/Tooltip.js +191 -185
- package/src/dataset/TiledGrid.js +74 -24
- package/src/index.js +82 -79
- package/src/layer/GridLayer.js +196 -194
- package/src/layer/LabelLayer.js +7 -4
- package/src/legend/ColorCategoryLegend.js +127 -125
- package/src/legend/ColorDiscreteLegend.js +116 -114
- package/src/legend/ColorLegend.js +33 -11
- package/src/legend/OrientationLegend.js +94 -92
- package/src/legend/SizeLegend.js +8 -1
- package/src/legend/TernaryLegend.js +317 -314
- package/src/legend/VennLegend.js +202 -0
- package/src/style/CircleColorSizeWebGLStyle.js +249 -0
- package/src/style/CompositionStyle.js +1 -1
- package/src/style/DotDensityStyle.js +8 -4
- package/src/style/ImageStyle.js +1 -1
- package/src/style/Interpolator.js +31 -6
- package/src/style/IsoFenceStyle.js +1 -1
- package/src/style/LegoStyle.js +6 -5
- package/src/style/MosaicStyle.js +1 -1
- package/src/style/NinjaStarStyle.js +1 -1
- package/src/style/PillarStyle.js +1 -1
- package/src/style/RandomWalkInterpolator.js +213 -0
- package/src/style/ShadingRayStyle.js +16 -2
- package/src/style/ShadingStyle.js +80 -72
- package/src/style/ShapeColorSizeStyle.js +18 -2
- package/src/style/SideCategoryStyle.js +1 -1
- package/src/style/SideStyle.js +1 -1
- package/src/style/SideTanakaStyle.js +1 -1
- package/src/style/SquareColorCategoryWebGLStyle.js +71 -20
- package/src/style/SquareColorWebGLStyle.js +7 -4
- package/src/style/StrokeStyle.js +1 -1
- package/src/style/TextStyle.js +1 -1
- package/src/style/TimeSeriesStyle.js +14 -7
- package/src/utils/WebGLSquareColoringAdvanced.js +47 -9
- package/src/utils/scale.js +20 -0
- package/src/utils/webGLUtils.js +52 -0
package/src/core/Tooltip.js
CHANGED
|
@@ -1,185 +1,191 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
'use strict'
|
|
3
|
-
|
|
4
|
-
import { select } from 'd3-selection'
|
|
5
|
-
//import { transition } from "d3-transition";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A generic class to make a tooltip.
|
|
9
|
-
* It is a div element, which can be moved under the mouse pointer and filled with some information in html.
|
|
10
|
-
* @module core
|
|
11
|
-
*/
|
|
12
|
-
export class Tooltip {
|
|
13
|
-
/**
|
|
14
|
-
* @param {object} opts
|
|
15
|
-
*/
|
|
16
|
-
constructor(opts) {
|
|
17
|
-
opts = opts || {}
|
|
18
|
-
|
|
19
|
-
/** @type {string} */
|
|
20
|
-
this.maxWidth = opts.maxWidth || '20em'
|
|
21
|
-
/** @type {string} */
|
|
22
|
-
this.fontSize = opts.fontSize || '
|
|
23
|
-
/** @type {string} */
|
|
24
|
-
this.
|
|
25
|
-
/** @type {string} */
|
|
26
|
-
this.
|
|
27
|
-
/** @type {string} */
|
|
28
|
-
this.
|
|
29
|
-
/** @type {string} */
|
|
30
|
-
this
|
|
31
|
-
/** @type {string} */
|
|
32
|
-
this
|
|
33
|
-
/** @type {string} */
|
|
34
|
-
this['
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/** @type {number} */
|
|
41
|
-
this.
|
|
42
|
-
/** @type {number} */
|
|
43
|
-
this.
|
|
44
|
-
/** @type {number} */
|
|
45
|
-
this.
|
|
46
|
-
/** @type {
|
|
47
|
-
this.
|
|
48
|
-
/** @type {
|
|
49
|
-
this.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.tooltip.style('
|
|
64
|
-
this.tooltip.style('
|
|
65
|
-
this.tooltip.style('
|
|
66
|
-
this.tooltip.style('
|
|
67
|
-
this.tooltip.style('
|
|
68
|
-
this.tooltip.style('
|
|
69
|
-
this.tooltip.style('
|
|
70
|
-
this.tooltip.style('
|
|
71
|
-
this.tooltip.style('
|
|
72
|
-
this.tooltip.style('
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.tooltip.style('
|
|
76
|
-
this.tooltip.style('
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
this.tooltip.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
this.tooltip.
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
|
|
93
|
-
// @ts-ignore
|
|
94
|
-
this.tooltip.transition().duration(this.transitionDuration).style('opacity',
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Ensure tooltip doesn't go beyond the
|
|
142
|
-
if (node.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
my.setPosition(event);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (arguments.length == 1) return this.tooltip.
|
|
182
|
-
this.tooltip.
|
|
183
|
-
return this
|
|
184
|
-
}
|
|
185
|
-
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { select } from 'd3-selection'
|
|
5
|
+
//import { transition } from "d3-transition";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A generic class to make a tooltip.
|
|
9
|
+
* It is a div element, which can be moved under the mouse pointer and filled with some information in html.
|
|
10
|
+
* @module core
|
|
11
|
+
*/
|
|
12
|
+
export class Tooltip {
|
|
13
|
+
/**
|
|
14
|
+
* @param {object} opts
|
|
15
|
+
*/
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
opts = opts || {}
|
|
18
|
+
|
|
19
|
+
/** @type {string} */
|
|
20
|
+
this.maxWidth = opts.maxWidth || '20em'
|
|
21
|
+
/** @type {string} */
|
|
22
|
+
this.fontSize = opts.fontSize || '1rem'
|
|
23
|
+
/** @type {string} */
|
|
24
|
+
this.color = opts.color || '#171a22'
|
|
25
|
+
/** @type {string} */
|
|
26
|
+
this.lineHeight = opts.lineHeight || '1.5'
|
|
27
|
+
/** @type {string} */
|
|
28
|
+
this.background = opts.background || 'white'
|
|
29
|
+
/** @type {string} */
|
|
30
|
+
this.padding = opts.padding || '4px'
|
|
31
|
+
/** @type {string} */
|
|
32
|
+
this.border = opts.border || '1px solid #d5d5d5'
|
|
33
|
+
/** @type {string} */
|
|
34
|
+
this['border-radius'] = opts['border-radius'] || '6px'
|
|
35
|
+
/** @type {string} */
|
|
36
|
+
this['box-shadow'] = opts['box-shadow'] || '0px 4px 6px rgba(0, 0, 0, 0.1), 0px 1px 3px rgba(0, 0, 0, 0.08)'
|
|
37
|
+
/** @type {string} */
|
|
38
|
+
this['font-family'] = opts['font-family'] || "'Helvetica Neue', Arial, Helvetica, sans-serif"
|
|
39
|
+
|
|
40
|
+
/** @type {number} */
|
|
41
|
+
this.transitionDuration = opts.transitionDuration || 100
|
|
42
|
+
/** @type {number} */
|
|
43
|
+
this.xOffset = opts.xOffset || 30
|
|
44
|
+
/** @type {number} */
|
|
45
|
+
this.yOffset = opts.yOffset || 20
|
|
46
|
+
/** @type {number} */ // e.g. to prevent mouse cursor covering cell being highlighted
|
|
47
|
+
this.yMouseOffset = opts.yMouseOffset || 0
|
|
48
|
+
/** @type {number} */
|
|
49
|
+
this.xMouseOffset = opts.xMouseOffset || 0
|
|
50
|
+
/** @type {HTMLElement} */
|
|
51
|
+
this.parentElement = opts.parentElement || document.body
|
|
52
|
+
/** @type {HTMLElement} */
|
|
53
|
+
this.tooltipElement = opts.tooltipElement || null
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @public
|
|
57
|
+
* @type {import("d3-selection").Selection} */
|
|
58
|
+
this.tooltip = opts.tooltipElement
|
|
59
|
+
? select(opts.tooltipElement) // Wrap the provided HTML node in a D3 selection
|
|
60
|
+
: select(this.parentElement).append('div').attr('id', 'gridviz-tooltip').attr('class', 'gridviz-tooltip') // create default element
|
|
61
|
+
|
|
62
|
+
//initialise
|
|
63
|
+
this.tooltip.style('max-width', this.maxWidth)
|
|
64
|
+
this.tooltip.style('overflow', 'hidden')
|
|
65
|
+
this.tooltip.style('font-size', this.fontSize)
|
|
66
|
+
this.tooltip.style('color', this.color)
|
|
67
|
+
this.tooltip.style('line-height', this.lineHeight)
|
|
68
|
+
this.tooltip.style('background', this.background)
|
|
69
|
+
this.tooltip.style('padding', this.padding)
|
|
70
|
+
this.tooltip.style('border', this.border)
|
|
71
|
+
this.tooltip.style('border-radius', this['border-radius'])
|
|
72
|
+
this.tooltip.style('box-shadow', this['box-shadow'])
|
|
73
|
+
this.tooltip.style('font-family', this['font-family'])
|
|
74
|
+
this.tooltip.style('position', 'absolute')
|
|
75
|
+
this.tooltip.style('pointer-events', 'none')
|
|
76
|
+
this.tooltip.style('opacity', '0')
|
|
77
|
+
this.tooltip.style('text-wrap', 'nowrap')
|
|
78
|
+
this.tooltip.style('z-index', 99999999) // important for leaflet-gridviz etc
|
|
79
|
+
|
|
80
|
+
// these placeholders are needed to prevent an infinite DOM resizeObserver loop:
|
|
81
|
+
this.tooltip.style('left', '0')
|
|
82
|
+
this.tooltip.style('top', '0')
|
|
83
|
+
|
|
84
|
+
// a tooltip element given by the user gets the class too
|
|
85
|
+
this.tooltip.classed('gridviz-tooltip', true)
|
|
86
|
+
|
|
87
|
+
// aria-labels (thanks to wahlatlas)
|
|
88
|
+
this.tooltip.attr('role', 'tooltip').attr('aria-live', 'polite')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Show the tooltip */
|
|
92
|
+
show() {
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
this.tooltip.transition().duration(this.transitionDuration).style('opacity', 1)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Hide the tooltip */
|
|
98
|
+
hide() {
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
this.tooltip.transition().duration(this.transitionDuration).style('opacity', 0)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Set the content of the tooltip.
|
|
105
|
+
* @param {string} html
|
|
106
|
+
*/
|
|
107
|
+
html(html) {
|
|
108
|
+
this.tooltip.html(html)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Set the position of the tooltip at the mouse event position.
|
|
113
|
+
* @param {MouseEvent} event
|
|
114
|
+
*/
|
|
115
|
+
setPosition(event) {
|
|
116
|
+
// Get the bounding rect of the parent container (map2)
|
|
117
|
+
let parentRect = this.parentElement.getBoundingClientRect()
|
|
118
|
+
|
|
119
|
+
// Get the mouse position (relative to the parent container)
|
|
120
|
+
let x = event.clientX - parentRect.left + this.xOffset // Relative to parent
|
|
121
|
+
let y = event.clientY - parentRect.top - this.yOffset // Relative to parent
|
|
122
|
+
|
|
123
|
+
// Now, apply the position to the tooltip
|
|
124
|
+
this.tooltip.style('left', x + 'px').style('top', y + 'px')
|
|
125
|
+
|
|
126
|
+
// Ensure the tooltip stays inside the parent container
|
|
127
|
+
this.ensureTooltipInsideContainer(event, parentRect, this.tooltip.node())
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @function ensureTooltipInsideContainer
|
|
131
|
+
* @description Prevents the tooltip from overflowing out of the App container (ensures that the tooltip is inside the gridviz container)
|
|
132
|
+
* @param {MouseEvent} event
|
|
133
|
+
* @param {DOMRect} parentRect
|
|
134
|
+
* @param {HTMLElement} tooltipNode
|
|
135
|
+
*/
|
|
136
|
+
ensureTooltipInsideContainer(event, parentRect, tooltipNode) {
|
|
137
|
+
let node = tooltipNode
|
|
138
|
+
let parentWidth = parentRect.width
|
|
139
|
+
let parentHeight = parentRect.height
|
|
140
|
+
|
|
141
|
+
// Ensure tooltip doesn't go beyond the right edge
|
|
142
|
+
if (node.offsetLeft + node.clientWidth > parentWidth) {
|
|
143
|
+
let left = event.clientX - node.clientWidth - this.xOffset
|
|
144
|
+
node.style.left = left + 'px'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Ensure tooltip doesn't go beyond the bottom edge
|
|
148
|
+
if (node.offsetTop + node.clientHeight > parentHeight) {
|
|
149
|
+
node.style.top = parentHeight - node.clientHeight + 'px'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Ensure tooltip doesn't go above the top edge
|
|
153
|
+
if (node.offsetTop < 0) {
|
|
154
|
+
node.style.top = 0 + 'px'
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Ensure tooltip doesn't go beyond the left edge
|
|
158
|
+
if (node.offsetLeft < 0) {
|
|
159
|
+
node.style.left = 0 + 'px'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
my.mouseover = function (event, html) {
|
|
165
|
+
if (html) my.html(html);
|
|
166
|
+
my.setPosition(event);
|
|
167
|
+
my.show()
|
|
168
|
+
//this.ensureTooltipInsideContainer();
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
my.mousemove = function (event) {
|
|
172
|
+
my.setPosition(event);
|
|
173
|
+
//this.ensureTooltipInsideContainer();
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
my.mouseout = function () {
|
|
177
|
+
my.hide();
|
|
178
|
+
};*/
|
|
179
|
+
|
|
180
|
+
style(k, v) {
|
|
181
|
+
if (arguments.length == 1) return this.tooltip.style(k)
|
|
182
|
+
this.tooltip.style(k, v)
|
|
183
|
+
return this
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
attr(k, v) {
|
|
187
|
+
if (arguments.length == 1) return this.tooltip.attr(k)
|
|
188
|
+
this.tooltip.attr(k, v)
|
|
189
|
+
return this
|
|
190
|
+
}
|
|
191
|
+
}
|
package/src/dataset/TiledGrid.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
// internal
|
|
7
7
|
import { Dataset } from '../core/Dataset.js'
|
|
8
|
+
import { isVisibleAt } from '../core/Drawable.js'
|
|
8
9
|
//import { monitor, monitorDuration } from '../utils/Utils.js'
|
|
9
10
|
|
|
10
11
|
// external
|
|
@@ -96,7 +97,7 @@ export class TiledGrid extends Dataset {
|
|
|
96
97
|
if (!this.map || !this.map.layers) return false
|
|
97
98
|
const z = this.map.getZoom()
|
|
98
99
|
for (const lay of this.map.layers) {
|
|
99
|
-
if (lay
|
|
100
|
+
if (!isVisibleAt(lay, z)) continue
|
|
100
101
|
if (!lay.getDataset) continue
|
|
101
102
|
if (lay.getDataset(z) == this) return true
|
|
102
103
|
}
|
|
@@ -152,8 +153,6 @@ export class TiledGrid extends Dataset {
|
|
|
152
153
|
const yMin = Math.max(tb.yMin, gbYMin)
|
|
153
154
|
const yMax = Math.min(tb.yMax, gbYMax)
|
|
154
155
|
|
|
155
|
-
const totalTiles = (xMax - xMin + 1) * (yMax - yMin + 1)
|
|
156
|
-
let processedTiles = 0
|
|
157
156
|
const tilePromises = []
|
|
158
157
|
|
|
159
158
|
// Iterate over tiles within bounds
|
|
@@ -161,11 +160,13 @@ export class TiledGrid extends Dataset {
|
|
|
161
160
|
for (let yT = yMin; yT <= yMax; yT++) {
|
|
162
161
|
if (!this.cache[xT]) this.cache[xT] = {}
|
|
163
162
|
|
|
164
|
-
// Skip
|
|
165
|
-
|
|
163
|
+
// Skip the tiles loaded, under way, or that failed recently
|
|
164
|
+
const kept = this.cache[xT][yT]
|
|
165
|
+
const retry =
|
|
166
|
+
kept && kept.failed && !kept.missing && now() - kept.failed >= TiledGrid.retryFailedAfterMs
|
|
167
|
+
if (kept && !retry) {
|
|
166
168
|
// in the view: not to be dropped
|
|
167
|
-
if (
|
|
168
|
-
++processedTiles
|
|
169
|
+
if (kept.cells) kept.lastUsed = now()
|
|
169
170
|
continue
|
|
170
171
|
}
|
|
171
172
|
|
|
@@ -173,19 +174,40 @@ export class TiledGrid extends Dataset {
|
|
|
173
174
|
this.cache[xT][yT] = 'loading'
|
|
174
175
|
|
|
175
176
|
tilePromises.push(
|
|
176
|
-
this.loadTile(xT, yT, signal)
|
|
177
|
-
|
|
177
|
+
this.loadTile(xT, yT, signal).then(
|
|
178
|
+
(tile) => {
|
|
178
179
|
this.cache[xT][yT] = tile
|
|
179
180
|
this._keep(tile)
|
|
180
181
|
|
|
181
182
|
// Check if this is the last tile
|
|
182
|
-
|
|
183
|
+
// (tiles under way for another request count: the one that ends last is the one that draws)
|
|
184
|
+
const isLastTile = !this._anyLoading(xMin, xMax, yMin, yMax)
|
|
183
185
|
this.checkAndRedraw(tile, isLastTile)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
},
|
|
187
|
+
(error) => {
|
|
188
|
+
if (error && error.name === 'AbortError') {
|
|
189
|
+
// cancelled, not failed: the next request loads it
|
|
190
|
+
delete this.cache[xT][yT]
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
// Most of the time a tile that fails is one the server doesn't have (the tiles of a grid are
|
|
194
|
+
// often sparse). It is remembered as failed, and not asked for again at every redraw.
|
|
195
|
+
// A 404 is final ('missing'). Any other failure is tried again after retryFailedAfterMs: a
|
|
196
|
+
// browser doesn't give the status of a response without CORS headers, so a 404 from such a
|
|
197
|
+
// server can't be told from a network error.
|
|
198
|
+
this.cache[xT][yT] = {
|
|
199
|
+
failed: now(),
|
|
200
|
+
missing: /^(404|410)\b/.test(error && error.message),
|
|
201
|
+
}
|
|
202
|
+
// it changes nothing on the map, except when it was waited for to draw
|
|
203
|
+
if (
|
|
204
|
+
this.onlyDrawWhenAllTilesReady &&
|
|
205
|
+
!this._anyLoading(xMin, xMax, yMin, yMax) &&
|
|
206
|
+
this.isShown()
|
|
207
|
+
)
|
|
208
|
+
this.map.redraw()
|
|
209
|
+
}
|
|
210
|
+
)
|
|
189
211
|
)
|
|
190
212
|
}
|
|
191
213
|
}
|
|
@@ -194,6 +216,25 @@ export class TiledGrid extends Dataset {
|
|
|
194
216
|
return this
|
|
195
217
|
}
|
|
196
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Tells if some tiles of a tiling envelope are still being loaded, by this request or any other one.
|
|
221
|
+
*
|
|
222
|
+
* @param {number} xMin
|
|
223
|
+
* @param {number} xMax
|
|
224
|
+
* @param {number} yMin
|
|
225
|
+
* @param {number} yMax
|
|
226
|
+
* @returns {boolean}
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
_anyLoading(xMin, xMax, yMin, yMax) {
|
|
230
|
+
for (let xT = xMin; xT <= xMax; xT++) {
|
|
231
|
+
const column = this.cache[xT]
|
|
232
|
+
if (!column) continue
|
|
233
|
+
for (let yT = yMin; yT <= yMax; yT++) if (column[yT] === 'loading') return true
|
|
234
|
+
}
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
|
|
197
238
|
/**
|
|
198
239
|
* Load a tile.
|
|
199
240
|
*
|
|
@@ -234,19 +275,20 @@ export class TiledGrid extends Dataset {
|
|
|
234
275
|
// 1. the dataset belongs to a layer which is visible at the current zoom level
|
|
235
276
|
if (!this.isShown()) return
|
|
236
277
|
|
|
278
|
+
// Waiting for all the tiles: drawn when the last one arrives, wherever it is (the tiles asked for are those of the
|
|
279
|
+
// view and of a margin around it, so the last one to arrive may be outside the view)
|
|
280
|
+
if (this.onlyDrawWhenAllTilesReady) {
|
|
281
|
+
if (isLastTile) this.map.redraw()
|
|
282
|
+
return
|
|
283
|
+
}
|
|
284
|
+
|
|
237
285
|
// Check if tile intersects the current view
|
|
238
286
|
const env = this.map.updateExtentGeo()
|
|
239
287
|
const { xMin, xMax, yMin, yMax } = tile.extGeo
|
|
240
288
|
if (env.xMax <= xMin || env.xMin >= xMax || env.yMax <= yMin || env.yMin >= yMax) return
|
|
241
289
|
|
|
242
290
|
// Trigger redraw
|
|
243
|
-
|
|
244
|
-
if (isLastTile) {
|
|
245
|
-
this.map.redraw()
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
this.map.redraw()
|
|
249
|
-
}
|
|
291
|
+
this.map.redraw()
|
|
250
292
|
}
|
|
251
293
|
|
|
252
294
|
/**
|
|
@@ -256,7 +298,7 @@ export class TiledGrid extends Dataset {
|
|
|
256
298
|
* @private
|
|
257
299
|
*/
|
|
258
300
|
_keep(tile) {
|
|
259
|
-
// a failed tile is
|
|
301
|
+
// a failed tile is not a tile
|
|
260
302
|
if (!tile || typeof tile !== 'object' || !tile.cells) return
|
|
261
303
|
tile.lastUsed = now()
|
|
262
304
|
tile.owner = this
|
|
@@ -316,7 +358,7 @@ export class TiledGrid extends Dataset {
|
|
|
316
358
|
//get tile
|
|
317
359
|
/** @type {object} */
|
|
318
360
|
const tile = this.cache[xT][yT]
|
|
319
|
-
if (!tile ||
|
|
361
|
+
if (!tile || !tile.cells) continue
|
|
320
362
|
tile.lastUsed = now()
|
|
321
363
|
|
|
322
364
|
//get cells
|
|
@@ -342,6 +384,14 @@ export class TiledGrid extends Dataset {
|
|
|
342
384
|
*/
|
|
343
385
|
TiledGrid.maxCachedCells = 1500000
|
|
344
386
|
|
|
387
|
+
/**
|
|
388
|
+
* How long, in ms, a tile that failed to load is remembered, before it is requested again. It doesn't apply to a tile the
|
|
389
|
+
* server answered 404 or 410 for: that one isn't requested again. It can be changed at any time.
|
|
390
|
+
*
|
|
391
|
+
* @type {number}
|
|
392
|
+
*/
|
|
393
|
+
TiledGrid.retryFailedAfterMs = 30000
|
|
394
|
+
|
|
345
395
|
function getGridTile(cells, xT, yT, gridInfo) {
|
|
346
396
|
const tile = {}
|
|
347
397
|
|