2019-05-29 19:21:03 +00:00
"use strict" ;
2019-06-10 22:24:28 +00:00
import L from 'leaflet' ;
import { Delaunay } from 'd3-delaunay' ;
2019-05-29 20:06:00 +00:00
import Vector2 from '../Helpers/Vector2.mjs' ;
import Rectangle from '../Helpers/Rectangle.mjs' ;
2019-06-10 23:32:01 +00:00
import SvgWriter from '../Helpers/SvgWriter.mjs' ;
2019-05-29 20:06:00 +00:00
/ * *
* Generates and manages a single voronoi SVGOverlay layer .
* /
2019-05-29 19:21:03 +00:00
class VoronoiOverlay {
constructor ( ) {
2019-05-29 20:06:00 +00:00
this . border = new Vector2 ( 0.1 , 0.1 ) ; // lat / long
this . cells = [ ] ;
}
2019-06-10 23:19:37 +00:00
/ * *
* Adds a cell to the voronoi overlay .
* @ param { VoronoiCell } cells The cell to add . May be specified as many times as requires to add cells in bulk .
* /
2019-05-29 20:06:00 +00:00
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 ( ) {
2019-06-10 22:24:28 +00:00
let result = {
x _min : Infinity ,
x _max : - Infinity ,
y _min : Infinity ,
y _max : - Infinity
}
2019-05-29 20:06:00 +00:00
for ( let cell of this . cells ) {
2019-06-10 23:19:37 +00:00
// TODO: Remove this restriction
2019-06-10 23:32:01 +00:00
if ( cell . point . y < 40 ) continue ; // Exclude the freetown one for testing 'cause it's miles away
2019-06-10 23:19:37 +00:00
if ( cell . point . x < result . x _min ) result . x _min = cell . point . x ;
if ( cell . point . x > result . x _max ) result . x _max = cell . point . x ;
if ( cell . point . y < result . y _min ) result . y _min = cell . point . y ;
if ( cell . point . y > result . y _max ) result . y _max = cell . point . y ;
2019-05-29 20:06:00 +00:00
}
2019-05-29 19:21:03 +00:00
2019-06-10 22:24:28 +00:00
result . x _min -= this . border . x ;
result . y _min -= this . border . y ;
result . x _max += this . border . x ;
result . y _max += this . border . y ;
2019-05-29 20:06:00 +00:00
2019-06-10 22:24:28 +00:00
return new Rectangle (
result . x _min ,
result . y _min ,
result . x _max - result . x _min ,
result . y _max - result . y _min
) ;
2019-05-29 20:06:00 +00:00
}
render ( ) {
let bounding _box = this . computeBoundingBox ( ) ;
2019-06-10 22:24:28 +00:00
let voronoi = Delaunay . from ( this . cells . map (
( cell ) => [ cell . point . x , cell . point . y ] )
) . voronoi ( [
bounding _box . x , bounding _box . y ,
bounding _box . Right , bounding _box . Bottom
] ) ;
2019-05-29 20:06:00 +00:00
2019-06-10 22:24:28 +00:00
console . log ( voronoi ) ;
2019-05-29 20:08:01 +00:00
// TODO: Map the generated polygons back onto this.cells
2019-06-10 22:24:28 +00:00
let i = 0 ;
for ( let polygon of voronoi . cellPolygons ( ) ) {
let our _cell = this . cells [ i ] ;
our _cell . polygon = polygon . map ( ( point ) => new Vector2 ( ... point ) ) ;
i ++ ;
2019-06-09 22:51:41 +00:00
}
console . log ( this . cells ) ;
2019-05-29 20:06:00 +00:00
2019-06-11 00:07:11 +00:00
// TODO: Investigate GeoJSON. Maybe it could help us avoid the complexity of an SVGOverlay? It looks like we might be able to apply a custom colour to a GeoJSON polygon too: https://leafletjs.com/reference-1.5.0.html#geojson
2019-06-10 23:19:37 +00:00
let svg = new SvgWriter (
2019-06-10 22:24:28 +00:00
"100%" , "100%" ,
bounding _box ,
true
) ;
2019-05-29 20:08:01 +00:00
// TODO: Render the SVG here
2019-06-10 22:24:28 +00:00
for ( let cell of this . cells ) {
2019-06-10 23:19:37 +00:00
if ( cell . polygon !== null ) {
svg . addPolygon (
` hsla( ${ ( Math . random ( ) * 360 ) . toFixed ( 2 ) } , 50%, 50%, 0.6) ` ,
cell . polygon
) ;
}
svg . addCircle ( cell . point , 0.005 , "red" ) ;
2019-06-10 22:24:28 +00:00
}
2019-06-10 23:19:37 +00:00
svg . complete ( ) ;
console . log ( svg . toString ( ) ) ;
return svg . toString ( ) ;
2019-06-10 22:24:28 +00:00
}
add _to ( map ) {
let bounds = this . computeBoundingBox ( ) ;
this . layer = L . svgOverlay (
SvgWriter . string2element ( this . render ( ) ) ,
L . latLngBounds (
2019-06-10 23:32:01 +00:00
L . latLng ( bounds . TopLeft . y , bounds . TopLeft . x ) ,
L . latLng ( bounds . BottomRight . y , bounds . BottomRight . x )
2019-06-10 22:24:28 +00:00
)
) ;
this . layer . addTo ( map ) ;
2019-05-29 20:08:01 +00:00
}
generate _overlay ( ) {
// TODO: Generate the Leaflet SVGOverlay here
2019-05-29 19:21:03 +00:00
}
}
2019-05-29 20:06:00 +00:00
2019-05-29 19:21:03 +00:00
export default VoronoiOverlay ;