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

task/WG-83: Handle Overlapping Point Clouds #181

Merged
merged 9 commits into from
Dec 18, 2023
33 changes: 25 additions & 8 deletions angular/src/app/components/map/map.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '@bagage/leaflet.vectorgrid';
import { Viewer, ViewerOptions } from 'mapillary-js';
import { ProjectsService } from '../../services/projects.service';
import { GeoDataService } from '../../services/geo-data.service';
import { createMarker } from '../../utils/leafletUtils';
import { createMarker, calculateMarkerPosition } from '../../utils/leafletUtils';
import { Feature } from 'geojson';
import { FeatureGroup, Layer, LayerGroup, LeafletMouseEvent, TileLayer } from 'leaflet';
import * as turf from '@turf/turf';
Expand Down Expand Up @@ -350,6 +350,14 @@ export class MapComponent implements OnInit, OnDestroy {
let feat: LayerGroup;
if (d.geometry.type === 'Polygon' && d.properties.style) {
feat = L.geoJSON(d, { style: d.properties.style });
} else if (d.featureType() === 'point_cloud') {
feat = L.geoJSON(d, { style: d.properties.style });
const markerPosition = calculateMarkerPosition(d.geometry);
const pointCloudMarker = createMarker(d, markerPosition);
pointCloudMarker.on('click', (ev) => {
this.featureClickHandler(ev, 'click');
});
markers.addLayer(pointCloudMarker);
nathanfranklin marked this conversation as resolved.
Show resolved Hide resolved
} else if (d.featureType() === 'streetview') {
feat = L.geoJSON(d, {
style: streetviewAssetStyles.feature.default,
Expand Down Expand Up @@ -398,13 +406,22 @@ export class MapComponent implements OnInit, OnDestroy {
}

featureClickHandler(ev: any, clickType: string): void {
if (ev.layer.feature.featureType() === 'streetview') {
this.streetviewService.sequenceFeatureToActiveAsset(ev.layer.feature).subscribe((e) => {
this.mapillaryClickHandler(e, clickType);
});
} else {
const f = ev.layer.feature;
this.geoDataService.activeFeature = f;
let f;
// First checks if clicked object is a marker
if (ev.target && ev.target.options.feature) {
f = ev.target.options.feature;
// Otherwise checks if a geoJSON layer with a feature prop
} else if (ev.layer && ev.layer.feature) {
f = ev.layer.feature;
}
if (f) {
if (f.featureType() === 'streetview') {
this.streetviewService.sequenceFeatureToActiveAsset(f).subscribe((e) => {
this.mapillaryClickHandler(e, clickType);
});
} else {
this.geoDataService.activeFeature = f;
}
}
}

Expand Down
39 changes: 35 additions & 4 deletions angular/src/app/utils/leafletUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CircleMarker, Path, circleMarker, divIcon, LatLng, Marker, marker } from 'leaflet';
import { CircleMarker, Path, circleMarker, divIcon, LatLng, Marker, MarkerOptions, marker, icon, geoJSON } from 'leaflet';
import { Feature } from '../models/models';
import { MarkerStyle } from '../models/style';

Expand All @@ -7,6 +7,13 @@ interface MarkerIcon {
name: string;
}

// Needed to add feature to marker options (for click events)
declare module 'leaflet' {
interface MarkerOptions {
feature?: Feature;
}
}

function createCircleMarker(feature: Feature, latlng: LatLng): CircleMarker {
const options = {
radius: 8,
Expand Down Expand Up @@ -38,9 +45,9 @@ function createVideoMarker(feature: Feature, latlng: LatLng): Marker {
}

function createCustomIconMarker(latlng: LatLng, style: MarkerStyle): Marker {
const icon = style.faIcon;
const faIcon = style.faIcon;
const color = style.color;
const divHtml = `<i class="fas ${icon} fa-2x" style="color: ${color}"></i>`;
const divHtml = `<i class="fas ${faIcon} fa-2x" style="color: ${color}"></i>`;
const ico = divIcon({ className: 'leaflet-fa-marker-icon', html: divHtml });
return marker(latlng, { icon: ico, ...style });
}
Expand All @@ -55,8 +62,32 @@ function createCustomCircleMarker(latlng: LatLng, style: MarkerStyle): CircleMar
return circleMarker(latlng, style);
}

function createPointCloudMarker(feature: Feature, latlng: LatLng): Marker {
const divHtml = '<i class="fab fa-mixcloud fa-2x light-blue"></i>';
const customIcon = divIcon({
className: 'leaflet-fa-marker-icon',
html: divHtml,
iconSize: [32, 32],
iconAnchor: [16, 16],
});
// Adding feature data to options prop of marker to statisfy TS type errors
return marker(latlng, {
icon: customIcon,
feature, // shorthand
});
}

// Used to find the top-left corner of our point-clouds to help with overlapping
export function calculateMarkerPosition(geoJsonPolygon): LatLng {
const layer = geoJSON(geoJsonPolygon); // Convert GeoJSON Polygon to Leaflet Layer
const bounds = layer.getBounds();
return new LatLng(bounds.getNorth(), bounds.getWest()); // Top-left corner
}

export function createMarker(feature: Feature, latlng: LatLng): Marker | CircleMarker {
if (feature.properties.style) {
if (feature.featureType() === 'point_cloud') {
return createPointCloudMarker(feature, latlng);
} else if (feature.properties.style) {
const style = feature.properties.style;
if (style.faIcon) {
return createCustomIconMarker(latlng, style);
Expand Down
Loading