@linzjs/landonline-openlayers-map
v6.2.1
Published
This library has been designed to wrap a domain agnostic OpenLayers map component to behave more like a React component. This gives the advantages of creating a separation of concerns between the host application and the map component. In addition, isolat
Downloads
2,408
Readme
Landonline OpenLayers map (Lolol)
This library has been designed to wrap a domain agnostic OpenLayers map component to behave more like a React component. This gives the advantages of creating a separation of concerns between the host application and the map component. In addition, isolating the map enables provides a component for more targeted automated testing.
Storybook
A number of stories have been created to demonstrate the capabilities and usage of this component. These can be found here
Component
A component LolOpenLayersMap was created, based on the map created as part of the survey application. This manages a native openlayers Map
object, which is associated with a <div>
in the DOM.
/**
* Properties for {@link LolOpenLayersMap}
*/
export interface LolOpenLayersMapProps {
/** children will be inserted into the DOM after the `map` div */
children?: ReactNode;
/** Defines the view with initial viewport coordinates, projection and scale */
view: LolOpenLayersViewDef;
/** Provide a setter to put the openlayers `Map` into state or global */
setMap?: (map: Map) => void;
/** Defines the Tile, VectorTile and Vector layers that make up the map */
layers: LolOpenLayersLayerDef[];
/** Group layers into a collection that are handled together in Openlayers,
* see https://openlayers.org/en/latest/apidoc/module-ol_layer_Group-LayerGroup.html
*/
layerGroup?: LolOpenLayersLayerGroupDef;
/** Indicated if the map component should manage the loading indicator */
useLoadingIndicator?: boolean;
/** Use the QueryClient of the parent - required if using queries*/
queryClient?: QueryClient;
/** Buffer the default zoom to bufferfactor, e.g. 1.1 leaves a 10% margin, default is 1.05 **/
bufferFactor?: number;
/** Interactions for draw **/
drawInteraction?: LolOpenLayersDrawInteraction;
/** Interactions for snap **/
snapInteraction?: LolOpenLayersSnapInteraction;
/** Interactions for modify **/
modifyInteraction?: LolOpenLayersModifyInteraction;
/** For testing, mock the map rather than using Openlayers **/
mock?: boolean;
/** Enable an openlayers Overlay which can have its element accessed (to set contents, etc)
* with mapContext.getOverlayRef
* https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html
*/
withOverlay?: boolean;
/** Show default zoom control or not */
withDefaultZoom?: boolean;
/** disable zoom on double click */
disableDoubleClickZoom?: boolean;
/** Map z index */
mapZIndex?: number;
/** enable auto placement */
enableAutoPlacement?: boolean;
/** Show only placed labels, hide unplaced */
showOnlyPlacedLabels?: boolean;
}
/**
* React wrapper for the openlayers https://openlayers.org/en/latest/apidoc/ library
* to render interactive maps
*
* @param props The React properties
*/
export const LolOpenLayersMap = (props: LolOpenLayersMapProps): JSX.Element
Layers within the map can be defined as LolOpenLayersLayerDef
which has subclasses:
LolOpenLayersTileLayerDef
: defines a tile layer, used for basemap, has LolOpenLayersXYZSourceDef to define a source against e.g. services.arcgisonline.comLolOpenLayersVectorTileLayerDef
: defines a vector tile layer, has LolOpenLayersMVTSourceDef to define a source for use with Geoserver.LolOpenLayersVectorLayerDef
: defines a vector layer. Source feature data can be loaded using LolOpenLayersFeatureSourceDef directly from an array of IFeatureSource, from a React query or loaded from state.
Context
A context LolOpenLayersMapContext
allows components at any level to interact with the state of the map.
export type LolOpenLayersMapContextType = {
/** The status (visibility, etc) of each layer */
layerStatus: (layerName: string) => ILayerStatus;
setLayerStatus: (layerName: string, layerStatus: ILayerStatus) => void;
/** The features dispalyed on a vector layer */
featureData: (layerName: string) => IFeatureSource[] | undefined;
setFeatureData: (layerName: string, features: IFeatureSource[]) => void;
/** Ids of features that are selected, can be changed using set or interactively in the map */
setFeatureSelect: (layerName: string, selectIds: number[]) => void;
featureSelect: (layerName: string) => number[];
/** Incrementing this causes the map to zoom to fit identified layers */
zoomToFit: number;
setZoomToFit: React.Dispatch<React.SetStateAction<number>>;
/** The resolution (e.g. scale) of the map */
mapResolution: number;
setMapResolution: (r: number) => void;
/** Used by LolOpenLayersMap to reflect when features have been changed */
featuresChanged: (layerName: string) => boolean;
clearFeaturesChanged: (layerName: string) => void;
clearFeatureSelectChanged: (layerName: string) => void;
featureSelectChanged: (layerName: string) => boolean;
};
Development
Using a local copy
If you want to work on this module in the context of your app (e.g https://github.com/linz/landonline-survey) some tweakage is needed: [ Don't commit these, the pipeline won't like it ]
- Checkout this repo, branch and edit as desired.
- In your app:
npm i --legacy-peer-deps -S <path>\landonline-openlayers-map
npm link --legacy-peer-deps -S <path>\landonline-openlayers-map\node_modules\react
(The last step ensures that React uses the version in lolmap and we don't get a hook error. And fixing react-dates might avoid this).
Alternatively, use npm pack
in this module to create a tgz file and import this into the application/module by a file://
path.
Logging
This library uses the loglevel package for logging.
To enable logging from a caller, use e.g:
logOpenlayersMap.setLevel(logOpenlayersMap.levels.DEBUG);
To add logs inside the library, import and use log
.
Releases
This library uses semantic-release to manage version numbers.
The commit message on master drives the release:
| Commit message | Release type |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -------------------------- |
| fix(landonline-openlayers-map): fix a bug with no API change
| ~~Patch~~ Fix Release |
| feat(landonline-openlayers-map): enhance with no breaking change
| ~~Minor~~ Feature Release |
| perf(landonline-openlayers-map): make a breaking change
BREAKING CHANGE: The graphiteWidth option has been removed.
The default graphite width of 10mm is always used for performance reasons.
| ~~Major~~ Breaking Release (Note that the BREAKING CHANGE:
token must be in the footer of the commit) |
"@babel/plugin-proposal-private-property-in-object"
This is required because we use eslint-config-react-app
which uses
babel-preset-react-app
which was causing warning
One of your dependencies, babel-preset-react-app, is importing the
"@babel/plugin-proposal-private-property-in-object" package without
declaring it in its dependencies. This is currently working because
"@babel/plugin-proposal-private-property-in-object" is already in your
node_modules folder for unrelated reasons, but it may break at any time.
is not maintianed anymore. It is thus unlikely that this bug will
ever be fixed. Add "@babel/plugin-proposal-private-property-in-object" to
your devDependencies to work around this error. This will make this message
go away.
If we remove eslint-config-react-app
can safely be removed @babel/plugin-proposal-private-property-in-object
Changes
5.2.0
This upgrades OpenLayers to 7.5.2
The following changes in the caller may be required:
Enumerated types have been replaced by allowable string types in Openlayers, so you may need to enum constants to strings and remove the type ref
Examples:
GeometryType
OverlayPositioning
IconAnchorUnits
The options to some constructors now need a cast:
DrawOptions
CanvasTextAlign
The
Map
component callsResizeObserver
which is not implemented in jest-dom.You should include the
resize-observer-polyfill
NPM module and add in setupTests.ts:global.ResizeObserver = require("resize-observer-polyfill");