mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-11-26 07:02:59 +00:00
Colour the markers instead of having a heatmap
Goodbye, old friend :-( That heatmap thingy took several revisions and lots fo hard work, but it just didn't work out :-( :-( :'(
This commit is contained in:
parent
8ccc578e7b
commit
3fe326b02d
11 changed files with 4763 additions and 4794 deletions
|
@ -10,6 +10,8 @@ export default {
|
||||||
// The default zoom level to use when loading the page.
|
// The default zoom level to use when loading the page.
|
||||||
default_zoom: 12,
|
default_zoom: 12,
|
||||||
|
|
||||||
|
default_reading_type: "PM25",
|
||||||
|
|
||||||
// The number of minutes to round dates to when making time-based HTTP API requests.
|
// The number of minutes to round dates to when making time-based HTTP API requests.
|
||||||
// Very useful for improving cache hit rates.
|
// Very useful for improving cache hit rates.
|
||||||
date_rounding_interval: 6,
|
date_rounding_interval: 6,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import chroma from 'chroma-js';
|
||||||
|
|
||||||
var PM25 = {
|
var PM25 = {
|
||||||
/*
|
/*
|
||||||
|
@ -103,6 +104,11 @@ var specs = {
|
||||||
unknown
|
unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for(let spec of Object.values(specs)) {
|
||||||
|
spec.chroma = chroma.scale(Object.values(spec.gradient))
|
||||||
|
.domain(Object.keys(spec.gradient));
|
||||||
|
}
|
||||||
|
|
||||||
export default specs;
|
export default specs;
|
||||||
export {
|
export {
|
||||||
PM10, PM25,
|
PM10, PM25,
|
|
@ -10,45 +10,121 @@ import Emitter from 'event-emitter-es6';
|
||||||
|
|
||||||
import Config from './Config.mjs';
|
import Config from './Config.mjs';
|
||||||
import DeviceReadingDisplay from './DeviceReadingDisplay.mjs';
|
import DeviceReadingDisplay from './DeviceReadingDisplay.mjs';
|
||||||
|
import MarkerGenerator from './MarkerGenerator.mjs';
|
||||||
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
||||||
import { human_time_since } from './Helpers/DateHelper.mjs';
|
import { human_time_since } from './Helpers/DateHelper.mjs';
|
||||||
|
|
||||||
class LayerDeviceMarkers extends Emitter {
|
class LayerDeviceMarkers extends Emitter {
|
||||||
constructor(in_map, in_device_data) {
|
constructor(in_map_manager, in_device_data) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.map = in_map;
|
this.map_manager = in_map_manager;
|
||||||
this.device_data = in_device_data;
|
this.device_data = in_device_data;
|
||||||
|
|
||||||
|
this.marker_generator = new MarkerGenerator();
|
||||||
|
|
||||||
// Create a new clustering layer
|
// Create a new clustering layer
|
||||||
|
this.layer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs initial setup of the device markers layer.
|
||||||
|
* @return {Promise} A Promise that resolves when the initial setup is complete
|
||||||
|
*/
|
||||||
|
async setup() {
|
||||||
|
await this.update_markers(Config.default_reading_type, "now");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces all existing device markers (if any) with those for a given
|
||||||
|
* reading type and datetime.
|
||||||
|
* @param {string} reading_type The reading type to use to colour the markers.
|
||||||
|
* @param {String|Date} [datetime="now"] The datetime of the data to use to colour the markers (default: the special keyword "now", which indicates to fetch data for the current time)
|
||||||
|
* @return {Promise} A Promise that resolves when the markers have been updated.
|
||||||
|
*/
|
||||||
|
async update_markers(reading_type, datetime = "now") {
|
||||||
|
// 1: Remove the old layer, if present
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
if(this.layer !== null)
|
||||||
|
this.map_manager.map.removeLayer(this.layer);
|
||||||
|
|
||||||
|
// 2: Create a new layer
|
||||||
|
// --------------------------------------------------------------------
|
||||||
this.layer = L.markerClusterGroup({
|
this.layer = L.markerClusterGroup({
|
||||||
// this.layer = L.layerGroup({
|
// this.layer = L.layerGroup({
|
||||||
zoomToBoundsOnClick: false
|
zoomToBoundsOnClick: false
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
async setup() {
|
// 3: Fetch the latest readings data
|
||||||
// Add a marker for each device
|
// --------------------------------------------------------------------
|
||||||
|
let device_values = await this.map_manager.readings_data.fetch(reading_type, datetime);
|
||||||
|
|
||||||
|
// 4: Add a marker for each device
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
let has_data = 0, has_no_data = 0, total = 0;
|
||||||
for (let device of this.device_data.devices) {
|
for (let device of this.device_data.devices) {
|
||||||
// If the device doesn't have a location, we're not interested
|
// If the device doesn't have a location, we're not interested
|
||||||
// FUTURE: We might be able to display mobile devices by adding additional logic here
|
// FUTURE: We might be able to display mobile devices by adding additional logic here
|
||||||
if(typeof device.latitude != "number" || typeof device.longitude != "number")
|
if(typeof device.latitude != "number" || typeof device.longitude != "number")
|
||||||
continue;
|
continue;
|
||||||
this.add_device_marker(device);
|
|
||||||
|
console.log(`[LayerDeviceMarkers] id =`, device.id, `name =`, device.name, `location: (`, device.latitude, `,`, device.longitude, `)`);
|
||||||
|
|
||||||
|
if(device_values.has(device.id)) {
|
||||||
|
this.add_device_marker(device, reading_type, device_values.get(device.id).value);
|
||||||
|
console.log(`has value`);
|
||||||
|
has_data++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.add_device_marker(device, "unknown");
|
||||||
|
console.log(`doesn't have value`);
|
||||||
|
has_no_data++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display this layer
|
total++;
|
||||||
this.map.addLayer(this.layer);
|
}
|
||||||
|
console.log(`[LayerDeviceMarkers] has_data`, has_data, `has_no_data`, has_no_data, `total`, total);
|
||||||
|
|
||||||
|
// 5: Display the new layer
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
this.map_manager.map.addLayer(this.layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a single device marker with a given reading type and value.
|
||||||
|
* @param {Object} device The object representing the device to add.
|
||||||
|
* @param {string} reading_type The reading type to use when colouring the marker. The special "unknown" reading type causes a default blue marker to be shown (regardless of the value passed).
|
||||||
|
* @param {number} value The reading value to use when colouring the marker.
|
||||||
|
*/
|
||||||
|
add_device_marker(device, reading_type, value) {
|
||||||
|
let icon;
|
||||||
|
if(reading_type !== "unknown") {
|
||||||
|
icon = L.divIcon({
|
||||||
|
className: "device-marker-icon",
|
||||||
|
html: this.marker_generator.marker(value, reading_type),
|
||||||
|
iconSize: L.point(17.418, 27.508),
|
||||||
|
iconAnchor: L.point(8.71, 27.16)
|
||||||
|
});
|
||||||
|
console.log(`[LayerDeviceMarkers/add_device_marker] got value`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
icon = L.divIcon({
|
||||||
|
className: "device-marker-icon icon-unknown",
|
||||||
|
html: this.marker_generator.marker_default(),
|
||||||
|
iconSize: L.point(17.418, 27.508),
|
||||||
|
iconAnchor: L.point(8.71, 27.16)
|
||||||
|
});
|
||||||
|
console.log(`[LayerDeviceMarkers/add_device_marker] unknown value`);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_device_marker(device) {
|
|
||||||
// Create the marker
|
// Create the marker
|
||||||
let marker = L.marker(
|
let marker = L.marker(
|
||||||
L.latLng(device.latitude, device.longitude),
|
L.latLng(device.latitude, device.longitude),
|
||||||
{ // See https://leafletjs.com/reference-1.4.0.html#marker
|
{ // See https://leafletjs.com/reference-1.4.0.html#marker
|
||||||
title: `Device: ${device.name}`,
|
title: `Device: ${device.name}`,
|
||||||
autoPan: true,
|
autoPan: true,
|
||||||
autoPanPadding: L.point(100, 100)
|
autoPanPadding: L.point(100, 100),
|
||||||
|
icon
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// Create the popup
|
// Create the popup
|
||||||
|
|
|
@ -8,15 +8,16 @@ import 'leaflet-easyprint';
|
||||||
|
|
||||||
import Config from './Config.mjs';
|
import Config from './Config.mjs';
|
||||||
import LayerDeviceMarkers from './LayerDeviceMarkers.mjs';
|
import LayerDeviceMarkers from './LayerDeviceMarkers.mjs';
|
||||||
import VoronoiManager from './Overlay/VoronoiManager.mjs';
|
|
||||||
// import LayerHeatmap from './LayerHeatmap.mjs';
|
// import LayerHeatmap from './LayerHeatmap.mjs';
|
||||||
// import LayerHeatmapGlue from './LayerHeatmapGlue.mjs';
|
// import LayerHeatmapGlue from './LayerHeatmapGlue.mjs';
|
||||||
import DeviceData from './DeviceData.mjs';
|
import DeviceData from './DeviceData.mjs';
|
||||||
|
import ReadingsData from './ReadingsData.mjs';
|
||||||
import UI from './UI.mjs';
|
import UI from './UI.mjs';
|
||||||
|
|
||||||
class MapManager {
|
class MapManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
console.log(Config);
|
console.log(Config);
|
||||||
|
this.readings_data = new ReadingsData();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup() {
|
async setup() {
|
||||||
|
@ -55,9 +56,6 @@ class MapManager {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.setup_device_markers.bind(this)()
|
this.setup_device_markers.bind(this)()
|
||||||
.then(() => console.info("[map] Device markers loaded successfully.")),
|
.then(() => console.info("[map] Device markers loaded successfully.")),
|
||||||
|
|
||||||
this.setup_overlay.bind(this)()
|
|
||||||
.then(this.setup_layer_control.bind(this))
|
|
||||||
]).then(() => document.querySelector("main").classList.remove("working-visual"));
|
]).then(() => document.querySelector("main").classList.remove("working-visual"));
|
||||||
|
|
||||||
// Add the heatmap
|
// Add the heatmap
|
||||||
|
@ -69,13 +67,6 @@ class MapManager {
|
||||||
// .then(() => console.info("[map] Time dimension initialised."));
|
// .then(() => console.info("[map] Time dimension initialised."));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup_overlay() {
|
|
||||||
this.overlay = new VoronoiManager(this.device_data, this.map);
|
|
||||||
await this.overlay.setup();
|
|
||||||
// No need to do this here, as it does it automatically
|
|
||||||
// await this.overlay.set_data(new Date(), "PM25");
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_time_dimension() {
|
setup_time_dimension() {
|
||||||
// FUTURE: Replace leaflet-time-dimension with our own solution that's got a better ui & saner API?
|
// FUTURE: Replace leaflet-time-dimension with our own solution that's got a better ui & saner API?
|
||||||
this.layer_time = new L.TimeDimension({
|
this.layer_time = new L.TimeDimension({
|
||||||
|
@ -113,7 +104,7 @@ class MapManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup_device_markers() {
|
async setup_device_markers() {
|
||||||
this.device_markers = new LayerDeviceMarkers(this.map, this.device_data);
|
this.device_markers = new LayerDeviceMarkers(this, this.device_data);
|
||||||
await this.device_markers.setup();
|
await this.device_markers.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +140,7 @@ class MapManager {
|
||||||
"OpenStreetMap": this.layer_openstreet
|
"OpenStreetMap": this.layer_openstreet
|
||||||
}, { // Overlay(s)
|
}, { // Overlay(s)
|
||||||
"Devices": this.device_markers.layer,
|
"Devices": this.device_markers.layer,
|
||||||
// FUTURE: Have 1 heatmap layer per reading type?
|
// "Heatmap": this.overlay.layer
|
||||||
"Heatmap": this.overlay.layer
|
|
||||||
}, { // Options
|
}, { // Options
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
46
client_src/js/MarkerGenerator.mjs
Normal file
46
client_src/js/MarkerGenerator.mjs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import chroma from 'chroma-js';
|
||||||
|
|
||||||
|
import marker_svg from '../marker-embed.svg';
|
||||||
|
import gradients from './Gradients.mjs';
|
||||||
|
|
||||||
|
class MarkerGenerator {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
marker_default() {
|
||||||
|
return marker_svg.replace("{{colour_a}}", "#1975c8")
|
||||||
|
.replace("{{colour_b}}", "#5ea6d5")
|
||||||
|
.replace("{{colour_dark}}", "#2e6d99");
|
||||||
|
}
|
||||||
|
|
||||||
|
marker(value, type) {
|
||||||
|
let col = this.get_colour(value, type);
|
||||||
|
let result = marker_svg.replace(/\{\{colour_a\}\}/g, col.darken(0.25).hex())
|
||||||
|
.replace(/\{\{colour_b\}\}/g, col.brighten(0.25).hex())
|
||||||
|
.replace(/\{\{colour_dark\}\}/g, col.darken(1))
|
||||||
|
.replace(/\{\{id_grad\}\}/g, `marker-grad-${btoa(`${type}-${value}`).replace(/\+/g, "-").replace(/\//g, "_")}`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the colour for a given value of a given type.
|
||||||
|
* Currently a gradient is not used - i.e. a value is coloured according to
|
||||||
|
* the last threshold it crossed in the associated gradient definition.
|
||||||
|
* TODO: Calculate the gradient instead.
|
||||||
|
* @param {number} value The value to calculate the colour for.
|
||||||
|
* @param {string} type The type of measurement value we're working with. Determines the gradient to use.
|
||||||
|
* @return {chroma} The calculated colour.
|
||||||
|
*/
|
||||||
|
get_colour(value, type) {
|
||||||
|
if(typeof gradients[type] == "undefined") {
|
||||||
|
console.warn(`[MarkerGenerator] Warning: Unknown gradient type '${type}', using unknown instead.`);
|
||||||
|
type = "unknown";
|
||||||
|
}
|
||||||
|
return gradients[type].chroma(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MarkerGenerator;
|
38
client_src/js/ReadingsData.mjs
Normal file
38
client_src/js/ReadingsData.mjs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import Config from './Config.mjs';
|
||||||
|
|
||||||
|
import GetFromUrl from './Helpers/GetFromUrl.mjs';
|
||||||
|
|
||||||
|
class ReadingsData {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the data from all currently active devices at a given datetime
|
||||||
|
* and for a given reading type.
|
||||||
|
* @param {string} reading_type The reading type to fetch data for.
|
||||||
|
* @param {String|Date} [datetime="now"] The datetime to fetch the data for.
|
||||||
|
* @return {Promise<Map>} A promise that resolves to a Map keyed by device IDs that contains the data objects returned by the fetch-data API action.
|
||||||
|
*/
|
||||||
|
async fetch(reading_type, datetime = "now") {
|
||||||
|
if(datetime instanceof Date)
|
||||||
|
datetime = datetime.toISOString();
|
||||||
|
// TODO: memoize this
|
||||||
|
let data = await this.__make_request(reading_type, datetime);
|
||||||
|
let result = new Map();
|
||||||
|
for(let item of data)
|
||||||
|
result.set(item.device_id, item);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async __make_request(reading_type, datetime) {
|
||||||
|
return JSON.parse(await GetFromUrl(
|
||||||
|
`${Config.api_root}?action=fetch-data&datetime=${encodeURIComponent(datetime)}&reading_type=${encodeURIComponent(reading_type)}`
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReadingsData;
|
1
client_src/marker-embed.svg
Normal file
1
client_src/marker-embed.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg width="21.7725" height="34.385" version="1.1" viewBox="0 0 4.6085 7.2783" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="{{id_grad}}" x1="25.492" x2="25.557" y1="65.023" y2="44.643" gradientTransform="matrix(.33982 0 0 .33982 -6.3929 -14.983)" gradientUnits="userSpaceOnUse"><stop stop-color="{{colour_a}}" offset="0"/><stop stop-color="{{colour_b}}" offset="1"/></linearGradient><clipPath id="c"><path d="m40.048 68.631c-3.078-6.038-3.783-7.984-3.538-9.768 0.439-3.208 3.281-5.696 6.505-5.696 2.457 0 4.418 1.149 5.704 3.343 0.913 1.559 1.082 3.161 0.533 5.069-0.455 1.582-5.895 12.541-6.226 12.541-0.098 0-1.439-2.47-2.978-5.49zm4.445-7.594c1.168-1.168 0.58-3.06-1.079-3.477-1.301-0.326-2.675 1.155-2.368 2.554 0.345 1.572 2.28 2.09 3.448 0.922z" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".321" stroke-width="1.39"/></clipPath></defs><path d="m0.086822 2.4041c-0.039079-1.2465 1.1491-2.3381 2.217-2.3254 1.6322 0.19404 2.5079 1.4466 2.1195 2.8589-0.15462 0.5376-2.0032 4.2617-2.1157 4.2617-0.66809-1.378-2.0406-3.2681-2.2211-4.7952zm2.7196 0.34866c0.79076-1.4035-1.3749-1.4731-1.1717-0.31331 0.11724 0.5342 0.77479 0.71022 1.1717 0.31331z" fill="url(#{{id_grad}})" stroke-width=".33982"/><path transform="matrix(.33982 0 0 .33982 -12.313 -17.988)" d="m40.048 68.631c-3.078-6.038-3.783-7.984-3.538-9.768 0.439-3.208 3.281-5.696 6.505-5.696 2.457 0 4.418 1.149 5.704 3.343 0.913 1.559 1.082 3.161 0.533 5.069-0.455 1.582-5.895 12.541-6.226 12.541-0.098 0-1.439-2.47-2.978-5.49zm4.445-7.594c1.168-1.168 0.58-3.06-1.079-3.477-1.301-0.326-2.675 1.155-2.368 2.554 0.345 1.572 2.28 2.09 3.448 0.922z" clip-path="url(#c)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".321" stroke-width="1.39"/><path d="m1.2962 5.334c-1.046-2.0518-1.2855-2.7131-1.2023-3.3194 0.14918-1.0901 1.115-1.9356 2.2105-1.9356 0.83494 0 1.5013 0.39045 1.9383 1.136 0.31026 0.52978 0.36769 1.0742 0.18112 1.7225-0.15462 0.5376-2.0032 4.2617-2.1157 4.2617-0.033302 0-0.489-0.83936-1.012-1.8656zm1.5105-2.5806c0.39691-0.39691 0.1971-1.0398-0.36667-1.1816-0.44211-0.11078-0.90902 0.39249-0.80469 0.8679 0.11724 0.5342 0.77479 0.71022 1.1717 0.31331z" fill="none" stroke="{{colour_dark}}" stroke-opacity=".956" stroke-width=".15802"/></svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -1,6 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
@ -15,7 +13,7 @@
|
||||||
viewBox="0 0 13.562857 21.42"
|
viewBox="0 0 13.562857 21.42"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
|
||||||
sodipodi:docname="marker.svg">
|
sodipodi:docname="marker.svg">
|
||||||
<defs
|
<defs
|
||||||
id="defs2">
|
id="defs2">
|
||||||
|
@ -68,11 +66,12 @@
|
||||||
fit-margin-left="0"
|
fit-margin-left="0"
|
||||||
fit-margin-right="0"
|
fit-margin-right="0"
|
||||||
fit-margin-bottom="0"
|
fit-margin-bottom="0"
|
||||||
inkscape:window-width="1825"
|
inkscape:window-width="1831"
|
||||||
inkscape:window-height="1047"
|
inkscape:window-height="1047"
|
||||||
inkscape:window-x="95"
|
inkscape:window-x="89"
|
||||||
inkscape:window-y="33"
|
inkscape:window-y="33"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:document-rotation="0" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata5">
|
id="metadata5">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
|
@ -91,10 +90,11 @@
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(-27.03016,-48.232836)">
|
transform="translate(-27.03016,-48.232836)">
|
||||||
<path
|
<path
|
||||||
style="fill:url(#linearGradient844);fill-opacity:1;stroke:none;stroke-width:0.46500003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.95686275"
|
style="fill:url(#linearGradient844);fill-opacity:1;stroke:none;stroke-width:0.465;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.956863"
|
||||||
d="m 30.844224,63.930232 c -3.078474,-6.038878 -3.783282,-7.984375 -3.538785,-9.76818 0.439793,-3.20864 3.281231,-5.696716 6.505776,-5.696716 2.457647,0 4.418161,1.149131 5.704071,3.343371 0.913856,1.559378 1.082523,3.161787 0.533646,5.069884 -0.455307,1.582814 -5.895833,12.541745 -6.226308,12.541745 -0.09882,0 -1.439103,-2.470547 -2.9784,-5.490104 z m 4.445635,-7.594744 c 1.16819,-1.168191 0.580604,-3.060887 -1.079611,-3.477574 -1.30134,-0.326616 -2.675892,1.155891 -2.368663,2.554695 0.345401,1.572603 2.280617,2.090534 3.448274,0.922879 z"
|
d="m 27.286537,55.308491 c -0.115852,-3.668092 3.911381,-6.767612 6.524678,-6.843155 4.803399,0.571307 7.380181,4.257602 6.237717,8.413255 -0.455307,1.582814 -5.895833,12.541745 -6.226308,12.541745 -1.966961,-4.055469 -6.005853,-9.61727 -6.536087,-14.111845 z m 8.003322,1.026997 c 2.327368,-4.130254 -4.046386,-4.335875 -3.448274,-0.922879 0.345401,1.572603 2.280617,2.090534 3.448274,0.922879 z"
|
||||||
id="path842"
|
id="path842"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
<path
|
<path
|
||||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.39091456;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.32129965"
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.39091456;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.32129965"
|
||||||
d="m 40.048125,68.631745 c -3.078476,-6.03888 -3.783284,-7.98438 -3.538787,-9.76818 0.439793,-3.20864 3.281227,-5.69672 6.505777,-5.69672 2.45765,0 4.41816,1.14913 5.70407,3.34337 0.91386,1.55938 1.08252,3.16179 0.53365,5.06989 -0.45531,1.58281 -5.89584,12.54174 -6.22631,12.54174 -0.0988,0 -1.43911,-2.47055 -2.9784,-5.4901 z m 4.44563,-7.59475 c 1.16819,-1.16819 0.58061,-3.06088 -1.07961,-3.47757 -1.30134,-0.32662 -2.67589,1.15589 -2.36866,2.55469 0.3454,1.57261 2.28062,2.09054 3.44827,0.92288 z"
|
d="m 40.048125,68.631745 c -3.078476,-6.03888 -3.783284,-7.98438 -3.538787,-9.76818 0.439793,-3.20864 3.281227,-5.69672 6.505777,-5.69672 2.45765,0 4.41816,1.14913 5.70407,3.34337 0.91386,1.55938 1.08252,3.16179 0.53365,5.06989 -0.45531,1.58281 -5.89584,12.54174 -6.22631,12.54174 -0.0988,0 -1.43911,-2.47055 -2.9784,-5.4901 z m 4.44563,-7.59475 c 1.16819,-1.16819 0.58061,-3.06088 -1.07961,-3.47757 -1.30134,-0.32662 -2.67589,1.15589 -2.36866,2.55469 0.3454,1.57261 2.28062,2.09054 3.44827,0.92288 z"
|
||||||
|
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.5 KiB |
835
package-lock.json
generated
835
package-lock.json
generated
File diff suppressed because it is too large
Load diff
24
package.json
24
package.json
|
@ -18,17 +18,16 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/sbrl/ConnectedHumber-Air-Quality-Interface#readme",
|
"homepage": "https://github.com/sbrl/ConnectedHumber-Air-Quality-Interface#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.4",
|
||||||
"chroma-js": "^2.1.0",
|
"chroma-js": "^2.1.0",
|
||||||
"d3-delaunay": "^5.2.1",
|
|
||||||
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
"dom-create-element-query-selector": "github:hekigan/dom-create-element-query-selector",
|
||||||
"event-emitter-es6": "^1.1.5",
|
"event-emitter-es6": "^1.1.5",
|
||||||
"iso8601-js-period": "^0.2.1",
|
"iso8601-js-period": "^0.2.1",
|
||||||
"leaflet": "^1.6.0",
|
"leaflet": "^1.7.1",
|
||||||
"leaflet-easyprint": "^2.1.9",
|
"leaflet-easyprint": "^2.1.9",
|
||||||
"leaflet-fullscreen": "^1.0.2",
|
"leaflet-fullscreen": "^1.0.2",
|
||||||
"leaflet.markercluster": "^1.4.1",
|
"leaflet.markercluster": "^1.4.1",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.29.1",
|
||||||
"nanomodal": "^5.1.1",
|
"nanomodal": "^5.1.1",
|
||||||
"shepherd.js": "^7.1.4",
|
"shepherd.js": "^7.1.4",
|
||||||
"smartsettings": "^1.2.3",
|
"smartsettings": "^1.2.3",
|
||||||
|
@ -36,22 +35,23 @@
|
||||||
"xml-writer": "^1.7.0"
|
"xml-writer": "^1.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chart.js": "^2.9.21",
|
"@types/chart.js": "^2.9.30",
|
||||||
"@types/chroma-js": "^2.0.0",
|
"@types/chroma-js": "^2.1.3",
|
||||||
"@types/d3-delaunay": "^4.1.0",
|
|
||||||
"@types/event-emitter-es6": "^1.1.0",
|
"@types/event-emitter-es6": "^1.1.0",
|
||||||
"@types/leaflet": "^1.5.12",
|
"@types/leaflet": "^1.5.21",
|
||||||
"@types/leaflet-fullscreen": "^1.0.4",
|
"@types/leaflet-fullscreen": "^1.0.4",
|
||||||
"nightdocs": "^1.0.9",
|
"nightdocs": "^1.0.9",
|
||||||
|
"postcss": "^8.2.4",
|
||||||
"postcss-copy": "^7.1.0",
|
"postcss-copy": "^7.1.0",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-import": "^14.0.0",
|
||||||
"rollup": "^2.7.2",
|
"rollup": "^2.38.1",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-json": "^4.0.0",
|
"rollup-plugin-json": "^4.0.0",
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
"rollup-plugin-postcss": "^3.1.1",
|
"rollup-plugin-postcss": "^4.0.0",
|
||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"rollup-plugin-terser": "^5.3.0"
|
"rollup-plugin-string": "^3.0.0",
|
||||||
|
"rollup-plugin-terser": "^7.0.2"
|
||||||
},
|
},
|
||||||
"docpress": {
|
"docpress": {
|
||||||
"github": "ConnectedHumber/Air-Quality-Web",
|
"github": "ConnectedHumber/Air-Quality-Web",
|
||||||
|
|
|
@ -8,6 +8,7 @@ import postcss from 'rollup-plugin-postcss';
|
||||||
import { terser } from "rollup-plugin-terser";
|
import { terser } from "rollup-plugin-terser";
|
||||||
import replace from 'rollup-plugin-replace';
|
import replace from 'rollup-plugin-replace';
|
||||||
import json from 'rollup-plugin-json';
|
import json from 'rollup-plugin-json';
|
||||||
|
import { string } from 'rollup-plugin-string'
|
||||||
|
|
||||||
import postcss_import from 'postcss-import';
|
import postcss_import from 'postcss-import';
|
||||||
import postcss_copy from 'postcss-copy';
|
import postcss_copy from 'postcss-copy';
|
||||||
|
@ -40,6 +41,10 @@ let plugins = [
|
||||||
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
string({
|
||||||
|
include: '**/*.svg'
|
||||||
|
}),
|
||||||
|
|
||||||
replace({
|
replace({
|
||||||
exclude: 'node_modules/**',
|
exclude: 'node_modules/**',
|
||||||
values: {
|
values: {
|
||||||
|
|
Loading…
Reference in a new issue