gridviz 2.0.28 → 2.0.29
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/dist/gridviz.js +34315 -0
- package/package.json +3 -2
- package/src/App.js +651 -0
- package/src/BackgroundLayer.js +182 -0
- package/src/BackgroundLayerWMS.js +131 -0
- package/src/Dataset.js +76 -0
- package/src/DatasetComponent.js +103 -0
- package/src/GeoCanvas.js +419 -0
- package/src/LabelLayer.js +190 -0
- package/src/Layer.js +92 -0
- package/src/Legend.js +86 -0
- package/src/LineLayer.js +150 -0
- package/src/Style.js +114 -0
- package/src/Tooltip.js +150 -0
- package/src/dataset/COGeo.js +24 -0
- package/src/dataset/CSVGrid.js +105 -0
- package/src/dataset/GeoTIFF.js +127 -0
- package/src/dataset/GridTile.js +41 -0
- package/src/dataset/ParquetGrid.js +123 -0
- package/src/dataset/TiledGrid.js +294 -0
- package/src/index.js +176 -0
- package/src/legend/ColorCategoryLegend.js +124 -0
- package/src/legend/ColorDiscreteLegend.js +105 -0
- package/src/legend/ColorLegend.js +125 -0
- package/src/legend/SegmentOrientationLegend.js +87 -0
- package/src/legend/SegmentWidthLegend.js +97 -0
- package/src/legend/SizeLegend.js +141 -0
- package/src/style/CompositionStyle.js +294 -0
- package/src/style/ContourStyle.js +54 -0
- package/src/style/DotDensityStyle.js +156 -0
- package/src/style/JoyPlotStyle.js +135 -0
- package/src/style/KernelSmoothingOldStyle.js +221 -0
- package/src/style/KernelSmoothingStyle.js +115 -0
- package/src/style/KernelSmoothingWGLStyle.js +130 -0
- package/src/style/LegoStyle.js +112 -0
- package/src/style/MosaicStyle.js +107 -0
- package/src/style/NinjaStarStyle.js +124 -0
- package/src/style/PillarStyle.js +230 -0
- package/src/style/SegmentStyle.js +142 -0
- package/src/style/ShapeColorSizeStyle.js +126 -0
- package/src/style/SideCatStyle.js +172 -0
- package/src/style/SideStyle.js +218 -0
- package/src/style/SquareColorCatWGLStyle.js +120 -0
- package/src/style/SquareColorWGLStyle.js +146 -0
- package/src/style/StrokeStyle.js +131 -0
- package/src/style/TanakaStyle.js +160 -0
- package/src/style/TextStyle.js +132 -0
- package/src/utils/Utils.js +35 -0
- package/src/utils/WebGLRectangleColoring.js +106 -0
- package/src/utils/WebGLSquareColoring.js +118 -0
- package/src/utils/WebGLSquareColoringAdvanced.js +230 -0
- package/src/utils/WebGLSquareColoringCatAdvanced.js +133 -0
- package/src/utils/WebGLSquareColoringKS.js +153 -0
- package/src/utils/stretching.js +131 -0
- package/src/utils/webGLUtils.js +71 -0
- package/src/utils/zoomUtils.js +142 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
import { initShaderProgram, createShader } from './webGLUtils'
|
|
5
|
+
import { color } from 'd3-color'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Everything to easily draw colored squares with webGL.
|
|
9
|
+
* All the same size, but different fill color.
|
|
10
|
+
* The color interpolation is computed in the fragment shader program, by the GPU, thus it is less flexible but faster.
|
|
11
|
+
*/
|
|
12
|
+
export class WebGLSquareColoringKS {
|
|
13
|
+
//see:
|
|
14
|
+
//https://webglfundamentals.org/
|
|
15
|
+
//https://webglfundamentals.org/webgl/lessons/fr/webgl-shaders-and-glsl.html#les-uniforms-dans-les-shaders-de-vertex
|
|
16
|
+
//https://thebookofshaders.com/glossary/?search=mix
|
|
17
|
+
//https://thebookofshaders.com/06/
|
|
18
|
+
//https://thebookofshaders.com/glossary/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {*} gl
|
|
23
|
+
* @param {Array.<String>} colors
|
|
24
|
+
* @param {{fun:string,alpha:number}} stretching
|
|
25
|
+
* @param {number} sizePix
|
|
26
|
+
*/
|
|
27
|
+
constructor(gl, colors, stretching, sizePix = 10) {
|
|
28
|
+
/** @type {WebGLRenderingContext} */
|
|
29
|
+
this.gl = gl
|
|
30
|
+
|
|
31
|
+
/** @type {WebGLShader} */
|
|
32
|
+
const vShader = createShader(
|
|
33
|
+
gl,
|
|
34
|
+
gl.VERTEX_SHADER,
|
|
35
|
+
`
|
|
36
|
+
attribute vec2 pos;
|
|
37
|
+
uniform float sizePix;
|
|
38
|
+
uniform vec3 data[2];
|
|
39
|
+
uniform mat3 mat;
|
|
40
|
+
|
|
41
|
+
varying float vt;
|
|
42
|
+
|
|
43
|
+
void main() {
|
|
44
|
+
|
|
45
|
+
//one vertex for each screen pixels
|
|
46
|
+
//list of data as uniform
|
|
47
|
+
//compute smoothed t here from uniforms
|
|
48
|
+
|
|
49
|
+
//compute cell screen position
|
|
50
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
51
|
+
|
|
52
|
+
//set pixel size - same for all
|
|
53
|
+
gl_PointSize = sizePix;
|
|
54
|
+
|
|
55
|
+
//pass the pixel value to the fragment as varying
|
|
56
|
+
vt = data[2];
|
|
57
|
+
}
|
|
58
|
+
`
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
//prepare fragment shader code
|
|
62
|
+
//declare the uniform and other variables
|
|
63
|
+
let fshString = `
|
|
64
|
+
precision mediump float;
|
|
65
|
+
varying float vt;
|
|
66
|
+
uniform float alpha;
|
|
67
|
+
uniform vec4 c0;
|
|
68
|
+
uniform vec4 c1;
|
|
69
|
+
uniform vec4 c2;
|
|
70
|
+
uniform vec4 c3;
|
|
71
|
+
uniform vec4 c4;
|
|
72
|
+
void main(void) {
|
|
73
|
+
if(vt == 0.0) return;
|
|
74
|
+
float t = 1.0 - (1.0 / alpha) * log(exp(alpha) * (1.0 - vt) + vt);
|
|
75
|
+
vec4 cI;
|
|
76
|
+
vec4 cF;
|
|
77
|
+
if(t<1.0/4.0) { cI=c0; cF=c1; t=t*4.0; }
|
|
78
|
+
else if(t<2.0/4.0) { cI=c1; cF=c2; t=4.0*t-1.0; }
|
|
79
|
+
else if(t<3.0/4.0) { cI=c2; cF=c3; t=4.0*t-2.0; }
|
|
80
|
+
else { cI=c3; cF=c4; t=4.0*t-3.0; }
|
|
81
|
+
gl_FragColor = mix(cI, cF, t);
|
|
82
|
+
}`
|
|
83
|
+
|
|
84
|
+
/** @type {WebGLShader} */
|
|
85
|
+
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fshString)
|
|
86
|
+
|
|
87
|
+
/** @type {WebGLProgram} */
|
|
88
|
+
this.program = initShaderProgram(gl, vShader, fShader)
|
|
89
|
+
gl.useProgram(this.program)
|
|
90
|
+
|
|
91
|
+
//set uniforms
|
|
92
|
+
|
|
93
|
+
//sizePix
|
|
94
|
+
gl.uniform1f(gl.getUniformLocation(this.program, 'sizePix'), 1.0 * sizePix)
|
|
95
|
+
|
|
96
|
+
//stretching alpha factor
|
|
97
|
+
gl.uniform1f(gl.getUniformLocation(this.program, 'alpha'), stretching ? 1.0 * stretching.alpha : 0.0)
|
|
98
|
+
|
|
99
|
+
//colors
|
|
100
|
+
for (let i = 0; i < colors.length; i++) {
|
|
101
|
+
const c = color(colors[i])
|
|
102
|
+
gl.uniform4fv(gl.getUniformLocation(this.program, 'c' + i), [
|
|
103
|
+
+c.r / 255.0,
|
|
104
|
+
+c.g / 255.0,
|
|
105
|
+
+c.b / 255.0,
|
|
106
|
+
+c.opacity,
|
|
107
|
+
])
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** */
|
|
112
|
+
draw(verticesBuffer, data, transfoMat) {
|
|
113
|
+
const gl = this.gl
|
|
114
|
+
const program = this.program
|
|
115
|
+
|
|
116
|
+
//vertice data
|
|
117
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
118
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesBuffer), gl.STATIC_DRAW)
|
|
119
|
+
const position = gl.getAttribLocation(program, 'pos')
|
|
120
|
+
gl.vertexAttribPointer(
|
|
121
|
+
position,
|
|
122
|
+
2, //numComponents
|
|
123
|
+
gl.FLOAT, //type
|
|
124
|
+
false, //normalise
|
|
125
|
+
0, //stride
|
|
126
|
+
0 //offset
|
|
127
|
+
)
|
|
128
|
+
gl.enableVertexAttribArray(position)
|
|
129
|
+
|
|
130
|
+
//t data
|
|
131
|
+
/*gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
|
|
132
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tBuffer), gl.STATIC_DRAW);
|
|
133
|
+
const t = gl.getAttribLocation(program, "t");
|
|
134
|
+
gl.vertexAttribPointer(t, 1, gl.FLOAT, false, 0, 0);
|
|
135
|
+
gl.enableVertexAttribArray(t);*/
|
|
136
|
+
|
|
137
|
+
//data
|
|
138
|
+
//gl.uniformMatrix3fv(gl.getUniformLocation(program, "mat"), false, new Float32Array(transfoMat));
|
|
139
|
+
gl.uniform3fv(gl.getUniformLocation(program, 'data'), 2, new Float32Array(data))
|
|
140
|
+
|
|
141
|
+
//transformation
|
|
142
|
+
gl.uniformMatrix3fv(gl.getUniformLocation(program, 'mat'), false, new Float32Array(transfoMat))
|
|
143
|
+
|
|
144
|
+
// Enable the depth test
|
|
145
|
+
//gl.enable(gl.DEPTH_TEST);
|
|
146
|
+
// Clear the color buffer bit
|
|
147
|
+
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
148
|
+
// Set the view port
|
|
149
|
+
//gl.viewport(0, 0, cg.w, cg.h);
|
|
150
|
+
|
|
151
|
+
gl.drawArrays(gl.POINTS, 0, verticesBuffer.length / 2)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Some function [0,1]->[0,1] to stretch range of values.
|
|
6
|
+
* @see https://github.com/eurostat/gridviz/blob/master/docs/reference.md#stretching
|
|
7
|
+
* @see https://observablehq.com/@jgaffuri/stretching
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
12
|
+
* Polynomial
|
|
13
|
+
*
|
|
14
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
15
|
+
* @param {number} alpha 1: no stretching. <1: show low values. >1: show high values.
|
|
16
|
+
* @returns {number} The stretched value, within [0,1]
|
|
17
|
+
*/
|
|
18
|
+
export const sPow = (t, alpha = 3) => Math.pow(t, alpha)
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
22
|
+
* Polynomial (reverse)
|
|
23
|
+
*
|
|
24
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
25
|
+
* @param {number} alpha 1: no stretching. <1: show low values. >1: show high values.
|
|
26
|
+
* @returns {number} The stretched value, within [0,1]
|
|
27
|
+
*/
|
|
28
|
+
export const sPowRev = (t, alpha = 3) => 1 - Math.pow(1 - t, 1 / alpha)
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
32
|
+
* Exponential
|
|
33
|
+
*
|
|
34
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
35
|
+
* @param {number} alpha 0: no stretching. -Inf: show low values. Inf: show high values.
|
|
36
|
+
* @returns {number} The stretched value, within [0,1]
|
|
37
|
+
*/
|
|
38
|
+
export const sExp = (t, alpha = 3) => (alpha == 0 ? t : (Math.exp(t * alpha) - 1) / (Math.exp(alpha) - 1))
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
42
|
+
* Exponential (reverse)
|
|
43
|
+
*
|
|
44
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
45
|
+
* @param {number} alpha 0: no stretching. -Inf: show low values. Inf: show high values.
|
|
46
|
+
* @returns {number} The stretched value, within [0,1]
|
|
47
|
+
*/
|
|
48
|
+
export const sExpRev = (t, alpha = 3) =>
|
|
49
|
+
alpha == 0 ? t : 1 - (1 / alpha) * Math.log(Math.exp(alpha) * (1 - t) + t)
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
53
|
+
* Circle, show low values
|
|
54
|
+
* NB: sCircleHigh and sCircleLow are inverse functions of each other.
|
|
55
|
+
*
|
|
56
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
57
|
+
* @param {number} alpha 0: no stretching. 1: perfect circle section
|
|
58
|
+
* @returns {number} The stretched value, within [0,1]
|
|
59
|
+
*/
|
|
60
|
+
export const sCircleLow = (t, alpha = 0.8) => {
|
|
61
|
+
if (alpha == 0) return t
|
|
62
|
+
if (alpha == 1) return Math.sqrt(t * (2 - t))
|
|
63
|
+
const a = alpha / (1 - alpha)
|
|
64
|
+
return Math.sqrt(1 / (a * a) + t * (2 / a + 2 - t)) - 1 / a
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Function [0,1]->[0,1] to stretch range of values.
|
|
69
|
+
* Circle, show high values
|
|
70
|
+
* NB: sCircleHigh and sCircleLow are inverse functions of each other.
|
|
71
|
+
*
|
|
72
|
+
* @param {number} t The value to stretch, within [0,1]
|
|
73
|
+
* @param {number} alpha 0: no stretching. 1: perfect circle section
|
|
74
|
+
* @returns {number} The stretched value, within [0,1]
|
|
75
|
+
*/
|
|
76
|
+
export const sCircleHigh = (t, alpha = 0.8) => 1 - sCircleLow(1 - t, alpha)
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Inverse functions
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Inverse function of sExp
|
|
84
|
+
* @param {number} y
|
|
85
|
+
* @param {number} alpha
|
|
86
|
+
* @returns {number}
|
|
87
|
+
*/
|
|
88
|
+
export const sExpInverse = (y, alpha = 3) =>
|
|
89
|
+
alpha == 0 ? y : (1 / alpha) * Math.log(1 - y + y * Math.exp(alpha))
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Inverse function of sExpRev
|
|
93
|
+
* @param {number} y
|
|
94
|
+
* @param {number} alpha
|
|
95
|
+
* @returns {number}
|
|
96
|
+
*/
|
|
97
|
+
export const sExpRevInverse = (y, alpha = 3) => (Math.exp(-alpha * y) - 1) / (Math.exp(-alpha) - 1)
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Inverse function of sPow
|
|
101
|
+
* @param {number} y
|
|
102
|
+
* @param {number} alpha
|
|
103
|
+
* @returns {number}
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
export const sPowInverse = (y, alpha = 3) => Math.pow(y, 1 / alpha)
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Inverse function of sPowRev
|
|
110
|
+
* @param {number} y
|
|
111
|
+
* @param {number} alpha
|
|
112
|
+
* @returns {number}
|
|
113
|
+
*/
|
|
114
|
+
export const sPowRevInverse = (y, alpha = 3) => 1 - Math.pow(1 - y, alpha)
|
|
115
|
+
|
|
116
|
+
//test code
|
|
117
|
+
/*
|
|
118
|
+
for (let i = 0; i <= 1; i += 0.001) {
|
|
119
|
+
//const v = gviz.sExp(gviz.sExpInverse(i));
|
|
120
|
+
//const v = gviz.sExpInverse(gviz.sExp(i));
|
|
121
|
+
//const v = gviz.sExpRev(gviz.sExpRevInverse(i));
|
|
122
|
+
//const v = gviz.sExpRevInverse(gviz.sExpRev(i));
|
|
123
|
+
//const v = gviz.sPow(gviz.sPowInverse(i));
|
|
124
|
+
//const v = gviz.sPowInverse(gviz.sPow(i));
|
|
125
|
+
//const v = gviz.sPowRev(gviz.sPowRevInverse(i));
|
|
126
|
+
//const v = gviz.sPowRevInverse(gviz.sPowRev(i));
|
|
127
|
+
//const v = gviz.sCircleLow(gviz.sCircleHigh(i));
|
|
128
|
+
//const v = gviz.sCircleHigh(gviz.sCircleLow(i));
|
|
129
|
+
console.log(i - v)
|
|
130
|
+
}
|
|
131
|
+
*/
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} width
|
|
6
|
+
* @param {string} height
|
|
7
|
+
* @param {object} opts
|
|
8
|
+
* @returns {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext}}
|
|
9
|
+
*/
|
|
10
|
+
export function makeWebGLCanvas(width, height, opts) {
|
|
11
|
+
const canvas = document.createElement('canvas')
|
|
12
|
+
canvas.setAttribute('width', width)
|
|
13
|
+
canvas.setAttribute('height', height)
|
|
14
|
+
const gl = canvas.getContext('webgl', opts)
|
|
15
|
+
if (!gl) {
|
|
16
|
+
throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.')
|
|
17
|
+
}
|
|
18
|
+
return { canvas: canvas, gl: gl }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Initialize a shader program, so WebGL knows how to draw our data
|
|
23
|
+
*
|
|
24
|
+
* @param {WebGLRenderingContext} gl
|
|
25
|
+
* @param {...WebGLShader} shaders
|
|
26
|
+
* @returns {WebGLProgram}
|
|
27
|
+
*/
|
|
28
|
+
export function initShaderProgram(gl, ...shaders) {
|
|
29
|
+
/** @type {WebGLProgram|null} */
|
|
30
|
+
const program = gl.createProgram()
|
|
31
|
+
if (program == null) throw new Error('Cannot create webGL program')
|
|
32
|
+
for (const shader of shaders) gl.attachShader(program, shader)
|
|
33
|
+
gl.linkProgram(program)
|
|
34
|
+
if (gl.getProgramParameter(program, gl.LINK_STATUS)) return program
|
|
35
|
+
throw new Error(gl.getProgramInfoLog(program) || 'Cannot create webGL program (2)')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a shader of the given type, uploads the source and compiles it.
|
|
40
|
+
*
|
|
41
|
+
* @param {WebGLRenderingContext} gl
|
|
42
|
+
* @param {number} type
|
|
43
|
+
* @param {...string} sources
|
|
44
|
+
* @returns {WebGLShader}
|
|
45
|
+
*/
|
|
46
|
+
export function createShader(gl, type, ...sources) {
|
|
47
|
+
/** @type {WebGLShader|null} */
|
|
48
|
+
const shader = gl.createShader(type)
|
|
49
|
+
if (shader == null) throw new Error('Cannot create webGL shader')
|
|
50
|
+
gl.shaderSource(shader, sources.join('\n'))
|
|
51
|
+
gl.compileShader(shader)
|
|
52
|
+
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader
|
|
53
|
+
throw new Error(gl.getShaderInfoLog(shader) || 'Cannot create webGL shader (2)')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if webGL is supported
|
|
58
|
+
*
|
|
59
|
+
* @returns {boolean}
|
|
60
|
+
*/
|
|
61
|
+
export function checkWebGLSupport() {
|
|
62
|
+
try {
|
|
63
|
+
const canvas = document.createElement('canvas')
|
|
64
|
+
return !!window.WebGLRenderingContext &&
|
|
65
|
+
(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
|
|
66
|
+
? true
|
|
67
|
+
: false
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {import("../App").App} app
|
|
7
|
+
* @param {number} zfTarget
|
|
8
|
+
* @param {number} factor
|
|
9
|
+
* @param {number} delayMs
|
|
10
|
+
* @param {function|undefined} callback
|
|
11
|
+
* @param {number} delayBeforeCallBackMs
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export function zoomTo(
|
|
15
|
+
app,
|
|
16
|
+
zfTarget,
|
|
17
|
+
factor = 1.01,
|
|
18
|
+
delayMs = 0,
|
|
19
|
+
callback = undefined,
|
|
20
|
+
delayBeforeCallBackMs = 0
|
|
21
|
+
) {
|
|
22
|
+
//ensure good factor value: >1
|
|
23
|
+
factor = factor || 1.01
|
|
24
|
+
if (factor < 1) {
|
|
25
|
+
console.error('Unexpected value for factor: ' + factor + '. Set to default value 1.01')
|
|
26
|
+
factor = 1.01
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const zfIni = app.getZoomFactor()
|
|
30
|
+
if (zfTarget == zfIni) return
|
|
31
|
+
if (zfTarget < zfIni) factor = 1 / factor
|
|
32
|
+
let zf = zfIni
|
|
33
|
+
let timer = setInterval(() => {
|
|
34
|
+
//compute new zoom level
|
|
35
|
+
zf = app.getZoomFactor() * factor
|
|
36
|
+
if (zfTarget > zfIni && zf > zfTarget) zf = zfTarget
|
|
37
|
+
if (zfTarget < zfIni && zf < zfTarget) zf = zfTarget
|
|
38
|
+
|
|
39
|
+
//set new zoom level
|
|
40
|
+
app.setZoomFactor(zf)
|
|
41
|
+
app.redraw()
|
|
42
|
+
|
|
43
|
+
//target reached
|
|
44
|
+
if (zf == zfTarget) {
|
|
45
|
+
clearInterval(timer)
|
|
46
|
+
//trigger callback, if any
|
|
47
|
+
if (callback)
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
callback()
|
|
50
|
+
}, delayBeforeCallBackMs)
|
|
51
|
+
}
|
|
52
|
+
}, delayMs)
|
|
53
|
+
return timer
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {import("../App").App} app
|
|
59
|
+
* @param {number} xTarget
|
|
60
|
+
* @param {number} yTarget
|
|
61
|
+
* @param {number} zfTarget
|
|
62
|
+
* @param {number} progressFactorPix
|
|
63
|
+
* @param {number} delayMs
|
|
64
|
+
* @param {function|undefined} callback
|
|
65
|
+
* @param {number} delayBeforeCallBackMs
|
|
66
|
+
* @returns
|
|
67
|
+
*/
|
|
68
|
+
export function goToStraight(
|
|
69
|
+
app,
|
|
70
|
+
xTarget = NaN,
|
|
71
|
+
yTarget = NaN,
|
|
72
|
+
zfTarget = NaN,
|
|
73
|
+
progressFactorPix = 5,
|
|
74
|
+
delayMs = 0,
|
|
75
|
+
callback = undefined,
|
|
76
|
+
delayBeforeCallBackMs = 0
|
|
77
|
+
) {
|
|
78
|
+
//store initial position/zoom
|
|
79
|
+
const zfIni = app.getZoomFactor()
|
|
80
|
+
const cIni = app.getGeoCenter()
|
|
81
|
+
|
|
82
|
+
//default
|
|
83
|
+
xTarget = isNaN(xTarget) ? cIni.x : xTarget
|
|
84
|
+
yTarget = isNaN(yTarget) ? cIni.y : yTarget
|
|
85
|
+
zfTarget = isNaN(zfTarget) ? zfIni : zfTarget
|
|
86
|
+
|
|
87
|
+
//prepare for pan
|
|
88
|
+
const dx = xTarget - cIni.x
|
|
89
|
+
const dy = yTarget - cIni.y
|
|
90
|
+
let d = Math.hypot(dx, dy)
|
|
91
|
+
const ddx = (progressFactorPix * zfIni * dx) / d
|
|
92
|
+
const ddy = (progressFactorPix * zfIni * dy) / d
|
|
93
|
+
|
|
94
|
+
//prepare for zoom
|
|
95
|
+
let r = zfTarget / zfIni
|
|
96
|
+
const n = d / (progressFactorPix * zfIni)
|
|
97
|
+
const zoomFactor = d > 0 ? Math.pow(r, 1 / n) : Math.pow(r, 1 / 10) //TODO not 10 ?
|
|
98
|
+
|
|
99
|
+
//timer
|
|
100
|
+
let timer = setInterval(() => {
|
|
101
|
+
//compute and set new position
|
|
102
|
+
if (d > 0) {
|
|
103
|
+
const c = app.getGeoCenter()
|
|
104
|
+
let nx = c.x + ddx
|
|
105
|
+
let ny = c.y + ddy
|
|
106
|
+
//if went too far, stop at target values
|
|
107
|
+
if (nx < xTarget && xTarget < c.x) nx = xTarget
|
|
108
|
+
if (c.x < xTarget && xTarget < nx) nx = xTarget
|
|
109
|
+
if (ny < yTarget && yTarget < c.y) ny = yTarget
|
|
110
|
+
if (c.y < yTarget && yTarget < ny) ny = yTarget
|
|
111
|
+
app.setGeoCenter({ x: nx, y: ny })
|
|
112
|
+
if (nx == xTarget && ny == yTarget) d = 0
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//compute and set new zoom
|
|
116
|
+
if (r != 1) {
|
|
117
|
+
const zf = app.getZoomFactor()
|
|
118
|
+
let nzf = zoomFactor * zf
|
|
119
|
+
//if went too far, stop at target values
|
|
120
|
+
if (nzf < zfTarget && zfTarget < zf) nzf = zfTarget
|
|
121
|
+
if (zf < zfTarget && zfTarget < nzf) nzf = zfTarget
|
|
122
|
+
app.setZoomFactor(nzf)
|
|
123
|
+
if (nzf == zfTarget) r = 1
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//redraw
|
|
127
|
+
app.redraw()
|
|
128
|
+
|
|
129
|
+
//if target reached, stop
|
|
130
|
+
if (d == 0 && r == 1) {
|
|
131
|
+
//console.log("OK !")
|
|
132
|
+
clearInterval(timer)
|
|
133
|
+
//trigger callback, if any
|
|
134
|
+
if (callback)
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
callback()
|
|
137
|
+
}, delayBeforeCallBackMs)
|
|
138
|
+
}
|
|
139
|
+
}, delayMs)
|
|
140
|
+
|
|
141
|
+
return timer
|
|
142
|
+
}
|