@lgv/visualization-map 0.0.8 → 1.0.0
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/example/favicon.ico +0 -0
- package/example/index.html +78 -0
- package/example/main.js +143 -0
- package/example/style.css +55 -0
- package/example/webpack.common.js +38 -0
- package/example/webpack.dev.js +42 -0
- package/example/webpack.prod.js +19 -0
- package/package.json +14 -13
- package/src/configuration.js +1 -6
- package/src/index.js +3 -5
- package/src/visualization/index.js +71 -48
- package/webpack.common.js +1 -1
- package/src/layout/heat.js +0 -59
- package/src/visualization/cluster.js +0 -63
- package/src/visualization/heatmap.js +0 -153
- package/src/visualization/marker-cluster.css +0 -108
- package/src/visualization/route.js +0 -52
|
Binary file
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Map</title>
|
|
5
|
+
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
6
|
+
<link href="style.css" rel="stylesheet" />
|
|
7
|
+
<script src="main.js" defer="defer" type="module"></script>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
|
|
12
|
+
<header>
|
|
13
|
+
|
|
14
|
+
<hgroup>
|
|
15
|
+
<h1>Map</h1>
|
|
16
|
+
<p>@lgv</p>
|
|
17
|
+
</hgroup>
|
|
18
|
+
|
|
19
|
+
<div>
|
|
20
|
+
<a target="_blank" href="https://gitlab.com/lgensinger/visualization-map">git</a>
|
|
21
|
+
<a target="_blank" href="https://www.npmjs.com/package/@lgv/visualization-map">npm</a>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
<main>
|
|
27
|
+
|
|
28
|
+
<figure></figure>
|
|
29
|
+
|
|
30
|
+
<section>
|
|
31
|
+
<h1>Source Data</h1>
|
|
32
|
+
<p>Minimal required to render visualization.</p>
|
|
33
|
+
<pre><code></code></pre>
|
|
34
|
+
</section>
|
|
35
|
+
|
|
36
|
+
<section>
|
|
37
|
+
<h1>Events</h1>
|
|
38
|
+
<table>
|
|
39
|
+
<thead>
|
|
40
|
+
<th>element</th>
|
|
41
|
+
<th>name</th>
|
|
42
|
+
<th>description</th>
|
|
43
|
+
</thead>
|
|
44
|
+
<tbody>
|
|
45
|
+
<tr>
|
|
46
|
+
<td>circle</td>
|
|
47
|
+
<td>bubble-click</td>
|
|
48
|
+
<td>onclick for an individual svg circle element</td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td>circle</td>
|
|
52
|
+
<td>bubble-mouseover</td>
|
|
53
|
+
<td>mouseover for an individual svg circle element</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td>circle</td>
|
|
57
|
+
<td>bubbble-mouseout</td>
|
|
58
|
+
<td>move mouse outside the bounds of an svg circle element to clear the mouseover</td>
|
|
59
|
+
</tr>
|
|
60
|
+
</tbody>
|
|
61
|
+
</table>
|
|
62
|
+
<pre><code></code></pre>
|
|
63
|
+
</section>
|
|
64
|
+
|
|
65
|
+
</main>
|
|
66
|
+
|
|
67
|
+
<footer>
|
|
68
|
+
<a target="_blank" href="https://gitlab.com/lgensinger">
|
|
69
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 380 380"><defs><style>.cls-1{fill:#171321;}</style></defs><g id="LOGO"><path class="cls-1" d="M282.83,170.73l-.27-.69-26.14-68.22a6.81,6.81,0,0,0-2.69-3.24,7,7,0,0,0-8,.43,7,7,0,0,0-2.32,3.52l-17.65,54H154.29l-17.65-54A6.86,6.86,0,0,0,134.32,99a7,7,0,0,0-8-.43,6.87,6.87,0,0,0-2.69,3.24L97.44,170l-.26.69a48.54,48.54,0,0,0,16.1,56.1l.09.07.24.17,39.82,29.82,19.7,14.91,12,9.06a8.07,8.07,0,0,0,9.76,0l12-9.06,19.7-14.91,40.06-30,.1-.08A48.56,48.56,0,0,0,282.83,170.73Z"/></g></svg>
|
|
70
|
+
</a>
|
|
71
|
+
<a target="_blank" href="https://github.com/lgensinger">
|
|
72
|
+
<svg viewBox="0 0 98 96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"></svg>
|
|
73
|
+
</a>
|
|
74
|
+
</footer>
|
|
75
|
+
|
|
76
|
+
</body>
|
|
77
|
+
|
|
78
|
+
</html>
|
package/example/main.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import packageJson from "../package.json";
|
|
2
|
+
import { VisualizationMap } from "../src/index.js";
|
|
3
|
+
import { processEvent, renderDefault } from "@lgv/visualization-chart";
|
|
4
|
+
|
|
5
|
+
let data = {
|
|
6
|
+
"type": "FeatureCollection",
|
|
7
|
+
"features": [
|
|
8
|
+
{
|
|
9
|
+
"type": "Feature",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"geometry": {
|
|
12
|
+
"coordinates": [
|
|
13
|
+
[
|
|
14
|
+
[
|
|
15
|
+
-0.18311949782085435,
|
|
16
|
+
51.524112572236476
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
-0.19328128598888838,
|
|
20
|
+
51.511578089614886
|
|
21
|
+
],
|
|
22
|
+
[
|
|
23
|
+
-0.18542083599513148,
|
|
24
|
+
51.4978346986118
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
-0.15282841947237102,
|
|
28
|
+
51.505455119848165
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
-0.1558361451737369,
|
|
32
|
+
51.52401252514309
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
-0.18311949782085435,
|
|
36
|
+
51.524112572236476
|
|
37
|
+
]
|
|
38
|
+
]
|
|
39
|
+
],
|
|
40
|
+
"type": "Polygon"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "Feature",
|
|
45
|
+
"properties": {},
|
|
46
|
+
"geometry": {
|
|
47
|
+
"coordinates": [
|
|
48
|
+
[
|
|
49
|
+
[
|
|
50
|
+
-0.11372536280845225,
|
|
51
|
+
51.495850326660104
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
-0.11372536280845225,
|
|
55
|
+
51.484758714307475
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
-0.09431987304824929,
|
|
59
|
+
51.484758714307475
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
-0.09431987304824929,
|
|
63
|
+
51.495850326660104
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
-0.11372536280845225,
|
|
67
|
+
51.495850326660104
|
|
68
|
+
]
|
|
69
|
+
]
|
|
70
|
+
],
|
|
71
|
+
"type": "Polygon"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"type": "Feature",
|
|
76
|
+
"properties": {},
|
|
77
|
+
"geometry": {
|
|
78
|
+
"coordinates": [
|
|
79
|
+
[
|
|
80
|
+
[
|
|
81
|
+
-0.1074645619268324,
|
|
82
|
+
51.52894445636778
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
-0.10883628720753791,
|
|
86
|
+
51.52166505153471
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
-0.10013275748593742,
|
|
90
|
+
51.52599979138691
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
-0.1074645619268324,
|
|
94
|
+
51.52894445636778
|
|
95
|
+
]
|
|
96
|
+
]
|
|
97
|
+
],
|
|
98
|
+
"type": "Polygon"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// get elements
|
|
105
|
+
let container = document.getElementsByTagName("figure")[0];
|
|
106
|
+
let sourceContainer = document.getElementsByTagName("code")[0];
|
|
107
|
+
let outputContainer = document.getElementsByTagName("code")[1];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Render initial visualization.
|
|
111
|
+
* @param {element} container - DOM element
|
|
112
|
+
* @param {array} data - object with key/value pairs of path
|
|
113
|
+
*/
|
|
114
|
+
function startup(data,container) {
|
|
115
|
+
|
|
116
|
+
// update version in header
|
|
117
|
+
let h1 = document.querySelector("h1");
|
|
118
|
+
let title = h1.innerText;
|
|
119
|
+
h1.innerHTML = `${title} <span>v${packageJson.version}</span>`;
|
|
120
|
+
|
|
121
|
+
// render source data
|
|
122
|
+
renderDefault(data,sourceContainer,outputContainer);
|
|
123
|
+
|
|
124
|
+
// determine configs
|
|
125
|
+
let width = container.offsetWidth;
|
|
126
|
+
let height = width*0.75;
|
|
127
|
+
|
|
128
|
+
// initialize
|
|
129
|
+
const m = new VisualizationMap(null,data,width,height);
|
|
130
|
+
|
|
131
|
+
// render visualization
|
|
132
|
+
m.render(container);
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// load document
|
|
137
|
+
document.onload = startup(data,container);
|
|
138
|
+
|
|
139
|
+
// attach events
|
|
140
|
+
container.outputContainer = outputContainer;
|
|
141
|
+
//container.addEventListener("bubble-click",processEvent);
|
|
142
|
+
//container.addEventListener("bubble-mouseover", processEvent);
|
|
143
|
+
//container.addEventListener("bubble-mouseout", processEvent);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@import "~highlight.js/styles/atom-one-dark.css";
|
|
2
|
+
@import "~@lgv/visualization-chart/src/example/style/index.css";
|
|
3
|
+
|
|
4
|
+
main > hgroup {
|
|
5
|
+
align-items: center;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: space-between;
|
|
8
|
+
margin-bottom: 1em;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
main > hgroup h1 {
|
|
12
|
+
font-size: 1.5em;
|
|
13
|
+
font-weight: 700;
|
|
14
|
+
margin-right: 1em;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main hgroup div {
|
|
18
|
+
display: flex;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main button {
|
|
22
|
+
border: 0.2em;
|
|
23
|
+
border-style: solid;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
font-size: 0.75em;
|
|
26
|
+
padding: 0.5em;
|
|
27
|
+
text-transform: uppercase;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
main hgroup div button {
|
|
31
|
+
border: 0 none;
|
|
32
|
+
background: #525252;
|
|
33
|
+
border-radius: 1em;
|
|
34
|
+
color: white;
|
|
35
|
+
text-transform: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
main hgroup div button:first-of-type {
|
|
39
|
+
border-bottom-right-radius: 0;
|
|
40
|
+
border-top-right-radius: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
main hgroup div button:last-of-type {
|
|
44
|
+
background: #292929;
|
|
45
|
+
border-bottom-left-radius: 0;
|
|
46
|
+
border-top-left-radius: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main button:hover {
|
|
50
|
+
background: grey;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main figure {
|
|
54
|
+
max-width: 100%;
|
|
55
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
import HtmlBundlerPlugin from "html-bundler-webpack-plugin";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
const commonConfig = {
|
|
10
|
+
|
|
11
|
+
module: {
|
|
12
|
+
rules: [
|
|
13
|
+
{
|
|
14
|
+
test: /\.(ico|png|jp?g|svg)/,
|
|
15
|
+
type: "asset",
|
|
16
|
+
generator: { filename: "img/[name].[hash:8][ext]" },
|
|
17
|
+
parser: { dataUrlCondition: { maxSize: 2 * 1024 } }
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
output: {
|
|
23
|
+
path: path.resolve(__dirname, "dist"),
|
|
24
|
+
clean: true
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
plugins: [
|
|
28
|
+
new HtmlBundlerPlugin({
|
|
29
|
+
entry: { index: "./example/index.html" },
|
|
30
|
+
js: { filename: "[name].[contenthash:8].js" },
|
|
31
|
+
css: { filename: "[name].[contenthash:8].css" }
|
|
32
|
+
})
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export { commonConfig };
|
|
38
|
+
export default commonConfig;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
import { merge } from "webpack-merge";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
import { commonConfig as visConfig } from "../webpack.common.js";
|
|
10
|
+
import { commonConfig } from "./webpack.common.js";
|
|
11
|
+
|
|
12
|
+
const webpackConfig = merge(visConfig, commonConfig, {
|
|
13
|
+
|
|
14
|
+
devServer: {
|
|
15
|
+
allowedHosts: ["all"],
|
|
16
|
+
client: {
|
|
17
|
+
webSocketURL: {
|
|
18
|
+
hostname: "0.0.0.0",
|
|
19
|
+
pathname: "/ws",
|
|
20
|
+
password: "dev-server",
|
|
21
|
+
port: 8080,
|
|
22
|
+
protocol: "ws",
|
|
23
|
+
username: "webpack",
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
static: {
|
|
27
|
+
directory: path.resolve(__dirname, "dist"),
|
|
28
|
+
publicPath: "/"
|
|
29
|
+
},
|
|
30
|
+
watchFiles: {
|
|
31
|
+
paths: ["example/**/*.*"],
|
|
32
|
+
options: { usePolling: true },
|
|
33
|
+
},
|
|
34
|
+
webSocketServer: "ws"
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
mode: "development"
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export { webpackConfig };
|
|
42
|
+
export default webpackConfig;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { commonConfig } from "./webpack.common.js";
|
|
2
|
+
|
|
3
|
+
import { merge } from "webpack-merge";
|
|
4
|
+
|
|
5
|
+
const webpackConfig = merge(commonConfig, {
|
|
6
|
+
|
|
7
|
+
mode: "production",
|
|
8
|
+
|
|
9
|
+
output: {
|
|
10
|
+
library: {
|
|
11
|
+
name: "MapExample",
|
|
12
|
+
type: "umd"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export { webpackConfig };
|
|
19
|
+
export default webpackConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lgv/visualization-map",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "ES6 d3.js core visualization scaffold object and utilities for maps.",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "webpack build --config webpack.prod.js",
|
|
13
|
+
"build-example": "webpack build --config example/webpack.dev.js",
|
|
13
14
|
"coverage": "c8 --reporter=html --reporter=text ava --node-arguments='--experimental-json-modules'",
|
|
15
|
+
"example": "webpack serve --config example/webpack.dev.js",
|
|
14
16
|
"start": "webpack serve --config webpack.dev.js",
|
|
15
|
-
"startdocker": "webpack serve --config webpack.dev.js --host 0.0.0.0 --allowed-hosts all",
|
|
16
17
|
"test": "npx ava --verbose --serial --timeout 1m --node-arguments='--experimental-json-modules'"
|
|
17
18
|
},
|
|
18
19
|
"repository": {
|
|
@@ -20,8 +21,10 @@
|
|
|
20
21
|
"url": "https://gitlab.com/lgensinger/visualization-map.git"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
23
|
-
"
|
|
24
|
-
"
|
|
24
|
+
"d3",
|
|
25
|
+
"leaflet",
|
|
26
|
+
"vega",
|
|
27
|
+
"visualization"
|
|
25
28
|
],
|
|
26
29
|
"author": "lgensinger",
|
|
27
30
|
"license": "MIT",
|
|
@@ -30,25 +33,23 @@
|
|
|
30
33
|
},
|
|
31
34
|
"homepage": "https://gitlab.com/lgensinger/visualization-map#readme",
|
|
32
35
|
"devDependencies": {
|
|
36
|
+
"@fontsource/inter": "^5.1.0",
|
|
33
37
|
"ava": "^4.2.0",
|
|
34
38
|
"browser-env": "^3.3.0",
|
|
35
39
|
"c8": "^7.11.3",
|
|
36
|
-
"css-loader": "^
|
|
40
|
+
"css-loader": "^7.1.2",
|
|
37
41
|
"file-loader": "^6.2.0",
|
|
42
|
+
"highlight.js": "^11.10.0",
|
|
43
|
+
"html-bundler-webpack-plugin": "^4.4.1",
|
|
38
44
|
"html-webpack-plugin": "^5.3.2",
|
|
39
45
|
"style-loader": "^3.3.1",
|
|
40
46
|
"webpack": "^5.86.0",
|
|
41
47
|
"webpack-cli": "^5.1.4",
|
|
42
|
-
"webpack-dev-server": "^
|
|
48
|
+
"webpack-dev-server": "^5.0.4"
|
|
43
49
|
},
|
|
44
50
|
"dependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"
|
|
47
|
-
"@lgv/visualization-chart": "^0.3.26",
|
|
48
|
-
"@msrvida/vega-deck.gl": "^3.3.4",
|
|
49
|
-
"leaflet": "^1.9.2",
|
|
50
|
-
"leaflet.markercluster": "^1.5.3",
|
|
51
|
-
"vega": "^5.22.1"
|
|
51
|
+
"@lgv/visualization-chart": "^1.0.3",
|
|
52
|
+
"leaflet": "^1.9.4"
|
|
52
53
|
},
|
|
53
54
|
"ava": {
|
|
54
55
|
"files": [
|
package/src/configuration.js
CHANGED
|
@@ -5,16 +5,11 @@ const configuration = {
|
|
|
5
5
|
name: packagejson.name.replace("/", "-").slice(1)
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
const configurationColor = {
|
|
9
|
-
p1: ["#0a86ca", "#0a86ca"],
|
|
10
|
-
p2: ["#F7BBB5", "#F37765", "#EF4223", "#992B20", "#37150E"]
|
|
11
|
-
};
|
|
12
|
-
|
|
13
8
|
const configurationLayout = {
|
|
14
9
|
height: process.env.LGV_HEIGHT || 400,
|
|
15
10
|
tileserver: process.env.LGV_TILESERVER || "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
16
11
|
width: process.env.LGV_WIDTH || 400
|
|
17
12
|
}
|
|
18
13
|
|
|
19
|
-
export { configuration,
|
|
14
|
+
export { configuration, configurationLayout };
|
|
20
15
|
export default configuration;
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { configurationLayout } from "./configuration.js";
|
|
2
|
+
|
|
2
3
|
import { MapLayout } from "./layout/map.js";
|
|
3
4
|
|
|
4
5
|
import { MapData } from "./structure/index.js";
|
|
5
6
|
|
|
6
|
-
import { Clustermap } from "./visualization/cluster.js";
|
|
7
|
-
import { Heatmap } from "./visualization/heatmap.js";
|
|
8
|
-
import { Routemap } from "./visualization/route.js";
|
|
9
7
|
import { VisualizationMap } from "./visualization/index.js";
|
|
10
8
|
|
|
11
|
-
export {
|
|
9
|
+
export { configurationLayout, MapData, MapLayout, VisualizationMap };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { select } from "d3-selection";
|
|
2
|
+
import { debounce, LinearGrid } from "@lgv/visualization-chart";
|
|
2
3
|
import { mean } from "d3-array";
|
|
3
4
|
import L from "leaflet";
|
|
4
5
|
import "leaflet/dist/leaflet.css";
|
|
5
6
|
import "leaflet/dist/images/marker-shadow.png";
|
|
6
|
-
import "./marker-cluster.css";
|
|
7
7
|
|
|
8
8
|
import { configuration, configurationLayout } from "../configuration.js";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* VisualizationMap is a map abstraction.
|
|
12
12
|
* @param {object} data - usually array; occasionally object
|
|
13
|
+
* @param {node} dom - HTML dom node
|
|
13
14
|
* @param {string} label - identifer for chart brand
|
|
14
15
|
* @param {float} height - specified height of chart
|
|
15
16
|
* @param {class} MapData - lgv data class
|
|
@@ -18,17 +19,14 @@ import { configuration, configurationLayout } from "../configuration.js";
|
|
|
18
19
|
*/
|
|
19
20
|
class VisualizationMap extends LinearGrid {
|
|
20
21
|
|
|
21
|
-
constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapData=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
|
|
22
|
+
constructor(dom=null, data, width=configurationLayout.width, height=configurationLayout.height, MapData=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
|
|
22
23
|
|
|
23
24
|
// initialize inheritance
|
|
24
25
|
super(data, width, height, MapData, label, name);
|
|
25
26
|
|
|
26
|
-
// determine type of data object
|
|
27
|
-
this.determineDataType();
|
|
28
|
-
|
|
29
27
|
// determine x/y center
|
|
30
|
-
let x =
|
|
31
|
-
let y =
|
|
28
|
+
let x = mean(this.data.features, d => typeof(d.geometry.coordinates[0]) == "object" ? mean(d.geometry.coordinates.map(x => x[1]).flat()) : d.geometry.coordinates[1]);
|
|
29
|
+
let y = mean(this.data.features, d => typeof(d.geometry.coordinates[0]) == "object" ? mean(d.geometry.coordinates.map(x => x[0]).flat()) : d.geometry.coordinates[0]);
|
|
32
30
|
|
|
33
31
|
// update self
|
|
34
32
|
this.center = [x,y];
|
|
@@ -36,42 +34,30 @@ class VisualizationMap extends LinearGrid {
|
|
|
36
34
|
this.tileServerUrl = tileServerUrl;
|
|
37
35
|
this.zoom = 1;
|
|
38
36
|
|
|
37
|
+
// if dom node provided set as the map container
|
|
38
|
+
if (dom) this.container = select(dom);
|
|
39
|
+
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
+
* Determine if data is geojson feature collection.
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
// update dimensions on class
|
|
48
|
-
let containerSize = this.map.getSize();
|
|
49
|
-
this.heightSpecified = containerSize.y;
|
|
50
|
-
this.widthSpecified = containerSize.x;
|
|
51
|
-
|
|
52
|
-
// process data
|
|
53
|
-
// update data object now that map exists
|
|
54
|
-
this.Data.map = this.map;
|
|
55
|
-
if (this.Data.data) this.data = this.Data.update;
|
|
56
|
-
|
|
57
|
-
// render overlay
|
|
58
|
-
this.generateChart();
|
|
59
|
-
|
|
60
|
-
// broadcast event
|
|
61
|
-
this.container.dispatch("map-change", {
|
|
62
|
-
bubbles: true
|
|
63
|
-
});
|
|
45
|
+
get isFeatureCollection() {
|
|
46
|
+
return this.data !== (null || undefined) && this.Data.source.features !== (null || undefined);
|
|
47
|
+
}
|
|
64
48
|
|
|
65
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Determine if data is geojson point.
|
|
51
|
+
*/
|
|
52
|
+
get isPoint() {
|
|
53
|
+
return this.data && this.data.coordinates && this.data.type.lower() == "point";
|
|
66
54
|
}
|
|
67
55
|
|
|
68
56
|
/**
|
|
69
|
-
*
|
|
57
|
+
* Attach event handlers for map events.
|
|
70
58
|
*/
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
this.isPoint = this.data && this.data.coordinates && this.data.type.lower() == "point";
|
|
74
|
-
this.isXY = this.data && this.data.metadata && this.data.results;
|
|
59
|
+
attachEvents() {
|
|
60
|
+
this.map.on("moveend", debounce(() => this.processMoveEnd(),2000));
|
|
75
61
|
}
|
|
76
62
|
|
|
77
63
|
/**
|
|
@@ -80,10 +66,10 @@ class VisualizationMap extends LinearGrid {
|
|
|
80
66
|
fitToData() {
|
|
81
67
|
|
|
82
68
|
// determine bounding box
|
|
83
|
-
let bounds = (this.isFeatureCollection || this.isPoint) ? L.geoJSON(this.Data.source).getBounds() :
|
|
69
|
+
let bounds = (this.isFeatureCollection || this.isPoint) ? L.geoJSON(this.Data.source).getBounds() : this.map.getBounds();
|
|
84
70
|
|
|
85
71
|
// fit to bounds
|
|
86
|
-
if (this.isFeatureCollection
|
|
72
|
+
if (this.isFeatureCollection) {
|
|
87
73
|
// several data points
|
|
88
74
|
this.map.fitBounds(bounds);
|
|
89
75
|
} else if (this.isPoint) {
|
|
@@ -140,15 +126,9 @@ class VisualizationMap extends LinearGrid {
|
|
|
140
126
|
zoom: this.zoom
|
|
141
127
|
});
|
|
142
128
|
|
|
143
|
-
// add handlers for leaflet events
|
|
144
|
-
this.attachEvents();
|
|
145
|
-
|
|
146
129
|
// update tile server
|
|
147
130
|
L.tileLayer(this.tileServerUrl).addTo(this.map);
|
|
148
131
|
|
|
149
|
-
// fit to bounds
|
|
150
|
-
this.fitToData();
|
|
151
|
-
|
|
152
132
|
}
|
|
153
133
|
|
|
154
134
|
/**
|
|
@@ -162,6 +142,16 @@ class VisualizationMap extends LinearGrid {
|
|
|
162
142
|
// generate patterns
|
|
163
143
|
this.generatePatterns();
|
|
164
144
|
|
|
145
|
+
// add handlers for leaflet events
|
|
146
|
+
this.attachEvents();
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Callback for map event on movened.
|
|
152
|
+
*/
|
|
153
|
+
processMoveEnd() {
|
|
154
|
+
this.updateMap();
|
|
165
155
|
}
|
|
166
156
|
|
|
167
157
|
/**
|
|
@@ -185,19 +175,52 @@ class VisualizationMap extends LinearGrid {
|
|
|
185
175
|
|
|
186
176
|
}
|
|
187
177
|
|
|
178
|
+
// update data in class
|
|
179
|
+
this.updateData(data);
|
|
180
|
+
|
|
181
|
+
// generate visualization
|
|
182
|
+
this.generateChart();
|
|
183
|
+
|
|
184
|
+
// fit to bounds
|
|
185
|
+
this.fitToData();
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Update visualization.
|
|
191
|
+
* @param {object} data - geojson
|
|
192
|
+
*/
|
|
193
|
+
updateData(data) {
|
|
194
|
+
|
|
188
195
|
// recalculate values
|
|
189
196
|
this.Data.source = data;
|
|
190
197
|
this.Data.data = this.Data.update;
|
|
191
198
|
this.data = this.Data.data;
|
|
192
199
|
|
|
193
|
-
|
|
194
|
-
this.determineDataType();
|
|
200
|
+
}
|
|
195
201
|
|
|
196
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Update map state.
|
|
204
|
+
*/
|
|
205
|
+
updateMap() {
|
|
206
|
+
console.log("FIRE!")
|
|
207
|
+
// update dimensions on class
|
|
208
|
+
let containerSize = this.map.getSize();
|
|
209
|
+
this.heightSpecified = containerSize.y;
|
|
210
|
+
this.widthSpecified = containerSize.x;
|
|
211
|
+
|
|
212
|
+
// process data
|
|
213
|
+
// update data object now that map exists
|
|
214
|
+
this.Data.map = this.map;
|
|
215
|
+
if (this.Data.data) this.data = this.Data.update;
|
|
216
|
+
|
|
217
|
+
// render overlay
|
|
197
218
|
this.generateChart();
|
|
198
219
|
|
|
199
|
-
//
|
|
200
|
-
this.
|
|
220
|
+
// broadcast event
|
|
221
|
+
this.container.dispatch("map-change", {
|
|
222
|
+
bubbles: true
|
|
223
|
+
});
|
|
201
224
|
|
|
202
225
|
}
|
|
203
226
|
|
package/webpack.common.js
CHANGED
package/src/layout/heat.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import L from "leaflet";
|
|
2
|
-
|
|
3
|
-
import { MapLayout } from "./map.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* HeatLayout is a data-bound layout abstraction for a heatmap.
|
|
7
|
-
* @param {array} data - geojson
|
|
8
|
-
* @param {class} map - Leaflet map object
|
|
9
|
-
*/
|
|
10
|
-
class HeatLayout extends MapLayout {
|
|
11
|
-
|
|
12
|
-
constructor(data, map) {
|
|
13
|
-
|
|
14
|
-
// initialize inheritance
|
|
15
|
-
super(data);
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Condition data for visualization requirements.
|
|
21
|
-
* @param {array} data - geojson
|
|
22
|
-
* @returns An object or array of data specifically formatted to the visualization type.
|
|
23
|
-
*/
|
|
24
|
-
condition(data) {
|
|
25
|
-
|
|
26
|
-
let result = data;
|
|
27
|
-
|
|
28
|
-
if (this.map && data.type == "FeatureCollection") {
|
|
29
|
-
|
|
30
|
-
let bounds = this.map.getBounds();
|
|
31
|
-
|
|
32
|
-
// project to xy
|
|
33
|
-
result = data.features
|
|
34
|
-
.filter(d => d.geometry.coordinates[1] >= bounds._southWest.lat && d.geometry.coordinates[1] <= bounds._northEast.lat && d.geometry.coordinates[0] >= bounds._southWest.lng && d.geometry.coordinates[0] <= bounds._northEast.lng)
|
|
35
|
-
.map(d => {
|
|
36
|
-
|
|
37
|
-
// convert to xy
|
|
38
|
-
let xy = this.map.latLngToContainerPoint(L.latLng(d.geometry.coordinates[1], d.geometry.coordinates[0]));
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
count: d.properties.count,
|
|
42
|
-
id: d.properties.id,
|
|
43
|
-
label: d.properties.name,
|
|
44
|
-
x: xy.x,
|
|
45
|
-
y: xy.y
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return result;
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { HeatLayout };
|
|
59
|
-
export default HeatLayout;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import L from "leaflet";
|
|
2
|
-
import MarkerClusterGroup from "leaflet.markercluster";
|
|
3
|
-
import defaultIcon from "leaflet/dist/images/marker-icon.png";
|
|
4
|
-
|
|
5
|
-
import { VisualizationMap } from "./index.js";
|
|
6
|
-
import { MapLayout as ML } from "../layout/map.js";
|
|
7
|
-
|
|
8
|
-
import { configuration, configurationLayout } from "../configuration.js";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Clustermap is a map abstraction for a clustered visualization.
|
|
12
|
-
* @param {object} data - usually array; occasionally object
|
|
13
|
-
* @param {string} label - identifer for chart brand
|
|
14
|
-
* @param {float} height - specified height of chart
|
|
15
|
-
* @param {object} markerIcon - Leaflet object
|
|
16
|
-
* @param {class} MapData - lgv data class
|
|
17
|
-
* @param {string} name - name of chart
|
|
18
|
-
* @param {float} width - specified width of chart
|
|
19
|
-
*/
|
|
20
|
-
class Clustermap extends VisualizationMap {
|
|
21
|
-
|
|
22
|
-
constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapLayout=null, markerIcon=L.icon({iconUrl: defaultIcon}), tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
|
|
23
|
-
|
|
24
|
-
// initialize inheritance
|
|
25
|
-
super(data, width, height, MapLayout ? MapLayout : new ML(data), tileServerUrl, label, name);
|
|
26
|
-
|
|
27
|
-
// set default icon
|
|
28
|
-
L.Marker.prototype.setIcon(markerIcon);
|
|
29
|
-
|
|
30
|
-
// initialize marker group
|
|
31
|
-
this.markerClusterGroup = L.markerClusterGroup();
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Generate main visualization, i.e. everything that sits inside the map.
|
|
37
|
-
*/
|
|
38
|
-
generateChart() {
|
|
39
|
-
|
|
40
|
-
// check if marker group exists
|
|
41
|
-
if (!this.map.hasLayer(this.markerClusterGroup)) {
|
|
42
|
-
|
|
43
|
-
// add popup info to marker
|
|
44
|
-
let geoJsonLayer = L.geoJson(this.data, {
|
|
45
|
-
onEachFeature: function (feature, layer) {
|
|
46
|
-
layer.bindPopup(`<div><div id="popup-poster"><div data-id="${feature.properties.id}" style="background-image: url(${feature.properties.poster})"></div></div><div><p><strong>${feature.properties.label}</strong></p><p>${feature.properties.value}</p></div>`);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// add markers to group
|
|
51
|
-
this.markerClusterGroup.addLayer(geoJsonLayer);
|
|
52
|
-
|
|
53
|
-
// add marker layer to map
|
|
54
|
-
this.map.addLayer(this.markerClusterGroup);
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export { Clustermap };
|
|
63
|
-
export default Clustermap;
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import * as deck from '@deck.gl/core';
|
|
2
|
-
import * as layers from '@deck.gl/layers';
|
|
3
|
-
import * as luma from '@luma.gl/core';
|
|
4
|
-
import * as VegaDeckGl from "@msrvida/vega-deck.gl";
|
|
5
|
-
import L from "leaflet";
|
|
6
|
-
import * as vega from "vega";
|
|
7
|
-
|
|
8
|
-
import { VisualizationMap } from "./index.js";
|
|
9
|
-
import { HeatLayout as HL } from "../layout/heat.js";
|
|
10
|
-
|
|
11
|
-
import { configuration, configurationColor, configurationLayout } from "../configuration.js";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Heatmap is a map abstraction for a heatmap visualization.
|
|
15
|
-
* @param {object} data - usually array; occasionally object
|
|
16
|
-
* @param {string} label - identifer for chart brand
|
|
17
|
-
* @param {float} height - specified height of chart
|
|
18
|
-
* @param {class} MapData - lgv data class
|
|
19
|
-
* @param {string} name - name of chart
|
|
20
|
-
* @param {float} width - specified width of chart
|
|
21
|
-
*/
|
|
22
|
-
class Heatmap extends VisualizationMap {
|
|
23
|
-
|
|
24
|
-
constructor(data, width=configurationLayout.width, height=configurationLayout.height, HeatLayout=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
|
|
25
|
-
|
|
26
|
-
// initialize inheritance
|
|
27
|
-
super(data, width, height, HeatLayout ? HeatLayout : new HL(data), tileServerUrl, label, name);
|
|
28
|
-
|
|
29
|
-
// initialize vega
|
|
30
|
-
VegaDeckGl.use(vega, deck, layers, luma);
|
|
31
|
-
|
|
32
|
-
// update self
|
|
33
|
-
this.imageOverlay = null;
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Generate mark size.
|
|
39
|
-
* @returns An integer representing the render size of a visual mark.
|
|
40
|
-
*/
|
|
41
|
-
get mark() {
|
|
42
|
-
|
|
43
|
-
let isHighDensityDisplay = window.devicePixelRatio > 1 && window.innerWidth * window.devicePixelRatio > 3360 && window.innerHeight * window.devicePixelRatio > 1942;
|
|
44
|
-
|
|
45
|
-
// set starting size
|
|
46
|
-
let base = isHighDensityDisplay ? this.unit * 1.75 : this.unit * 2;
|
|
47
|
-
let mark = base;
|
|
48
|
-
|
|
49
|
-
// determine mark size
|
|
50
|
-
switch (true) {
|
|
51
|
-
case (this.zoom >= 16):
|
|
52
|
-
mark = base - 1;
|
|
53
|
-
break;
|
|
54
|
-
case (this.zoom >= 14):
|
|
55
|
-
mark = base - 2;
|
|
56
|
-
break;
|
|
57
|
-
case (this.zoom >= 12):
|
|
58
|
-
mark = base - 3;
|
|
59
|
-
break;
|
|
60
|
-
case (this.zoom >= 8):
|
|
61
|
-
mark = base - 4;
|
|
62
|
-
break;
|
|
63
|
-
case (this.zoom >= 0):
|
|
64
|
-
mark = base - 5;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return mark;
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Generate main visualization, i.e. everything that sits inside the map.
|
|
74
|
-
*/
|
|
75
|
-
generateChart() {
|
|
76
|
-
|
|
77
|
-
// generate vega specification
|
|
78
|
-
let spec = this.generateSpecification();
|
|
79
|
-
|
|
80
|
-
// render vega with deck.gl
|
|
81
|
-
let view = new VegaDeckGl.ViewGl(vega.parse(spec))
|
|
82
|
-
.renderer("deck.gl")
|
|
83
|
-
.run();
|
|
84
|
-
|
|
85
|
-
// generate url blob
|
|
86
|
-
view.toImageURL("svg")
|
|
87
|
-
.then(url => {
|
|
88
|
-
|
|
89
|
-
// check if overlay exists
|
|
90
|
-
if (this.imageOverlay) {
|
|
91
|
-
|
|
92
|
-
// update existing
|
|
93
|
-
this.imageOverlay.setUrl(url);
|
|
94
|
-
this.imageOverlay.setBounds(this.map.getBounds());
|
|
95
|
-
|
|
96
|
-
} else {
|
|
97
|
-
|
|
98
|
-
// initialize
|
|
99
|
-
this.imageOverlay = L.imageOverlay(url, this.map.getBounds());
|
|
100
|
-
|
|
101
|
-
// update map
|
|
102
|
-
this.imageOverlay.addTo(this.map);
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Generate vega specification in prep for render.
|
|
112
|
-
*/
|
|
113
|
-
generateSpecification() {
|
|
114
|
-
|
|
115
|
-
// register custom scheme
|
|
116
|
-
vega.scheme(this.name, configurationColor.p1);
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
width: this.width,
|
|
120
|
-
height: this.height,
|
|
121
|
-
data: [{ name: this.name, values: this.isXY ? this.data.results : this.data }],
|
|
122
|
-
scales: [
|
|
123
|
-
{
|
|
124
|
-
name: "color",
|
|
125
|
-
type: "linear",
|
|
126
|
-
domain: { data: this.name, field: "count" },
|
|
127
|
-
range: { scheme: this.name, count: configurationColor.p1.length }
|
|
128
|
-
}
|
|
129
|
-
],
|
|
130
|
-
marks: [
|
|
131
|
-
{
|
|
132
|
-
type: "symbol",
|
|
133
|
-
from: { data: this.name },
|
|
134
|
-
encode: {
|
|
135
|
-
update: {
|
|
136
|
-
shape: { value: "square" },
|
|
137
|
-
x: { field: "x" },
|
|
138
|
-
y: { field: "y" },
|
|
139
|
-
size: { value: this.mark },
|
|
140
|
-
fill: { scale: "color", field: "count" },
|
|
141
|
-
opacity: { value: 1 }
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
}
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export { Heatmap };
|
|
153
|
-
export default Heatmap;
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
|
|
3
|
-
--marker-cluster-small: rgba(181, 226, 140, 0.6);
|
|
4
|
-
--marker-cluster-small-div: rgba(110, 204, 57, 0.6);
|
|
5
|
-
--marker-cluster-medium: rgba(241, 211, 87, 0.6);
|
|
6
|
-
--marker-cluster-medium-div: rgba(240, 194, 12, 0.6);
|
|
7
|
-
--marker-cluster-large: rgba(253, 156, 115, 0.6);
|
|
8
|
-
--marker-cluster-large-div: rgba(241, 128, 23, 0.6);
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.marker-cluster-small {
|
|
13
|
-
background-color: var(--marker-cluster-small);
|
|
14
|
-
}
|
|
15
|
-
.marker-cluster-small div {
|
|
16
|
-
background-color: var(--marker-cluster-small-div);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.marker-cluster-medium {
|
|
20
|
-
background-color: var(--marker-cluster-medium);
|
|
21
|
-
}
|
|
22
|
-
.marker-cluster-medium div {
|
|
23
|
-
background-color: var(--marker-cluster-medium-div);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.marker-cluster-large {
|
|
27
|
-
background-color: var(--marker-cluster-large);
|
|
28
|
-
}
|
|
29
|
-
.marker-cluster-large div {
|
|
30
|
-
background-color: var(--marker-cluster-large-div);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.marker-cluster {
|
|
34
|
-
background-clip: padding-box;
|
|
35
|
-
border-radius: 2.5em;
|
|
36
|
-
}
|
|
37
|
-
.marker-cluster div {
|
|
38
|
-
width: 2.5em;
|
|
39
|
-
height: 2.5em;
|
|
40
|
-
text-align: center;
|
|
41
|
-
border-radius: 2.5em;
|
|
42
|
-
display: flex;
|
|
43
|
-
align-items: center;
|
|
44
|
-
justify-content:center;
|
|
45
|
-
margin-left: 0.45em;
|
|
46
|
-
margin-top: 0.45em;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/***************** POP UP *****************/
|
|
50
|
-
|
|
51
|
-
.cluster-map .leaflet-popup-content {
|
|
52
|
-
|
|
53
|
-
margin-bottom: 0;
|
|
54
|
-
margin-left: 0;
|
|
55
|
-
margin-top: 0;
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/* wrap */
|
|
60
|
-
.cluster-map .leaflet-popup-content > div {
|
|
61
|
-
|
|
62
|
-
display: flex;
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* poster parent */
|
|
67
|
-
.cluster-map .leaflet-popup-content > div > div:first-of-type {
|
|
68
|
-
|
|
69
|
-
height: 100%;
|
|
70
|
-
overflow: hidden;
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* poster */
|
|
75
|
-
.cluster-map .leaflet-popup-content > div > div:first-of-type > div {
|
|
76
|
-
|
|
77
|
-
background-position: center;
|
|
78
|
-
background-repeat: no-repeat;
|
|
79
|
-
background-size: cover;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
height: 5em;
|
|
82
|
-
margin-right: 1em;
|
|
83
|
-
transition: .3s cubic-bezier(.25,.8,.25,1);
|
|
84
|
-
transition-property: transform;
|
|
85
|
-
width: 5em;
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.cluster-map .leaflet-popup-content > div > div:first-of-type:hover > div,
|
|
90
|
-
.cluster-map .leaflet-popup-content > div > div:first-of-type:focus > div {
|
|
91
|
-
|
|
92
|
-
transform: scale(1.1);
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* text wrap */
|
|
97
|
-
.cluster-map .leaflet-popup-content > div > div:last-of-type {
|
|
98
|
-
|
|
99
|
-
margin-top: 1em;
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/* text */
|
|
104
|
-
.cluster-map .leaflet-popup-content p {
|
|
105
|
-
|
|
106
|
-
margin: 0;
|
|
107
|
-
|
|
108
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { select, Selection } from "d3-selection";
|
|
2
|
-
//import { transition, Transition } from "d3-transition";
|
|
3
|
-
import transition from "d3-transition";
|
|
4
|
-
import "d3-transition";
|
|
5
|
-
import L from "leaflet";
|
|
6
|
-
|
|
7
|
-
import { VisualizationMap } from "./index.js";
|
|
8
|
-
import { MapLayout as ML } from "../layout/map.js";
|
|
9
|
-
|
|
10
|
-
import { configuration, configurationLayout } from "../configuration.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Routemap is a map abstraction for a routing visualization.
|
|
14
|
-
* @param {object} data - usually array; occasionally object
|
|
15
|
-
* @param {string} label - identifer for chart brand
|
|
16
|
-
* @param {float} height - specified height of chart
|
|
17
|
-
* @param {class} MapData - lgv data class
|
|
18
|
-
* @param {string} name - name of chart
|
|
19
|
-
* @param {float} width - specified width of chart
|
|
20
|
-
*/
|
|
21
|
-
class Routemap extends VisualizationMap {
|
|
22
|
-
|
|
23
|
-
constructor(data, width=configurationLayout.width, height=configurationLayout.height, MapLayout=null, tileServerUrl=configurationLayout.tileserver, label=configuration.branding, name=configuration.name) {
|
|
24
|
-
|
|
25
|
-
// initialize inheritance
|
|
26
|
-
super(data, width, height, MapLayout ? MapLayout : new ML(data), tileServerUrl, label, name);
|
|
27
|
-
|
|
28
|
-
// initialize feature group
|
|
29
|
-
this.geoJsonLayer = null;
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Generate main visualization, i.e. everything that sits inside the map.
|
|
35
|
-
*/
|
|
36
|
-
generateChart() {
|
|
37
|
-
|
|
38
|
-
// clear if exists
|
|
39
|
-
if (this.geoJsonLayer) this.geoJsonLayer.clearLayers();
|
|
40
|
-
|
|
41
|
-
// initialize feature group
|
|
42
|
-
this.geoJsonLayer = L.geoJSON(this.data);
|
|
43
|
-
|
|
44
|
-
// add lines
|
|
45
|
-
this.geoJsonLayer.addTo(this.map);
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export { Routemap };
|
|
52
|
-
export default Routemap;
|