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

clean up and add documentation #9

Open
wants to merge 2 commits into
base: support_refactoring
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/tests.webpack.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
var context = require.context('../web', true, /(MapSearch-test\.jsx?)|(MapSearch-test-chrome\.jsx?)$/);
var context = require.context('../web', true, /(-test\.jsx?)|(-test-chrome\.jsx?)$/);
context.keys().forEach(context);
module.exports = context;
47 changes: 47 additions & 0 deletions docs/developer-guide/writing-map-tool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# How to write a map tool

> ┻┳|
> ┳┻| _
> ┻┳| •.•) 💬 *"Hey, Checkout this awesome documentation on how to write a map tool!"*
> ┳┻|⊂ノ
> ┻┳|

## Premises
We wish to:
- being able to define map tools/support as plugins, with a Map container
- allow a single ReactJS component and different (dynamically loaded) implementations for the different mapping libraries

In [this](https://github.com/geosolutions-it/MapStore2/pull/6006) pr we made a refactor on the locate plugin that can be used to create your own map tool or map support or migrate an existing one

## Steps
- You can start by adding a new map container inside the map tool you are [refactoring](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-ad8a2ac6a2d1aadb86756a00b02afc44d23d26d813dea4a43489d3bdf8766fb8R56-R66)

`
Map: {
name: "Locate",
Tool: connect((state) => ({
status: state.locate && state.locate.state,
messages: state.locale && state.locale.messages ? state.locale.messages.locate : undefined
}), {
changeLocateState,
onLocateError
})(LocateTool),
priority: 1
}
`

- [remove](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-7fe64fb8a440f8d88eea28d07442b02d81011cef71ea8a2c5b2d6a69a69245d8L216-R216) that tool if present, from the default map tool, it will be included as plugin directly as a child of the map
- [clean](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-064ff22000f3ba1d62c147f1cb4a30fbdf22409ced300195f0c47eac7c5481a7L15-R110) up also the index that gathers supports or tools
- continue the clean up [here](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-cdbb5c16fa137021718a4d8d9242f0f1605f3ad4d805467c4f14823b02bde844L13) and [here](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-90e9c33847a4f39451c18e28b60cea034a456a7e1c668f34613621d7423b22daL17)
- adjust plugins [import](https://github.com/geosolutions-it/MapStore2/pull/6006/files#diff-12914c878def7e2331e05bdcdc559471b70f8ca6dee5ca776efcb0558bc9035cL70-R70) if needed

Now you are ready to create map tools or supports for the mapTypes you need.

Create a new component that will act as interface that will use the various implementations and place it in `web/client/components/mapcontrols/<toolName>/<ToolName>Tool.jsx`

place a new <toolName>.js in web/client/map/<mayType> if you are working on the product, or simply your js/map folder if it is a project

This file will contain the implementation of that library.

Now you are good to go!

1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -122,6 +122,7 @@ pages:
- Writing Plugins: 'developer-guide/plugins-howto.md'
- Writing Epics: 'developer-guide/writing-epics.md'
- Writing Actions and Reducers: 'developer-guide/writing-actions-reducers.md'
- Write a Map Tool: 'developer-guide/writing-map-tool.md'
- Configuration:
- Configuration Files: 'developer-guide/configuration-files.md'
- Application Configuration: 'developer-guide/local-config.md'
33 changes: 27 additions & 6 deletions web/client/components/mapcontrols/locate/LocateTool.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import {useEffect, useRef} from 'react';
import useMapTool from "../../../map/hooks/use-map-tool";

@@ -14,15 +22,19 @@ const defaultOpt = {
maxZoom: 18
}
};

/**
* Locate Tool Component shared across multiple map types
* @prop {object} map the map object
* @prop {string} mapType the map type
* @prop {string} status locate status: DISABLED, FOLLOWING, ENABLED, LOCATING, PERMISSION_DENIED
* @prop {string} messages message to be shown when location is found
* @prop {function} changeLocateState callback to run when status changes
* @prop {function} onLocateError callback to run when an error occurs
*/
const LocateTool = ({map, mapType, status, messages, changeLocateState, onLocateError}) => {
const locateInstance = useRef();
const [loaded, Impl, error] = useMapTool(mapType, 'locate');
useEffect(() => {
if (error) {
onLocateError(error);
}
}, [error]);

const onStateChange = (state) => {
if (status !== state) {
changeLocateState(state);
@@ -36,6 +48,8 @@ const LocateTool = ({map, mapType, status, messages, changeLocateState, onLocate

useEffect(() => {
if (loaded) {
// the Locate tool is a class and we can create an instance of it
// other possibilities are to use a react component
locateInstance.current = new Impl();
locateInstance.current.start({
map, options: defaultOpt, messages, status, onStateChange, onLocationError
@@ -45,10 +59,17 @@ const LocateTool = ({map, mapType, status, messages, changeLocateState, onLocate
locateInstance.current?.clear();
};
}, [loaded]);

useEffect(() => {
locateInstance.current?.update({status, messages});
}, [status, messages, loaded]);

useEffect(() => {
if (error) {
onLocateError(error);
}
}, [error]);

return null;
};

8 changes: 7 additions & 1 deletion web/client/map/hooks/use-map-tool.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,13 @@

import {useEffect, useRef, useState} from "react";

const useMapTool = (mapType, tool) => {
/**
* Hook that can be used to load a tool in an asynchronous way
* @param {string} mapType the map type
* @param {string} tool the name of the tool, should match a file in web/client/map/<mapType> folder
* @return {[boolean, object, object]} [loaded, tool_implementation, error]: loaded is false until the tool has been correctly loaded, tool_implementation is a ReactJS reference to the tool, error is an object containing an error if the tool implementation cannot be loaded
*/
const useMapTool = (mapType = "openlayers", tool = "") => {
const [loaded, setLoaded] = useState(false);
const [error, setError] = useState(null);
const impl = useRef();
6 changes: 2 additions & 4 deletions web/client/plugins/Locate.jsx
Original file line number Diff line number Diff line change
@@ -33,14 +33,12 @@ import LocateTool from "../components/mapcontrols/locate/LocateTool";
*/

const LocatePlugin = connect((state) => ({
locate: state.locate && state.locate.state || 'DISABLED',
tooltip: state.locate && state.locate.state === 'FOLLOWING' ? "locate.tooltipDeactivate" : "locate.tooltip"
locate: state?.locate?.state || 'DISABLED',
tooltip: state?.locate?.state === 'FOLLOWING' ? "locate.tooltipDeactivate" : "locate.tooltip"
}), {
onClick: changeLocateState
})(LocateBtn);

require('./locate/locate.css');


export default createPlugin('Locate', {
component: LocatePlugin,
File renamed without changes.
1 change: 1 addition & 0 deletions web/client/themes/default/ms2-theme.less
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
@import "./less/leaflet.less";
@import "./less/loaders.less";
@import "./less/loading-mask.less";
@import "./less/locate.less";
@import "./less/manager.less";
@import "./less/map-footer.less";
@import "./less/map-search-bar.less";