Skip to content

Commit

Permalink
Fix and simplify the lasso code
Browse files Browse the repository at this point in the history
(closes #1621)
  • Loading branch information
bhousel committed Nov 25, 2024
1 parent d758851 commit baaa44a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 60 deletions.
4 changes: 2 additions & 2 deletions modules/behaviors/LassoBehavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class LassoBehavior extends AbstractBehavior {

// Push the polygon data to the map UI for rendering.
const mapUILayer = gfx.scene.layers.get('map-ui');
mapUILayer.lassoPolygonData = this._coords;
mapUILayer.lassoData = this._coords;
gfx.immediateRedraw();
}

Expand All @@ -136,7 +136,7 @@ export class LassoBehavior extends AbstractBehavior {

const ids = this._lassoed();
this._coords = [];
mapUILayer.lassoPolygonData = this._coords;
mapUILayer.lassoData = null;

this._extent = null;

Expand Down
6 changes: 3 additions & 3 deletions modules/pixi/PixiGeometry.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Extent, geomGetSmallestSurroundingRectangle, vecInterp } from '@rapid-sdk/math';
import { polygonHull as d3_polygonHull, polygonCentroid as d3_polygonCentroid } from 'd3-polygon';
import { polygonHull, polygonCentroid } from 'd3-polygon';
import polylabel from '@mapbox/polylabel';


Expand Down Expand Up @@ -205,7 +205,7 @@ export class PixiGeometry {
this.hull[i] = viewport.project(this.origHull[i]);
}
} else { // recalculate and store as WGS84
this.hull = d3_polygonHull(this.outer);
this.hull = polygonHull(this.outer);
if (this.hull) {
this.origHull = new Array(this.hull.length);
for (let i = 0; i < this.origHull.length; ++i) {
Expand All @@ -221,7 +221,7 @@ export class PixiGeometry {
if (this.hull.length === 2) {
this.centroid = vecInterp(this.hull[0], this.hull[1], 0.5); // average the 2 points
} else {
this.centroid = d3_polygonCentroid(this.hull);
this.centroid = polygonCentroid(this.hull);
}
this.origCentroid = viewport.unproject(this.centroid);
}
Expand Down
119 changes: 64 additions & 55 deletions modules/pixi/PixiLayerMapUI.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as PIXI from 'pixi.js';
import { geoMetersToLon } from '@rapid-sdk/math';
import { geoMetersToLon, vecEqual } from '@rapid-sdk/math';

import { AbstractLayer } from './AbstractLayer.js';
import { DashLine } from './lib/DashLine.js';
Expand Down Expand Up @@ -69,19 +69,29 @@ groupContainer.addChild(container);
this.selectedContainer = selectedContainer;

// Lasso polygon
this._lassoPolygonData = null;
this._lassoPolygonDirty = false;
this._lassoLineGraphics = new PIXI.Graphics();
this._lassoFillGraphics = new PIXI.Graphics();
const lassoContainer = new PIXI.Container();
lassoContainer.label= 'lasso';
lassoContainer.eventMode = 'none';
lassoContainer.sortableChildren = false;
lassoContainer.visible = true;
lassoContainer.addChild(this._lassoLineGraphics, this._lassoFillGraphics);
this.lassoContainer = lassoContainer;

this.container.addChild(geolocationContainer, tileDebugContainer, selectedContainer, lassoContainer);
this._lassoData = null;
this._lassoDirty = false;
this._lassoLine = new PIXI.Graphics();
this._lassoFill = new PIXI.Graphics();
const lasso = new PIXI.Container();
lasso.label= 'lasso';
lasso.eventMode = 'none';
lasso.sortableChildren = false;
lasso.visible = true;
this.lasso = lasso;

this.container.addChild(geolocationContainer, tileDebugContainer, selectedContainer, lasso);
}


/**
* reset
* Every Layer should have a reset function to clear out any state when a reset occurs.
*/
reset() {
super.reset();
this._lassoData = null;
this.lasso.removeChildren();
}


Expand Down Expand Up @@ -111,14 +121,15 @@ groupContainer.addChild(container);


/**
* lassoPolygonData
* lassoData
* Pass an array of coordinate data that grows at the user draws the lasso
*/
get lassoPolygonData() {
return this._lassoPolygonData;
get lassoData() {
return this._lassoData;
}
set lassoPolygonData(val) {
this._lassoPolygonData = val;
this._lassoPolygonDirty = true;
set lassoData(val) {
this._lassoData = val;
this._lassoDirty = true;
}


Expand All @@ -133,15 +144,15 @@ groupContainer.addChild(container);
const k = viewport.transform.scale;
if (k !== this._oldk) {
this._geolocationDirty = true;
this._lassoPolygonDirty = true;
this._lassoDirty = true;
this._oldk = k;
}

if (this._geolocationDirty) {
this.renderGeolocation(frame, viewport);
}

if (this._lassoPolygonDirty) {
if (this._lassoDirty) {
this.renderLasso(frame, viewport);
}

Expand All @@ -154,49 +165,47 @@ groupContainer.addChild(container);
* @param viewport Pixi viewport to use for rendering
*/
renderLasso(frame, viewport) {
if (this._lassoPolygonDirty) {
this._lassoPolygonDirty = false;
}
if (!this._lassoDirty) return;

const LASSO_STYLE = {
alpha: 0.7,
dash: [6, 3],
width: 1, // px
color: 0xffffff
};

// Simple state machine: If there's lasso data set, ensure that the lasso graphcs are added to the container.
// If there's no lasso data set, remove the graphics from the container and stop rendering.

// No polygon data? remove the graphics from the container.
if (!this._lassoPolygonData && this._lassoLineGraphics.parent) {
this.lassoContainer.removeChildren();

} else {
// Otherwise, we have polygon data but no parent. Add the graphics to the lasso container.
if (!this._lassoLineGraphics.parent) {
this.lassoContainer.addChild(this._lassoLineGraphics);
this.lassoContainer.addChild(this._lassoFillGraphics);
const container = this.lasso;
const line = this._lassoLine;
const fill = this._lassoFill;
const data = this._lassoData;

if (Array.isArray(data) && data.length > 1) { // should show lasso
if (!container.children.length) {
container.addChild(line, fill);
}

// Make sure the lasso is closed
const coords = data.slice(); // shallow copy
const start = coords.at(0);
const end = coords.at(-1);
if (!vecEqual(start, end)) {
coords.push(start);
}

// Update polygon rendered to map UI
this._lassoLineGraphics.clear();
this._lassoFillGraphics.clear();
const flatCoords = coords.map(coord => viewport.project(coord)).flat();

// Render the data only as long as we have something meaningful.
if (this._lassoPolygonData?.length > 0) {
const projectedCoords = this._lassoPolygonData.map(coord => viewport.project(coord));
// line
const lineStyle = { alpha: 0.7, dash: [6, 3], width: 1, color: 0xffffff };
line.clear();
new DashLine(line, lineStyle).poly(flatCoords);

new DashLine(this._lassoLineGraphics, LASSO_STYLE)
.poly(projectedCoords.flat());
// fill
const fillStyle = { alpha: 0.5, color: 0xaaaaaa };
fill.clear().poly(flatCoords).fill(fillStyle);

this._lassoFillGraphics
.poly(projectedCoords.flat())
.fill({color: 0xaaaaaa, width: 0.5 });
} else { // no lasso data
if (container.children.length) {
container.removeChildren();
}
}

this._lassoDirty = false;
}


/**
* renderGeolocation
* Render the geoloation data
Expand Down

0 comments on commit baaa44a

Please sign in to comment.