Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Locator Overlays aka 'Heatmaps'. #1437

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

[Draft] Locator Overlays aka 'Heatmaps'. #1437

wants to merge 9 commits into from

Conversation

Bonkles
Copy link
Contributor

@Bonkles Bonkles commented May 16, 2024

Locator overlays for Rapid Datasets are now a thing!

The procedure is as follows:

  1. Create a public vector data endpoint for the heatmap (an internal Meta process that I won't go into here).
  2. Hook our Rapid System code to the overlay using the code in this PR.
  3. Fire a new bit of pixi rendering code to draw very simple, highly transparent circle shapes for each point we get back from the vector heatmap endpoint.

This POC shows the resultant experience of zooming in at very high zooms over the continental US.

To test, enter poweruser mode and enable the 'meta Footways' dataset. You should then see the heatmap appear over the map if you're at low zooms (0-15). The color/checkbox for the dataset also propagates to the heatmap, so you get something like this:

overlays_color_switching_toggling.mov

The code creates a new layer above the map that styles any vector data points it gets from the heatmap endpoint. Right now, we don't do anything fancy- just draw a circle at 5% opacity at every point and make it large enough to overlap with its neighbors and the transparency stacking does a pretty good job.

@bhousel
Copy link
Contributor

bhousel commented May 16, 2024

This is going to be awesome! I can imagine this being useful for any of the data layers to be able to show users at low zoom where the data exists.

@@ -92,6 +92,11 @@ export class RapidSystem extends AbstractSystem {
enabled: false, // whether the user has checked it on
conflated: true,
service: 'mapwithai',
overlay: {
url: 'https://external.xx.fbcdn.net/maps/vtp/rapid_overlay_footways/1/{z}/{x}/{y}/',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure right now if it's possible for us to update an existing overlay without needing to respin rapid- i.e. generating a new overlay would necessarily bump the 1 in the url to a 2.

@@ -217,7 +217,7 @@ export class PixiFeaturePoint extends AbstractFeature {
// Apply effectiveZoom style adjustments
// This is where we adjust the actual texture and anchor properties
//
if (zoom < 16) { // Hide container and everything under it
if (zoom < 10) { // Hide container and everything under it
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, should probably remove this. Bryan and I did this while we were trying to get SOME points to display- no longer necessary as I'm not relying on PixiFeaturePoint to do the rendering.

modules/pixi/PixiLayerRapidOverlay.js Outdated Show resolved Hide resolved
const vtService = this.context.services.vectortile;
const datasets = this.context.systems.rapid.datasets;

// for (const [key, dataset] in datasets) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually this code should go through all the Rapid datasets and look for any overlays. For now it's hard-wired to just go looking for fbRoads.

To keep the PR minimal, I am demonstrating footways overlays wired up to fbRoads, but that's just for demo purposes. Footways impl is in a different branch.

modules/pixi/PixiLayerRapidOverlay.js Outdated Show resolved Hide resolved
overlayData = vtService.getData(overlay.url).map(d => d.geojson);
}

// const polygons = overlayData.filter(d => d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vector data we get back seems to consist of two bits of data:

Polygon borders for awater layer (which we can safely discard)
and Points that have a single property: weight. Presumably the weight is to control how bright/vivid the heatmap should be, but in empirical testing I saw values from 100 to 300,000.

modules/pixi/PixiLayerRapidOverlay.js Show resolved Hide resolved
modules/pixi/PixiLayerRapidOverlay.js Outdated Show resolved Hide resolved
…akes showing/hiding the overlays work as the checkbox is toggled.
@@ -118,6 +118,11 @@ export class RapidSystem extends AbstractSystem {
enabled: false, // whether the user has checked it on
conflated: true,
service: 'mapwithai',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 'overlay' section is entirely optional and the overlays rendering code will skip any dataset that doesn't have it defined.

const datasets = this.context.systems.rapid.datasets;
const parentContainer = this.overlaysContainer;

//Extremely inefficient but we're not drawing anything else at this zoom
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now we just expensively delete all the container's children at each render pass. and just redraw them. It's maybe a hundred points that we're rendering at a time, so it seems to stay lightning fast as we zoom in / out.

We could still also gain speed by texture-izing the points themselves instead of drawing circles and filling them, but again, this seems pretty quick.

}
const overlayData = vtService.getData(overlay.url).map(d => d.geojson);
const points = overlayData.filter(d => d.geometry.type === 'Point' || d.geometry.type === 'MultiPoint');
this.renderPoints(frame, viewport, zoom, points, customColor);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We call renderPoints once per dataset with an 'overlay' defined. Oh, the dataset has to be enabled too!

modules/pixi/PixiLayerRapidOverlay.js Outdated Show resolved Hide resolved

const xyCoords = viewport.project(coords);
const feature = new PIXI.Graphics().
beginFill(color, 0.05).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we just fill each point with a 5% transparency for now. It's kludgy and hacky to expect this to work - but for the fact that the points generated by the endpoint are dense enough to actually make this look pretty decent.

@Bonkles Bonkles marked this pull request as ready for review June 26, 2024 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: show heatmap of buildings or other layers at zoom 10-13
3 participants