gridviz 2.1.17 → 3.0.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 +2 -3
- package/dist/gridviz.js +8659 -9294
- package/dist/gridviz.min.js +1 -1
- package/package.json +3 -2
- package/src/button/Button.js +14 -15
- package/src/button/FullscreenButton.js +14 -14
- package/src/button/ZoomButtons.js +2 -2
- package/src/{DatasetComponent.js → core/Dataset.js} +33 -13
- package/src/core/Drawable.js +60 -0
- package/src/{GeoCanvas.js → core/GeoCanvas.js} +65 -155
- package/src/core/Layer.js +24 -0
- package/src/{Legend.js → core/Legend.js} +24 -1
- package/src/core/Map.js +474 -0
- package/src/core/MultiResolutionDataset.js +96 -0
- package/src/core/Style.js +84 -0
- package/src/dataset/COGeo.js +5 -5
- package/src/dataset/CSVGrid.js +43 -41
- package/src/dataset/GeoTIFF.js +9 -14
- package/src/dataset/{LGrid.js → JSGrid.js} +9 -11
- package/src/dataset/TiledGrid.js +68 -45
- package/src/index.js +22 -29
- package/src/{BackgroundLayer.js → layer/BackgroundLayer.js} +27 -52
- package/src/{BackgroundLayerWMS.js → layer/BackgroundLayerWMS.js} +21 -45
- package/src/{LineLayer.js → layer/GeoJSONLayer.js} +22 -23
- package/src/layer/GridLayer.js +160 -0
- package/src/{LabelLayer.js → layer/LabelLayer.js} +25 -23
- package/src/legend/ColorCategoryLegend.js +9 -24
- package/src/legend/ColorDiscreteLegend.js +20 -24
- package/src/legend/ColorLegend.js +21 -33
- package/src/legend/OrientationLegend.js +90 -0
- package/src/legend/SizeLegend.js +153 -72
- package/src/style/CompositionStyle.js +71 -84
- package/src/style/ContourStyle.js +2 -36
- package/src/style/DotDensityStyle.js +50 -73
- package/src/style/IsoFenceStyle.js +59 -70
- package/src/style/JoyPlotStyle.js +41 -48
- package/src/style/LegoStyle.js +4 -4
- package/src/style/MosaicStyle.js +30 -39
- package/src/style/NinjaStarStyle.js +45 -68
- package/src/style/PillarStyle.js +70 -93
- package/src/style/SegmentStyle.js +37 -75
- package/src/style/ShapeColorSizeStyle.js +49 -98
- package/src/style/SideCategoryStyle.js +112 -0
- package/src/style/SideStyle.js +99 -133
- package/src/style/{SquareColorCatWGLStyle.js → SquareColorCategoryWebGLStyle.js} +28 -41
- package/src/style/{SquareColorWGLStyle.js → SquareColorWebGLStyle.js} +28 -49
- package/src/style/StrokeStyle.js +43 -70
- package/src/style/TanakaStyle.js +34 -132
- package/src/style/TextStyle.js +43 -64
- package/src/style/TimeSeriesStyle.js +44 -75
- package/src/utils/WebGLSquareColoringAdvanced.js +4 -4
- package/src/utils/scale.js +217 -0
- package/src/utils/stretching.js +86 -129
- package/src/utils/{Utils.js → utils.js} +15 -0
- package/src/utils/webGLUtils.js +4 -5
- package/src/utils/zoomUtils.js +30 -30
- package/src/App.js +0 -760
- package/src/Dataset.js +0 -76
- package/src/Layer.js +0 -103
- package/src/Style.js +0 -131
- package/src/dataset/GridTile.js +0 -41
- package/src/legend/SegmentOrientationLegend.js +0 -87
- package/src/legend/SegmentWidthLegend.js +0 -101
- package/src/style/CompositionStyle_.js +0 -293
- package/src/style/ShapeColorSizeStyle_.js +0 -108
- package/src/style/SideCatStyle.js +0 -172
- /package/src/{Tooltip.js → core/Tooltip.js} +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
import { Style } from '../Style.js'
|
|
4
|
+
import { Style } from '../core/Style.js'
|
|
5
5
|
import { randomNormal } from 'd3-random'
|
|
6
6
|
import { checkWebGLSupport, makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
7
7
|
import { WebGLSquareColoring } from '../utils/WebGLSquareColoring.js'
|
|
8
8
|
import { color } from 'd3-color'
|
|
9
|
-
import { monitor, monitorDuration } from '../utils/Utils.js'
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
*
|
|
@@ -18,139 +17,117 @@ export class DotDensityStyle extends Style {
|
|
|
18
17
|
super(opts)
|
|
19
18
|
opts = opts || {}
|
|
20
19
|
|
|
21
|
-
/** The name of the column/attribute of the tabular data where to retrieve the variable for dot number.
|
|
22
|
-
* @type {string} */
|
|
23
|
-
this.nbCol = opts.nbCol
|
|
24
|
-
|
|
25
20
|
/** A function returning the number of dots for a cell value.
|
|
26
|
-
* @type {function(
|
|
27
|
-
this.
|
|
21
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
|
|
22
|
+
this.dotNumber = opts.dotNumber || ((cell, resolution) => resolution / 100)//(c,r,z,vs) => {}
|
|
28
23
|
|
|
29
24
|
/** The color of the dots. Same color for all dots within a cell.
|
|
30
|
-
* @type {function(import(
|
|
31
|
-
this.color = opts.color || (() => '#FF5733')
|
|
25
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, object):string} */
|
|
26
|
+
this.color = opts.color || (() => '#FF5733') //(c,r,z,vs) => {}
|
|
32
27
|
|
|
33
|
-
/** A function returning the size of the dots, in geo unit.
|
|
34
|
-
* @type {function(number,number):number} */
|
|
35
|
-
this.dotSize = opts.dotSize
|
|
28
|
+
/** A function returning the size of the dots, in geo unit. Same size for all cells.
|
|
29
|
+
* @type {function(number, number,object):number} */
|
|
30
|
+
this.dotSize = opts.dotSize || ((resolution, z) => 1.5 * z) //(c,r,z,vs) => {}
|
|
36
31
|
|
|
37
|
-
/** A function returning the sigma of the distribution
|
|
38
|
-
* @type {function(number,number):number} */
|
|
39
|
-
this.sigma = opts.sigma
|
|
32
|
+
/** A function returning the sigma of the dots distribution. Same value for all cells.
|
|
33
|
+
* @type {function(number, number,object):number} */
|
|
34
|
+
this.sigma = opts.sigma || ((resolution, z) => resolution / 2)//(c,r,z,vs) => {}
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
/**
|
|
43
38
|
* Draw cells as text.
|
|
44
39
|
*
|
|
45
|
-
* @param {Array.<import("../Dataset").Cell>} cells
|
|
46
|
-
* @param {
|
|
47
|
-
* @param {
|
|
40
|
+
* @param {Array.<import("../core/Dataset").Cell>} cells
|
|
41
|
+
* @param {import("../core/GeoCanvas").GeoCanvas} geoCanvas
|
|
42
|
+
* @param {number} resolution
|
|
48
43
|
*/
|
|
49
|
-
draw(cells,
|
|
50
|
-
if (monitor) monitorDuration('*** DotDensityStyle draw')
|
|
44
|
+
draw(cells, geoCanvas, resolution) {
|
|
51
45
|
|
|
52
46
|
//filter
|
|
53
47
|
if (this.filter) cells = cells.filter(this.filter)
|
|
54
48
|
|
|
55
|
-
//
|
|
56
|
-
const
|
|
49
|
+
//
|
|
50
|
+
const z = geoCanvas.view.z
|
|
57
51
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!stat) return
|
|
52
|
+
//get view scale
|
|
53
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
61
54
|
|
|
62
|
-
//size
|
|
63
|
-
const sGeo = this.dotSize ? this.dotSize(
|
|
55
|
+
//get size
|
|
56
|
+
const sGeo = this.dotSize ? this.dotSize(resolution, z, viewScale) : z
|
|
64
57
|
|
|
65
58
|
//make random function
|
|
66
|
-
const sig = this.sigma ? this.sigma(
|
|
59
|
+
const sig = this.sigma ? this.sigma(resolution, z, viewScale) : resolution * 0.4
|
|
67
60
|
const rand = randomNormal(0, sig)
|
|
68
61
|
|
|
69
|
-
if (monitor) monitorDuration(' preparation')
|
|
70
|
-
|
|
71
62
|
if (checkWebGLSupport()) {
|
|
72
63
|
//create canvas and webgl renderer
|
|
73
|
-
const cvWGL = makeWebGLCanvas(
|
|
64
|
+
const cvWGL = makeWebGLCanvas(geoCanvas.w + '', geoCanvas.h + '')
|
|
74
65
|
if (!cvWGL) {
|
|
75
66
|
console.error('No webGL')
|
|
76
67
|
return
|
|
77
68
|
}
|
|
78
69
|
|
|
79
70
|
//create webGL program
|
|
80
|
-
const prog = new WebGLSquareColoring(cvWGL.gl, sGeo /
|
|
71
|
+
const prog = new WebGLSquareColoring(cvWGL.gl, sGeo / z)
|
|
81
72
|
|
|
82
|
-
|
|
73
|
+
const r2 = resolution / 2
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let col, offset, nb, cx, cy, cc
|
|
87
|
-
for (let c of cells) {
|
|
75
|
+
for (let cell of cells) {
|
|
88
76
|
//get color
|
|
89
|
-
col = this.color(
|
|
77
|
+
const col = this.color(cell, resolution, z, viewScale)
|
|
90
78
|
if (!col || col === 'none') continue
|
|
91
79
|
|
|
92
|
-
//get offset
|
|
93
|
-
offset = this.offset(c, r, zf)
|
|
94
|
-
|
|
95
80
|
//number of dots
|
|
96
|
-
|
|
81
|
+
const dotNumber = this.dotNumber(cell, resolution, z, viewScale)
|
|
82
|
+
|
|
83
|
+
//get offset
|
|
84
|
+
const offset = this.offset(cell, resolution, z)
|
|
97
85
|
|
|
98
86
|
//cell center
|
|
99
|
-
cx =
|
|
100
|
-
cy =
|
|
87
|
+
const cx = cell.x + offset.dx + r2
|
|
88
|
+
const cy = cell.y + offset.dy + r2
|
|
101
89
|
|
|
102
90
|
//convert color
|
|
103
|
-
cc = color(col)
|
|
91
|
+
const cc = color(col)
|
|
104
92
|
if (!cc) return
|
|
105
93
|
|
|
106
94
|
//random points
|
|
107
|
-
for (let i = 0; i <=
|
|
95
|
+
for (let i = 0; i <= dotNumber; i++)
|
|
108
96
|
prog.addPointData2(cx + rand(), cy + rand(), cc.r, cc.g, cc.b, cc.opacity)
|
|
109
97
|
}
|
|
110
98
|
|
|
111
|
-
if (monitor) monitorDuration(' data preparation')
|
|
112
|
-
|
|
113
99
|
//draw
|
|
114
|
-
prog.draw(
|
|
115
|
-
|
|
116
|
-
if (monitor) monitorDuration(' webgl drawing')
|
|
100
|
+
prog.draw(geoCanvas.getWebGLTransform())
|
|
117
101
|
|
|
118
102
|
//draw in canvas geo
|
|
119
|
-
|
|
120
|
-
|
|
103
|
+
geoCanvas.initCanvasTransform()
|
|
104
|
+
geoCanvas.ctx.drawImage(cvWGL.canvas, 0, 0)
|
|
121
105
|
|
|
122
|
-
if (monitor) monitorDuration(' canvas drawing')
|
|
123
106
|
} else {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
//draw in geo coordinates
|
|
127
|
-
cg.setCanvasTransform()
|
|
107
|
+
for (let cell of cells) {
|
|
128
108
|
|
|
129
|
-
for (let c of cells) {
|
|
130
109
|
//get color
|
|
131
|
-
const col = this.color(
|
|
110
|
+
const col = this.color(cell, resolution, z, viewScale)
|
|
132
111
|
if (!col || col === 'none') continue
|
|
133
112
|
//set color
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
//get offset
|
|
137
|
-
const offset = this.offset(c, r, zf)
|
|
113
|
+
geoCanvas.ctx.fillStyle = col
|
|
138
114
|
|
|
139
115
|
//number of dots
|
|
140
|
-
const
|
|
116
|
+
const dotNumber = this.dotNumber(cell, resolution, z, viewScale)
|
|
117
|
+
|
|
118
|
+
//get offset
|
|
119
|
+
const offset = this.offset(cell, resolution, z)
|
|
141
120
|
|
|
142
121
|
//draw random dots
|
|
143
|
-
const cx =
|
|
144
|
-
cy =
|
|
145
|
-
for (let i = 0; i <=
|
|
146
|
-
|
|
122
|
+
const cx = cell.x + offset.dx + resolution / 2,
|
|
123
|
+
cy = cell.y + offset.dy + resolution / 2
|
|
124
|
+
for (let i = 0; i <= dotNumber; i++) {
|
|
125
|
+
geoCanvas.ctx.fillRect(cx + rand(), cy + rand(), sGeo, sGeo)
|
|
147
126
|
}
|
|
148
127
|
}
|
|
149
128
|
}
|
|
150
129
|
|
|
151
130
|
//update legends
|
|
152
|
-
this.updateLegends({ style: this,
|
|
153
|
-
|
|
154
|
-
if (monitor) monitorDuration('*** DotDensityStyle end draw')
|
|
131
|
+
this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
|
|
155
132
|
}
|
|
156
133
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
import { Style } from '../Style.js'
|
|
4
|
+
import { Style } from '../core/Style.js'
|
|
5
|
+
import { SideStyle } from './SideStyle.js'
|
|
5
6
|
|
|
6
|
-
/** @typedef {{x:number,y:number,or:"v"|"h",c1:import('../Dataset.js').Cell|undefined,c2:import('../Dataset.js').Cell|undefined}} Side */
|
|
7
|
+
/** @typedef {{x:number,y:number,or:"v"|"h",c1:import('../core/Dataset.js').Cell|undefined,c2:import('../core/Dataset.js').Cell|undefined}} Side */
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @author Julien Gaffuri
|
|
@@ -20,25 +21,21 @@ export class IsoFenceStyle extends Style {
|
|
|
20
21
|
* @type {object} */
|
|
21
22
|
this.color = opts.color
|
|
22
23
|
|
|
23
|
-
/**
|
|
24
|
-
* @type {
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
/** A function returning the height of a cell.
|
|
28
|
-
* @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
29
|
-
this.height = opts.height || ((v, r, s, zf) => r * 0.4)
|
|
24
|
+
/** A function returning the height of a cell in geographical unit.
|
|
25
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
|
|
26
|
+
this.height = opts.height || ((cell, resolution, z, viewScale) => resolution * 0.4)
|
|
30
27
|
|
|
31
28
|
/** The perspective angle, in degree, within [-180,180], from [O,x] axis.
|
|
32
29
|
* @type {number} */
|
|
33
30
|
this.angle = opts.angle != undefined ? opts.angle : 50
|
|
34
31
|
|
|
35
32
|
/** A function returning the corner line stroke style.
|
|
36
|
-
* @type {function(import('../Dataset.js').Cell,number,number,number):string} */
|
|
37
|
-
this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r,
|
|
33
|
+
* @type {function(import('../core/Dataset.js').Cell,number,number,number):string} */
|
|
34
|
+
this.cornerLineStrokeColor = opts.cornerLineStrokeColor || ((c, r, z, angle) => "#999")
|
|
38
35
|
|
|
39
36
|
/** A function returning the corner line width.
|
|
40
|
-
* @type {function(import('../Dataset.js').Cell,number,number,number):number} */
|
|
41
|
-
this.cornerLineWidth = opts.cornerLineWidth || ((c, r,
|
|
37
|
+
* @type {function(import('../core/Dataset.js').Cell,number,number,number):number} */
|
|
38
|
+
this.cornerLineWidth = opts.cornerLineWidth || ((c, r, z, angle) => (angle % 90 == 0 ? 0 : 0.8 * z))
|
|
42
39
|
|
|
43
40
|
/**
|
|
44
41
|
* Show vertical cross-sections.
|
|
@@ -52,44 +49,39 @@ export class IsoFenceStyle extends Style {
|
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* @param {
|
|
58
|
-
* @
|
|
59
|
-
* @param {import("../GeoCanvas.js").GeoCanvas} cg
|
|
52
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
53
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
54
|
+
* @param {number} resolution
|
|
55
|
+
* @override
|
|
60
56
|
*/
|
|
61
|
-
draw(cells,
|
|
57
|
+
draw(cells, geoCanvas, resolution) {
|
|
58
|
+
|
|
62
59
|
//filter
|
|
63
60
|
if (this.filter) cells = cells.filter(this.filter)
|
|
64
61
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
62
|
+
//
|
|
63
|
+
const z = geoCanvas.view.z
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//if size is used, sort cells by size so that the biggest are drawn first
|
|
71
|
-
cells.sort((c1, c2) => c2[this.heightCol] - c1[this.heightCol])
|
|
72
|
-
//and compute statistics
|
|
73
|
-
stat = Style.getStatistics(cells, (c) => c[this.heightCol], true)
|
|
74
|
-
}
|
|
65
|
+
//get view scale
|
|
66
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
75
67
|
|
|
76
68
|
//nb categories - used for radar and agepyramid
|
|
77
69
|
const cats = Object.keys(this.color)
|
|
78
70
|
|
|
79
71
|
//half resolution
|
|
80
|
-
const r2 =
|
|
72
|
+
const r2 = resolution / 2
|
|
81
73
|
|
|
82
74
|
//get offset
|
|
83
75
|
// @ts-ignore
|
|
84
|
-
const offset = this.offset(undefined,
|
|
85
|
-
|
|
86
|
-
//height
|
|
87
|
-
/** @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
88
|
-
let h_ = this.height
|
|
76
|
+
const offset = this.offset(undefined, resolution, z), dx = offset.dx, dy = offset.dy
|
|
89
77
|
|
|
90
78
|
//make sides
|
|
91
79
|
/** @type {Array.<Side>} */
|
|
92
|
-
const sides =
|
|
80
|
+
const sides = SideStyle.buildSides(cells, resolution, this.angle % 180 != 90 && this.sVert, this.angle % 180 != 0 && this.sHor, true)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/*const sides = []
|
|
93
85
|
|
|
94
86
|
//make horizontal sides - except when angle%180=0
|
|
95
87
|
//sort cells by x and y
|
|
@@ -99,14 +91,14 @@ export class IsoFenceStyle extends Style {
|
|
|
99
91
|
for (let i = 1; i < cells.length; i++) {
|
|
100
92
|
let c2 = cells[i]
|
|
101
93
|
|
|
102
|
-
if ((c1.y +
|
|
94
|
+
if ((c1.y + resolution == c2.y) && (c1.x == c2.x))
|
|
103
95
|
//cells in same column and touch along horizontal side
|
|
104
96
|
//make shared side
|
|
105
97
|
sides.push({ x: c1.x + r2, y: c2.y, or: 'h', c1: c1, c2: c2 })
|
|
106
98
|
else {
|
|
107
99
|
//cells do not touch along horizontal side
|
|
108
100
|
//make two sides: top one for c1, bottom for c2
|
|
109
|
-
sides.push({ x: c1.x + r2, y: c1.y +
|
|
101
|
+
sides.push({ x: c1.x + r2, y: c1.y + resolution, or: 'h', c1: c1, c2: undefined })
|
|
110
102
|
sides.push({ x: c2.x + r2, y: c2.y, or: 'h', c1: undefined, c2: c2 })
|
|
111
103
|
}
|
|
112
104
|
|
|
@@ -122,20 +114,20 @@ export class IsoFenceStyle extends Style {
|
|
|
122
114
|
for (let i = 1; i < cells.length; i++) {
|
|
123
115
|
let c2 = cells[i]
|
|
124
116
|
|
|
125
|
-
if ((c1.x +
|
|
117
|
+
if ((c1.x + resolution == c2.x) && (c1.y == c2.y))
|
|
126
118
|
//cells in same row and touch along vertical side
|
|
127
119
|
//make shared side
|
|
128
120
|
sides.push({ x: c2.x, y: c1.y + r2, or: 'v', c1: c1, c2: c2 })
|
|
129
121
|
else {
|
|
130
122
|
//cells do not touch along vertical side
|
|
131
123
|
//make two sides: right one for c1, left for c2
|
|
132
|
-
sides.push({ x: c1.x +
|
|
124
|
+
sides.push({ x: c1.x + resolution, y: c1.y + r2, or: 'v', c1: c1, c2: undefined })
|
|
133
125
|
sides.push({ x: c2.x, y: c2.y + r2, or: 'v', c1: undefined, c2: c2 })
|
|
134
126
|
}
|
|
135
127
|
|
|
136
128
|
c1 = c2
|
|
137
129
|
}
|
|
138
|
-
}
|
|
130
|
+
}*/
|
|
139
131
|
|
|
140
132
|
//
|
|
141
133
|
if (sides.length == 0) return
|
|
@@ -145,40 +137,37 @@ export class IsoFenceStyle extends Style {
|
|
|
145
137
|
|
|
146
138
|
//sort sides so that the back ones are drawn first. This depends on the angle.
|
|
147
139
|
//depending on distance to the reference corner point
|
|
148
|
-
const xCorner = Math.abs(this.angle) < 90 ?
|
|
149
|
-
const yCorner = this.angle < 0 ?
|
|
140
|
+
const xCorner = Math.abs(this.angle) < 90 ? geoCanvas.extGeo.xMin : geoCanvas.extGeo.xMax
|
|
141
|
+
const yCorner = this.angle < 0 ? geoCanvas.extGeo.yMax : geoCanvas.extGeo.yMin
|
|
150
142
|
sides.sort((s1, s2) => (Math.hypot(s2.x - xCorner, s2.y - yCorner) - Math.hypot(s1.x - xCorner, s1.y - yCorner)))
|
|
151
143
|
|
|
152
144
|
//prepare function to draw corner line for a cell *c*
|
|
153
|
-
const drawCornerLine = (
|
|
145
|
+
const drawCornerLine = (cell) => {
|
|
154
146
|
|
|
155
|
-
if (!
|
|
147
|
+
if (!cell) return
|
|
156
148
|
//line style
|
|
157
|
-
const lw = this.cornerLineWidth ? this.cornerLineWidth(
|
|
149
|
+
const lw = this.cornerLineWidth ? this.cornerLineWidth(cell, resolution, z, this.angle) : 0.8 * z
|
|
158
150
|
if (lw == 0) return
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
geoCanvas.ctx.strokeStyle = this.cornerLineStrokeColor ? this.cornerLineStrokeColor(cell, resolution, z, this.angle) : "#333"
|
|
152
|
+
geoCanvas.ctx.lineWidth = lw
|
|
161
153
|
|
|
162
154
|
//height - in geo
|
|
163
|
-
const hG =
|
|
155
|
+
const hG = this.height(cell, resolution, z, viewScale)
|
|
164
156
|
|
|
165
157
|
//draw line
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
158
|
+
geoCanvas.ctx.beginPath()
|
|
159
|
+
geoCanvas.ctx.moveTo(cell.x + r2 + dx, cell.y + r2 + dy)
|
|
160
|
+
geoCanvas.ctx.lineTo(cell.x + r2 + hG * cos + dx, cell.y + r2 + hG * sin + dy)
|
|
161
|
+
geoCanvas.ctx.stroke()
|
|
170
162
|
}
|
|
171
163
|
|
|
172
|
-
//draw in geo coordinates
|
|
173
|
-
cg.setCanvasTransform()
|
|
174
|
-
|
|
175
164
|
//draw sides
|
|
176
|
-
|
|
165
|
+
geoCanvas.ctx.lineCap = "round";
|
|
177
166
|
for (let s of sides) {
|
|
178
167
|
|
|
179
168
|
//heights - in geo
|
|
180
|
-
const hG1 = s.c1 ?
|
|
181
|
-
hG2 = s.c2 ?
|
|
169
|
+
const hG1 = s.c1 ? this.height(s.c1, resolution, z, viewScale) : 0,
|
|
170
|
+
hG2 = s.c2 ? this.height(s.c2, resolution, z, viewScale) : 0
|
|
182
171
|
|
|
183
172
|
//compute totals for both cells
|
|
184
173
|
const total1 = computeTotal(s.c1, cats),
|
|
@@ -201,33 +190,33 @@ export class IsoFenceStyle extends Style {
|
|
|
201
190
|
const h2n = hG2 * (cumul2 + v2) / total2 || 0
|
|
202
191
|
|
|
203
192
|
//make path
|
|
204
|
-
|
|
193
|
+
geoCanvas.ctx.beginPath()
|
|
205
194
|
if (s.or == "h") {
|
|
206
195
|
//horizontal side - vertical section
|
|
207
196
|
//bottom left
|
|
208
|
-
|
|
197
|
+
geoCanvas.ctx.moveTo(s.x + h1 * cos + dx, s.y - r2 + h1 * sin + dy)
|
|
209
198
|
//top left
|
|
210
|
-
|
|
199
|
+
geoCanvas.ctx.lineTo(s.x + h2 * cos + dx, s.y + r2 + h2 * sin + dy)
|
|
211
200
|
//top right
|
|
212
|
-
|
|
201
|
+
geoCanvas.ctx.lineTo(s.x + h2n * cos + dx, s.y + r2 + h2n * sin + dy)
|
|
213
202
|
//bottom right
|
|
214
|
-
|
|
203
|
+
geoCanvas.ctx.lineTo(s.x + h1n * cos + dx, s.y - r2 + h1n * sin + dy)
|
|
215
204
|
} else {
|
|
216
205
|
//vertical side - horizontal section
|
|
217
206
|
//bottom left
|
|
218
|
-
|
|
207
|
+
geoCanvas.ctx.moveTo(s.x - r2 + h1 * cos + dx, s.y + h1 * sin + dy)
|
|
219
208
|
//bottom right
|
|
220
|
-
|
|
209
|
+
geoCanvas.ctx.lineTo(s.x + r2 + h2 * cos + dx, s.y + h2 * sin + dy)
|
|
221
210
|
//top right
|
|
222
|
-
|
|
211
|
+
geoCanvas.ctx.lineTo(s.x + r2 + h2n * cos + dx, s.y + h2n * sin + dy)
|
|
223
212
|
//top left
|
|
224
|
-
|
|
213
|
+
geoCanvas.ctx.lineTo(s.x - r2 + h1n * cos + dx, s.y + h1n * sin + dy)
|
|
225
214
|
}
|
|
226
215
|
//cg.ctx.closePath()
|
|
227
216
|
|
|
228
217
|
//fill
|
|
229
|
-
|
|
230
|
-
|
|
218
|
+
geoCanvas.ctx.fillStyle = color
|
|
219
|
+
geoCanvas.ctx.fill()
|
|
231
220
|
|
|
232
221
|
cumul1 += v1
|
|
233
222
|
cumul2 += v2
|
|
@@ -244,7 +233,7 @@ export class IsoFenceStyle extends Style {
|
|
|
244
233
|
}
|
|
245
234
|
|
|
246
235
|
//update legends
|
|
247
|
-
this.updateLegends({ style: this,
|
|
236
|
+
this.updateLegends({ style: this, resolution: resolution, z: z, viewScale: viewScale })
|
|
248
237
|
}
|
|
249
238
|
}
|
|
250
239
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
|
-
import { Style } from '../Style.js'
|
|
4
|
+
import { Style } from '../core/Style.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
*
|
|
@@ -13,43 +13,38 @@ export class JoyPlotStyle extends Style {
|
|
|
13
13
|
super(opts)
|
|
14
14
|
opts = opts || {}
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* @type {
|
|
18
|
-
this.
|
|
19
|
-
|
|
20
|
-
/** A function returning the height of a cell.
|
|
21
|
-
* @type {function(number,number,import("../Style").Stat|undefined,number):number} */
|
|
22
|
-
this.height = opts.height || ((v) => Math.sqrt(v))
|
|
16
|
+
/** A function returning the height of a cell in geographical unit.
|
|
17
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, object):number} */
|
|
18
|
+
this.height = opts.height || ((c, r) => r * Math.random()) //(c,r,z,vs) => {}
|
|
23
19
|
|
|
24
20
|
/**
|
|
25
21
|
* @type {function(number,{min:number, max:number},number,number):string} */
|
|
26
|
-
this.lineColor = opts.lineColor || ((y, ys, r,
|
|
22
|
+
this.lineColor = opts.lineColor || ((y, ys, r, z) => '#BBB')
|
|
27
23
|
/**
|
|
28
24
|
* @type {function(number,{min:number, max:number},number,number):number} */
|
|
29
|
-
this.lineWidth = opts.lineWidth || ((y, ys, r,
|
|
25
|
+
this.lineWidth = opts.lineWidth || ((y, ys, r, z) => z)
|
|
30
26
|
/**
|
|
31
27
|
* @type {function(number,{min:number, max:number},number,number):string} */
|
|
32
|
-
this.fillColor = opts.fillColor || ((y, ys, r,
|
|
28
|
+
this.fillColor = opts.fillColor || ((y, ys, r, z) => '#c08c5968')
|
|
33
29
|
}
|
|
34
30
|
|
|
31
|
+
|
|
35
32
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @param {
|
|
39
|
-
* @
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
34
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
35
|
+
* @param {number} resolution
|
|
36
|
+
* @override
|
|
37
|
+
*/
|
|
38
|
+
draw(cells, geoCanvas, resolution) {
|
|
39
|
+
|
|
43
40
|
//filter
|
|
44
41
|
if (this.filter) cells = cells.filter(this.filter)
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
//
|
|
44
|
+
const z = geoCanvas.view.z
|
|
47
45
|
|
|
48
|
-
//
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
//compute statistics
|
|
52
|
-
const stat = Style.getStatistics(cells, (c) => c[this.heightCol], true)
|
|
46
|
+
//get view scale
|
|
47
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
53
48
|
|
|
54
49
|
//index cells by y and x
|
|
55
50
|
/** @type {object} */
|
|
@@ -60,25 +55,23 @@ export class JoyPlotStyle extends Style {
|
|
|
60
55
|
row = {}
|
|
61
56
|
ind[cell.y] = row
|
|
62
57
|
}
|
|
63
|
-
row[cell.x] = this.height(cell
|
|
58
|
+
row[cell.x] = this.height(cell, resolution, z, viewScale)
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
//compute extent
|
|
67
|
-
const e =
|
|
62
|
+
const e = geoCanvas.extGeo
|
|
68
63
|
if (!e) return
|
|
69
|
-
const xMin = Math.floor(e.xMin /
|
|
70
|
-
const xMax = Math.floor(e.xMax /
|
|
71
|
-
const yMin = Math.floor(e.yMin /
|
|
72
|
-
const yMax = Math.floor(e.yMax /
|
|
64
|
+
const xMin = Math.floor(e.xMin / resolution) * resolution
|
|
65
|
+
const xMax = Math.floor(e.xMax / resolution) * resolution
|
|
66
|
+
const yMin = Math.floor(e.yMin / resolution) * resolution
|
|
67
|
+
const yMax = Math.floor(e.yMax / resolution) * resolution
|
|
73
68
|
|
|
74
69
|
/** @type {{min:number, max:number}} */
|
|
75
70
|
const ys = { min: yMin, max: yMax }
|
|
76
71
|
|
|
77
|
-
//draw in geo coordinates
|
|
78
|
-
cg.setCanvasTransform()
|
|
79
|
-
|
|
80
72
|
//draw lines, row by row, stating from the top
|
|
81
|
-
|
|
73
|
+
geoCanvas.ctx.lineJoin = 'round'
|
|
74
|
+
for (let y = yMax; y >= yMin; y -= resolution) {
|
|
82
75
|
//get row
|
|
83
76
|
const row = ind[y]
|
|
84
77
|
|
|
@@ -86,15 +79,15 @@ export class JoyPlotStyle extends Style {
|
|
|
86
79
|
if (!row) continue
|
|
87
80
|
|
|
88
81
|
//place first point
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
geoCanvas.ctx.beginPath()
|
|
83
|
+
geoCanvas.ctx.moveTo(xMin - resolution / 2, y)
|
|
91
84
|
|
|
92
85
|
//store the previous height
|
|
93
86
|
/** @type {number|undefined} */
|
|
94
87
|
let hG_
|
|
95
88
|
|
|
96
89
|
//go through the line cells
|
|
97
|
-
for (let x = xMin; x <= xMax; x +=
|
|
90
|
+
for (let x = xMin; x <= xMax; x += resolution) {
|
|
98
91
|
//get column value
|
|
99
92
|
/** @type {number} */
|
|
100
93
|
let hG = row[x]
|
|
@@ -103,32 +96,32 @@ export class JoyPlotStyle extends Style {
|
|
|
103
96
|
if (hG || hG_) {
|
|
104
97
|
//draw line only when at least one of both values is non-null
|
|
105
98
|
//TODO test bezierCurveTo
|
|
106
|
-
|
|
99
|
+
geoCanvas.ctx.lineTo(x + resolution / 2, y + hG)
|
|
107
100
|
} else {
|
|
108
101
|
//else move the point
|
|
109
|
-
|
|
102
|
+
geoCanvas.ctx.moveTo(x + resolution / 2, y)
|
|
110
103
|
}
|
|
111
104
|
//store the previous value
|
|
112
105
|
hG_ = hG
|
|
113
106
|
}
|
|
114
107
|
|
|
115
108
|
//last point
|
|
116
|
-
if (hG_)
|
|
109
|
+
if (hG_) geoCanvas.ctx.lineTo(xMax + resolution / 2, y)
|
|
117
110
|
|
|
118
111
|
//draw fill
|
|
119
|
-
const fc = this.fillColor(y, ys,
|
|
112
|
+
const fc = this.fillColor(y, ys, resolution, z)
|
|
120
113
|
if (fc && fc != 'none') {
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
geoCanvas.ctx.fillStyle = fc
|
|
115
|
+
geoCanvas.ctx.fill()
|
|
123
116
|
}
|
|
124
117
|
|
|
125
118
|
//draw line
|
|
126
|
-
const lc = this.lineColor(y, ys,
|
|
127
|
-
const lw = this.lineWidth(y, ys,
|
|
119
|
+
const lc = this.lineColor(y, ys, resolution, z)
|
|
120
|
+
const lw = this.lineWidth(y, ys, resolution, z)
|
|
128
121
|
if (lc && lc != 'none' && lw > 0) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
geoCanvas.ctx.strokeStyle = lc
|
|
123
|
+
geoCanvas.ctx.lineWidth = lw
|
|
124
|
+
geoCanvas.ctx.stroke()
|
|
132
125
|
}
|
|
133
126
|
}
|
|
134
127
|
}
|
package/src/style/LegoStyle.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import { TanakaStyle } from './TanakaStyle.js'
|
|
5
5
|
import { StrokeStyle } from './StrokeStyle.js'
|
|
6
|
-
import {
|
|
7
|
-
import { Style } from '../Style.js'
|
|
6
|
+
import { SquareColorCategoryWebGLStyle } from './SquareColorCategoryWebGLStyle.js'
|
|
7
|
+
import { Style } from '../core/Style.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @author Julien Gaffuri
|
|
@@ -67,7 +67,7 @@ export class LegoStyle {
|
|
|
67
67
|
opts.colBright = opts.colBright || '#aaa'
|
|
68
68
|
|
|
69
69
|
//
|
|
70
|
-
const s = new
|
|
70
|
+
const s = new SquareColorCategoryWebGLStyle({ colorCol: col, color: opts.color })
|
|
71
71
|
//style to show limits between pieces
|
|
72
72
|
const sst = new StrokeStyle({ strokeColor: () => '#666', strokeWidth: (v, r, s, z) => 0.2 * z })
|
|
73
73
|
|
|
@@ -91,7 +91,7 @@ class LegoTopStyle extends Style {
|
|
|
91
91
|
//filter
|
|
92
92
|
if (this.filter) cells = cells.filter(this.filter)
|
|
93
93
|
|
|
94
|
-
cg.ctx.lineWidth = 0.6 * cg.
|
|
94
|
+
cg.ctx.lineWidth = 0.6 * cg.view.z
|
|
95
95
|
|
|
96
96
|
//dark part
|
|
97
97
|
cg.ctx.strokeStyle = this.colDark
|