mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-11-22 06:23:01 +00:00
Start implementing VoronoiOverlay, but there's a looong way to go.
This commit is contained in:
parent
a8444fdde6
commit
c1b13cda22
5 changed files with 320 additions and 2 deletions
247
client_src/js/Helpers/Rectangle.mjs
Normal file
247
client_src/js/Helpers/Rectangle.mjs
Normal file
|
@ -0,0 +1,247 @@
|
|||
"use strict";
|
||||
|
||||
import Vector from './Vector2.mjs';
|
||||
|
||||
/**
|
||||
* Represents a rectangle in 2D space.
|
||||
* @source https://gist.github.com/d7ff700d3ca57ab5d52ec12a1ee8b8a0
|
||||
* Changelog:
|
||||
* 29th May 2019
|
||||
* Created this changelog
|
||||
* Added setters to TopLeft, Top, Size, etc.
|
||||
*/
|
||||
class Rectangle
|
||||
{
|
||||
/**
|
||||
* The top-left corner of the rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get TopLeft() {
|
||||
return new Vector(this.x, this.y);
|
||||
}
|
||||
/**
|
||||
* Sets the top-left corner of the rectangle.
|
||||
* @param {Vector} point The point to set it to.
|
||||
*/
|
||||
set TopLeft(point) {
|
||||
this.x = point.x;
|
||||
this.y = point.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The top-right corner of the rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get TopRight() {
|
||||
return new Vector(this.x + this.width, this.y);
|
||||
}
|
||||
/**
|
||||
* Sets the top-right corner of the rectangle.
|
||||
* @param {Vector} point The point to set it to.
|
||||
*/
|
||||
set TopRight(point) {
|
||||
this.width = point.x - this.x;
|
||||
this.y = point.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bottom-left corner of the rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get BottomLeft() {
|
||||
return new Vector(this.x, this.y + this.height);
|
||||
}
|
||||
/**
|
||||
* Sets the bottom-left corner of the rectangle.
|
||||
* @param {Vector} point The point to set it to.
|
||||
*/
|
||||
set BottomLeft(point) {
|
||||
this.width = point.x;
|
||||
this.y = point.y - this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bottom-right corner of the rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get BottomRight() {
|
||||
return new Vector(this.x + this.width, this.y + this.height);
|
||||
}
|
||||
/**
|
||||
* Sets the bottom-right corner of the rectangle.
|
||||
* @param {Vector} point The point to set it to.
|
||||
*/
|
||||
set BottomRight(point) {
|
||||
this.width = point.x - this.x;
|
||||
this.y = point.y - this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The centre of the rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get Centre() {
|
||||
return new Vector(
|
||||
this.x + (this.width/2),
|
||||
this.y + (this.height/2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Y coordinate of the top of the rectangle.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get Top() {
|
||||
return this.y;
|
||||
}
|
||||
/**
|
||||
* Sets the Y coordinate of the top of the rectangle.
|
||||
* @param {Number} y
|
||||
*/
|
||||
set Top(y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Y coordinate of the bottom of the rectangle.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get Bottom() {
|
||||
return this.y + this.height;
|
||||
}
|
||||
/**
|
||||
* Sets the Y coordinate of the bottom of the rectangle.
|
||||
* @param {Number} y
|
||||
*/
|
||||
set Bottom(y) {
|
||||
this.height = y - this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The X coordinate of the left side of the rectangle.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get Left() {
|
||||
return this.x;
|
||||
}
|
||||
/**
|
||||
* Sets the X coordinate of the left of the rectangle.
|
||||
* @param {Number} x
|
||||
*/
|
||||
set Left(x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* The X coordinate of the right side of the rectangle.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get Right() {
|
||||
return this.x + this.width;
|
||||
}
|
||||
/**
|
||||
* Sets the X coordinate of the right of the rectangle.
|
||||
* @param {Number} x
|
||||
*/
|
||||
set Right(x) {
|
||||
this.x = x - this.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of this rectangle.
|
||||
* @returns {Vector}
|
||||
*/
|
||||
get Size() {
|
||||
return new Vector(this.width, this.height);
|
||||
}
|
||||
/**
|
||||
* Sets the size of the rectangle.
|
||||
* @param {Vector} newSize The new size of the rectangle.
|
||||
*/
|
||||
set Size(newSize) {
|
||||
this.width = newSize.x;
|
||||
this.height = newSize.y;
|
||||
}
|
||||
|
||||
constructor(x, y, width, height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this Rectangle by the specified vector.
|
||||
* @param {Vector} v The amount to move this Rectangle by.
|
||||
* @return {Rectangle} The current rectangle. Useful for daisy-chaining.
|
||||
*/
|
||||
move_by(v) {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out whether this rectangle overlaps another rectangle.
|
||||
* @param {Rectangle} otherRectangle The other rectangle to check the overlap of.
|
||||
* @return {bool} Whether this rectangle overlaps another rectangle.
|
||||
*/
|
||||
overlaps(otherRectangle)
|
||||
{
|
||||
if(this.Top > otherRectangle.Bottom ||
|
||||
this.Bottom < otherRectangle.Top ||
|
||||
this.Left > otherRectangle.Right ||
|
||||
this.Right < otherRectangle.Left)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Works out whether the specified vector falls within this Rectangle.
|
||||
* @param {Vector} v The vector to test.
|
||||
* @return {Boolean} Whether the specified vector falls within this Rectangle or not.
|
||||
*/
|
||||
is_inside_vector(v) {
|
||||
return v.x >= this.x && v.y >= this.y &&
|
||||
v.x <= this.Right && v.y <= this.Bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Works out if this Rectangle falls completely within the specified
|
||||
* rectangle.
|
||||
* @param {Rectangle} otherRectangle The other rectangle to compare against.
|
||||
* @return {Boolean} Whether this Rectangle faalls within the specified Rectangle.
|
||||
*/
|
||||
is_inside(otherRectangle) {
|
||||
if(this.Top >= otherRectangle.Top &&
|
||||
this.Bottom <= otherRectangle.Bottom &&
|
||||
this.Left >= otherRectangle.Left &&
|
||||
this.Right <= otherRectangle.Right)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this rectangle that can be safely edited without affecting the original.
|
||||
* @returns {Rectangle}
|
||||
*/
|
||||
clone()
|
||||
{
|
||||
return new Rectangle(this.x, this.y, this.width, this.height);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[Rectangle @ (${this.x}, ${this.y}) ${this.width} x ${this.height}]`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A rectangle with all it's values initalised to zero.
|
||||
* Don't forget to clone it before editing!
|
||||
* @type {Rectangle}
|
||||
*/
|
||||
Rectangle.Zero = new Rectangle(0, 0, 0, 0);
|
||||
|
||||
export default Rectangle;
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import XMLWriter from 'xml-writer';
|
||||
|
||||
import Rectangle from './Rectangle.mjs';
|
||||
import Vector2 from './Vector2.mjs';
|
||||
|
||||
/*
|
||||
|
@ -11,8 +12,12 @@ import Vector2 from './Vector2.mjs';
|
|||
* @license MPL-2.0
|
||||
*/
|
||||
class SvgWriter {
|
||||
constructor(viewBox) {
|
||||
// string outputFilename, string widthspec = "100%", string heightspec = "100%", Rectangle? rawViewBox = null
|
||||
/**
|
||||
* @param {String} [widthspec="100%"]
|
||||
* @param {String} [heightspec="100%"]
|
||||
* @param {Retangle} [viewBox=null]
|
||||
*/
|
||||
constructor(widthspec = "100%", heightspec = "100%", viewBox = null) {
|
||||
this.unitSuffix = "";
|
||||
|
||||
// ----------------------------------
|
||||
|
|
|
@ -1,9 +1,69 @@
|
|||
"use strict";
|
||||
|
||||
import Voronoi from 'voronoi';
|
||||
|
||||
import Vector2 from '../Helpers/Vector2.mjs';
|
||||
import Rectangle from '../Helpers/Rectangle.mjs';
|
||||
|
||||
import SvgWriter from '../Helpers/SVGWriter.mjs';
|
||||
|
||||
|
||||
/**
|
||||
* Generates and manages a single voronoi SVGOverlay layer.
|
||||
*/
|
||||
class VoronoiOverlay {
|
||||
constructor() {
|
||||
this.border = new Vector2(0.1, 0.1); // lat / long
|
||||
|
||||
this.cells = [];
|
||||
}
|
||||
|
||||
addCells(...cells) {
|
||||
this.cells.push(...cells);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the bounding box of all the currently registered points.
|
||||
* Includes a border, which is defined by this.border.
|
||||
* @return {Rectangle} The bounding box of the currently registered points.
|
||||
*/
|
||||
computeBoundingBox() {
|
||||
let result = new Rectangle(Infinity, Infinity, -Infinity, -Infinity);
|
||||
|
||||
for(let cell of this.cells) {
|
||||
if(cell.point.x < result.x) result.x = cell.point.x;
|
||||
if(cell.point.y < result.y) result.y = cell.point.y;
|
||||
if(cell.point.x > result.Right) result.Right = cell.point.x;
|
||||
if(cell.point.y > result.Bottom) result.Bottom = cell.point.y;
|
||||
}
|
||||
|
||||
result.Left -= this.border.x;
|
||||
result.Right += this.border.x;
|
||||
result.Top -= this.border.y;
|
||||
result.Bottom += this.border.y;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
render() {
|
||||
let bounding_box = this.computeBoundingBox();
|
||||
|
||||
// Recycle the diagram object if possible
|
||||
if(typeof VoronoiOverlay.diagram !== "undefined")
|
||||
VoronoiOverlay.voronoi.recycle(VoronoiOverlay.diagram);
|
||||
|
||||
VoronoiOverlay.diagram = VoronoiOverlay.voronoi.compute(
|
||||
this.cells.map((cell) => cell.point),
|
||||
bounding_box
|
||||
);
|
||||
|
||||
console.log(VoronoiOverlay.diagram)
|
||||
|
||||
let svg = new SvgWriter();
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOverlay.voronoi = new Voronoi();
|
||||
|
||||
|
||||
export default VoronoiOverlay;
|
||||
|
|
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -4362,6 +4362,11 @@
|
|||
"integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"voronoi": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/voronoi/-/voronoi-1.0.0.tgz",
|
||||
"integrity": "sha1-wIPK+pjENZpRgBi/6IYkyyJ6wpE="
|
||||
},
|
||||
"xml-writer": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-writer/-/xml-writer-1.7.0.tgz",
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"nanomodal": "^5.1.1",
|
||||
"smartsettings": "^1.2.3",
|
||||
"tabs": "^0.2.0",
|
||||
"voronoi": "^1.0.0",
|
||||
"xml-writer": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
Loading…
Reference in a new issue