Skip to content

Commit

Permalink
Merge pull request #3043 from bcgov/labels_by_extent_iapp
Browse files Browse the repository at this point in the history
#3028 IAPP Labels
  • Loading branch information
micheal-w-wells authored Jan 3, 2024
2 parents ee2c5ff + f6819ca commit f10bac3
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 75 deletions.
40 changes: 38 additions & 2 deletions appv2/src/UI/Map/LeafletCanvasLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import L from 'leaflet';
import { useLeafletContext } from '@react-leaflet/core';
import 'leaflet-markers-canvas';


const MAX_LABLES_TO_RENDER = 500

export const LeafletCanvasMarker = (props) => {
const map = useMap();
const context = useLeafletContext();
Expand Down Expand Up @@ -110,6 +113,14 @@ export const LeafletCanvasLabel = (props) => {
const layerRef = useRef();
const groupRef = useRef();


const [zoom, setZoom] = useState(map.getZoom());


map.on('zoomend', function () {
setZoom(map.getZoom());
})

useEffect(() => {
if (!map) return;
const container = context.layerContainer || context.map;
Expand All @@ -134,11 +145,36 @@ export const LeafletCanvasLabel = (props) => {

// console.log('label toggle');
// console.log(props.labelToggle);
console.log('map zoom:' + map.getZoom())
/*if((props.points?.features?.length > MAX_LABLES_TO_RENDER) && map.getZoom() < 10) {// && map.getZoom() < 13)){
//if(map.getZoom() < 10 ) {// && map.getZoom() < 13)){
return
}
*/
if(props.points?.features?.length > MAX_LABLES_TO_RENDER) {// && map.getZoom() < 13)){
return
}

/*
let countIndex = 0
*/
props.points?.features?.map((point) => {
if (props.labelToggle && props.points?.features.length < 5000) {

/*
if(countIndex > MAX_LABLES_TO_RENDER){
return
}
countIndex += 1
*/


if (props.labelToggle && props.points?.features.length ) {
if (!(point?.geometry?.coordinates?.length > 0)) {
return;
}



let labelImage;
if (props.layerType === 'IAPP') {
labelImage =
Expand Down Expand Up @@ -191,7 +227,7 @@ export const LeafletCanvasLabel = (props) => {
} catch (e) {}
};
//}, [map]);
}, [props.colour, props.labelToggle, props.enabled, props.points, props.zIndex, props.redraw]);
}, [zoom,props.colour, props.labelToggle, props.enabled, props.points, props.zIndex, props.redraw]);

return <></>;
};
151 changes: 85 additions & 66 deletions appv2/src/UI/Map/RecordSetLayersRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import 'leaflet-markers-canvas';
import { useDispatch } from 'react-redux';
import { SET_TOO_MANY_LABELS_DIALOG } from 'state/actions';
import { GeneralDialog } from './GeneralDialog';
import _ from 'lodash';
import _, { map } from 'lodash';
import { shallowEqual } from 'react-redux';
import { useState, useEffect } from 'react';

import * as turf from '@turf/turf';

import { LeafletCanvasLabel, LeafletCanvasMarker } from './LeafletCanvasLayer';
import { useMap } from 'react-leaflet';

export const RecordSetLayersRenderer = (props: any) => {
const ref = useRef(0);
Expand Down Expand Up @@ -47,106 +50,121 @@ export const RecordSetLayersRenderer = (props: any) => {
);
};

const LayerWrapper = memo(({ recordSetID }: any) => {
const LayerWrapper = (props) => {//memo(({ recordSetID }: any) => {
const ref = useRef(0);
ref.current += 1;
console.log(`%cLayerWrapper.tsx render ${recordSetID}:` + ref.current.toString(), 'color: green');
console.log(`%cLayerWrapper.tsx render ${props.recordSetID}:` + ref.current.toString(), 'color: green');

const type = useSelector( (state: any) => state.Map?.layers?.find((layer) => layer.recordSetID === recordSetID)?.type, shallowEqual)
const type = useSelector( (state: any) => state.Map?.layers?.find((layer) => layer?.recordSetID === props.recordSetID)?.type, shallowEqual)

const geoJSON = useSelector(
(state: any) =>
state.Map?.layers?.find((layer) => layer.recordSetID === props.recordSetID)?.geoJSON
? state.Map?.layers?.find((layer) => layer.recordSetID === props.recordSetID)?.geoJSON
: { type: 'FeatureCollection', features: [] },
(prev, next) => {
return prev?.features?.length == next?.features?.length && prev.features?.[0] == next.features?.[0];
}
);

// const type: any = 'Activity';
switch (type) {
case 'Activity':
return (
<>
<ActivitiesLayerV2 layerKey={recordSetID} />
<ActivitiesLayerV2 geoJSON={geoJSON} layerKey={props.recordSetID} />
{/*<ActivityCanvasLabelMemo layerKey={recordSetID} />*/}
</>
);
case 'IAPP':
return (
<>
<IAPPCanvasLayerMemo layerKey={recordSetID} />
<IAPPCanvasLabelMemo layerKey={recordSetID} />
<IAPPCanvasLayerMemo geoJSON={geoJSON} layerKey={props.recordSetID} />
<IAPPCanvasLabelMemo geoJSON={geoJSON} layerKey={props.recordSetID} />
</>
);
}

return <div key={'layerWrapper' + recordSetID}></div>;
});
return <div key={'layerWrapper' + props.recordSetID}></div>;
};

const IAPPCanvasLayerMemo = (props) => {
const IAPPGeoJSON = useSelector((state: any) => state.Map?.IAPPGeoJSON);
const layers = useSelector((state: any) => state.Map?.layers);


const layer = useSelector((state: any) => state.Map?.layers?.find((layer) => layer.recordSetID === props.layerKey));
const IAPPBoundsPolygon = useSelector((state: any) => state.Map?.IAPPBoundsPolygon);

const filteredFeatures = () => {
let returnVal;
if (layers?.[props.layerKey]?.IDList && layers?.[props.layerKey].layerState?.mapToggle && IAPPBoundsPolygon) {
returnVal = IAPPGeoJSON?.features.filter((row) => {
return layers?.[props.layerKey]?.IDList?.includes(row.properties.site_id);
});
} else {
returnVal = [];
}
let returnVal = [];
const points = { type: 'FeatureCollection', features: returnVal };
return pointsWithinPolygon(points as any, IAPPBoundsPolygon);
return props.geoJSON//pointsWithinPolygon(points as any, IAPPBoundsPolygon);
};

return useMemo(() => {
if (layers?.[props.layerKey]?.layerState) {
// return useMemo(() => {
if (layer?.layerState) {
return (
<LeafletCanvasMarker
key={'POICanvasLayermemo' + props.layerKey}
labelToggle={layers[props.layerKey].layerState.labelToggle}
labelToggle={layer?.layerState.labelToggle}
points={filteredFeatures()}
enabled={layers[props.layerKey].layerState.mapToggle}
colour={layers[props.layerKey].layerState.color}
zIndex={100000 + layers[props.layerKey].layerState.drawOrder}
enabled={layer?.layerState.mapToggle}
colour={layer?.layerState.color}
zIndex={100000 + layer?.layerState.drawOrder}
/>
);
} else return <></>;
}, [
JSON.stringify(layers?.[props.layerKey]?.layerState),
JSON.stringify(layers?.[props.layerKey]?.IDList, layers?.[props.layerKey].layerState?.mapToggle),
/* }, [
JSON.stringify(layer?.layerState),
JSON.stringify(layer?.IDList, layer?.layerState?.mapToggle),
JSON.stringify(IAPPBoundsPolygon)
]);
*/
};

const IAPPCanvasLabelMemo = (props) => {
const dispatch = useDispatch();
const labelBoundsPolygon = useSelector((state: any) => state.Map?.labelBoundsPolygon);
const IAPPBoundsPolygon = useSelector((state: any) => state.Map?.IAPPBoundsPolygon);
const layers = useSelector((state: any) => state.Map?.layers);
const layer = useSelector((state: any) => state.Map?.layers?.find((layer) => layer.recordSetID === props.layerKey));

const map = useMap()

const IAPPGeoJSON = useSelector(
(state: any) =>
state.Map?.layers?.find((layer) => layer.recordSetID === props.layerKey)?.geoJSON
? state.Map?.layers?.find((layer) => layer.recordSetID === props.layerKey)?.geoJSON
: { type: 'FeatureCollection', features: [] },
(prev, next) => {
return prev?.features?.length == next?.features?.length && prev.features?.[0] == next.features?.[0];
}
);

const layerStateColor = useSelector(
(state: any) => state.Map?.layers?.find((layer) => layer.recordSetID === props.layerKey)?.color,
shallowEqual
);
//CAP LABEL COUNT HERE
const IAPPBoundsPolygon = useSelector((state: any) => state.Map?.IAPPBoundsPolygon);

const [pointsInBounds, setPointsInBounds] = useState(null)

if(!props.geoJSON) return <></>

console.log('%cnumber of features to label ' + props.geoJSON?.features?.length, 'color: green')
const filteredFeatures = () => {
let returnVal;
if (labelBoundsPolygon && layers?.[props.layerKey]?.IDList && IAPPBoundsPolygon) {
returnVal = IAPPGeoJSON?.features.filter((row) => {
return layers?.[props.layerKey]?.IDList?.includes(row.properties.site_id);
});
} else {
returnVal = [];
}
let returnVal = [];
const points = { type: 'FeatureCollection', features: returnVal };
const pointsInBounds = pointsWithinPolygon(points as any, IAPPBoundsPolygon);
const pointsToLabel = pointsWithinPolygon(pointsInBounds as any, labelBoundsPolygon);
return props.geoJSON//pointsWithinPolygon(points as any, IAPPBoundsPolygon);
}

const [bounds, setBounds] = useState(null)


map.on('zoomend', function () {
const bboxString = map.getBounds().toBBoxString()
const bbox = JSON.parse('[' + bboxString + ']')
let newPointsInBounds = pointsWithinPolygon(props.geoJSON, turf.bboxPolygon(bbox))
setPointsInBounds(newPointsInBounds)
})
map.on('dragend', function () {
const bboxString = map.getBounds().toBBoxString()
const bbox = JSON.parse('[' + bboxString + ']')
let newPointsInBounds = pointsWithinPolygon(props.geoJSON, turf.bboxPolygon(bbox))
setPointsInBounds(newPointsInBounds)
})

//const pointsToLabel = pointsWithinPolygon(props.geoJSON, labelBoundsPolygon);
// only allow max labels
/*if (pointsToLabel?.features?.length > 5000) {
if (pointsToLabel?.features?.length > 5000) {
dispatch({
type: SET_TOO_MANY_LABELS_DIALOG,
Expand Down Expand Up @@ -178,32 +196,33 @@ const IAPPCanvasLabelMemo = (props) => {
}
}
});
return [];
}
}*/

return pointsToLabel;
};

return useMemo(() => {
if (layers?.[props.layerKey]?.layerState) {
// return useMemo(() => {
if (layer?.layerState) {
return (
<LeafletCanvasLabel
layerType={'IAPP'}
key={'POICanvasLayermemo' + props.layerKey}
labelToggle={layers[props.layerKey].layerState.labelToggle}
points={filteredFeatures()}
enabled={layers[props.layerKey].layerState.mapToggle}
colour={layers[props.layerKey].layerState.color}
zIndex={10000 + layers[props.layerKey].layerState.drawOrder}
// labelToggle={layer.layerState.labelToggle}
labelToggle={layer?.layerState?.labelToggle}
points={pointsInBounds}
enabled={layer.layerState.mapToggle}
colour={layer.layerState.color}
zIndex={10000 + layer.layerState.drawOrder}
/>
);
} else return <></>;
}, [
JSON.stringify(layers?.[props.layerKey]?.layerState),
JSON.stringify(layers?.[props.layerKey]?.IDList),
JSON.stringify(labelBoundsPolygon)
/* }, [
JSON.stringify(layer?.layerState),
JSON.stringify(layer?.IDList),
JSON.stringify(labelBoundsPolygon),
props.geoJSON
]);
};
*/
}

const ActivityCanvasLabelMemo = (props) => {
const layerState = useSelector(
Expand Down
2 changes: 1 addition & 1 deletion appv2/src/UI/Map/VectorOverviewLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const VectorOverviewLayer = (props) => {

layer.options.zIndex = 9999;

if (!map.hasLayer(layer)) {
if (!map.hasLayer(layer) ) {
container.addLayer(layer);
}

Expand Down
4 changes: 2 additions & 2 deletions appv2/src/UI/Overlay/Records/ExcelExporter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ const ExcelExporter = (props) => {
const CanTriggerCSV = useSelector((state: any) => state.Map.CanTriggerCSV)
const setType = useSelector((state: any) => state.UserSettings.recordSets[props.setName]?.recordSetType);
const [selection, setSelection] = useState(
setType === 'POI' ? 'site_selection_extract' : 'terrestrial_plant_observation'
setType === 'IAPP' ? 'site_selection_extract' : 'terrestrial_plant_observation'
);

let items;
if (setType === 'POI') {
if (setType === 'IAPP') {
items = [
<MenuItem value={'site_selection_extract'}>Site Selection Extract</MenuItem>,
<MenuItem value={'survey_extract'}>Survey Extract</MenuItem>,
Expand Down
4 changes: 2 additions & 2 deletions appv2/src/UI/Overlay/Records/Records.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const Records = (props) => {
dispatch({
type: USER_SETTINGS_ADD_RECORD_SET_REQUEST,
payload: {
recordSetType: isPOI ? 'POI' : 'Activity'
recordSetType: isPOI ? 'IAPP' : 'Activity'
}
});
};
Expand Down Expand Up @@ -185,7 +185,7 @@ export const Records = (props) => {
);
})}
<Button onClick={() => dispatch({type: USER_SETTINGS_ADD_RECORD_SET, payload: {recordSetType: 'Activity'}})} className={'addRecordSet'}>Add Layer of Records</Button>
<Button onClick={() => dispatch({type: USER_SETTINGS_ADD_RECORD_SET, payload: {recordSetType: 'POI'}})} className={'addRecordSet'}>Add IAPP Layer of Records</Button>
<Button onClick={() => dispatch({type: USER_SETTINGS_ADD_RECORD_SET, payload: {recordSetType: 'IAPP'}})} className={'addRecordSet'}>Add IAPP Layer of Records</Button>
</>
) : (
<></>
Expand Down
4 changes: 2 additions & 2 deletions appv2/src/state/reducers/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ function createMapReducer(configuration: AppConfig): (MapState, AnyAction) => Ma
draftState.layers[index].IDList = action.payload.IDList;
draftState.layers[index].loaded = true;

if (draftState.IAPPGeoJSON?.features?.length > 0) {
if (draftState.IAPPGeoJSONDict !== undefined) {
GeoJSONFilterSetForLayer(draftState, state, 'IAPP', action.payload.recordSetID, action.payload.IDList);
}
break;
Expand All @@ -365,7 +365,7 @@ function createMapReducer(configuration: AppConfig): (MapState, AnyAction) => Ma
drawOrder: 0
};
Object.keys(action.payload.updatedSet).map((key) => {
if (['color', 'mapToggle', 'drawOrder'].includes(key)) {
if (['color', 'mapToggle', 'drawOrder', 'labelToggle'].includes(key)) {
draftState.layers[layerIndex].layerState[key] = action.payload.updatedSet[key];
}
});
Expand Down

0 comments on commit f10bac3

Please sign in to comment.