JMap Server Lima
English
English
  • Welcome to JMap Server Lima
  • Administrator
    • JMap Server Administrator Manual
      • Introduction
        • Quick Start Guide
        • User Interface
          • Old User Interface
      • Resources: Databases
        • Creating Databases
        • Configuring Databases
          • Database Permissions
        • Managing Databases
        • JMap Server System Database
      • Resources: JMap Server to JMap Server Connections
        • Creating Connections to JMap Server
        • Configuring JMap Server to JMap Server Connections
          • Permissions for the Remote Connection
        • Managing Connections
      • Resources: Spatial Data
        • Basic Concepts
        • Creating Spatial Data Sources
        • Configuring Spatial Data Sources
          • Spatial Data Source Permissions
          • External Attributes
          • Metadata
          • Sharing Spatial Data Sources
        • Managing Spatial Data Sources
        • Vector Data Sources
          • JMap ADF - E00 Arc - Info reader
          • JMap CSV reader
          • JMap DGN V7 - V8 File reader
          • JMap DWG - DXF reader
          • JMap EDIGEO reader
          • JMap File geodatabase reader
          • JMap GeoJSON reader
          • JMap GML reader
          • JMap GPX reader
          • JMap IFC reader
          • JMap KML reader
          • JMap MID - MIF reader
          • JMap Photo reader
          • JMap SHP reader
          • JMap TAB reader
          • Annotations in a database
          • ArcGIS REST
          • ArcSDE geodatabase
          • Coordinates in a database
          • Enterprise geodatabase
          • JMap Server
          • JMap Spatial Table
          • MongoDB
          • MySQL Spatial
          • OGC API Features
          • Oracle Spatial Locator
          • Personal geodatabase
          • PostGIS
          • SQL Server Spatial
          • WFS Server
          • WKB or WKT in a database
        • Raster Data Sources
          • ECW - JPG2000
          • GDAL - Geospatial Data Abstraction Library
          • ArcGIS REST
          • JMap Server
          • OpenStreetMap
          • WMS server
          • WMTS Server
      • Resources: Metadata templates
      • Resources: Projects
        • Creating Projects
          • Multilingual Projects
          • Vector tiles in JMap
        • Configuring Projects
          • Project Permissions
          • Managing Layers
            • Organizing Layers
          • Attribute Queries
            • Attribute Query Forms
          • Image Producer
          • JMap Extensions Compatible with JMap NG or JMap Survey
        • Sharing the Project
        • Managing Projects
      • Resources: Style Templates
        • Creating Style Templates
        • Managing Style Templates
      • Resources: Personal Layers
      • Resources: Layers
        • Creating Layers
        • Configuring Layers
          • Layer Permissions
          • General Settings
          • Dynamic Filters
          • Style
          • Thematics
          • Labels
          • Mouseover
          • Information Reports
          • Forms
            • Configuring Forms
            • Creating Forms
              • Layer Attributes Forms
              • Database Forms
          • JMap Extensions
        • Sharing Layers
      • JMap Server Applications
        • Deployment: Classical JMap applications
          • JMap Pro Applications
          • JMap Web Applications
            • Using a GeoWebCache Server
          • WFS and WMS Services
          • Managing Deployed Applications
          • Downloading Services
        • New generation JMap applications
      • Tools
        • SQL Console
        • Import / Export
          • User Data
        • Scheduler
        • Messaging
        • Debugging tools
      • JMap Server Extensions
        • Installed Extensions
        • Marketplace
      • JMap Server
        • JMap Server Status
        • Sessions
        • Security
          • Users and Groups
            • User Managers
              • JMap DB user manager
              • Composite user manager
              • Active Directory user manager
              • JMap LDAP user manager
              • OpenID Connect (OIDC) user manager
              • SAML2 user manager
            • Single Sign-On for JMap Pro
          • Managing Permissions
          • Using HTTPS with JMap
        • Log Files
        • Usage Statistics
        • JMap Server Settings
    • Technical Specifications
    • Installation Guide
    • Installing and Starting JMap Server (with installer)
    • Installing and Starting JMap Server (in a Docker container)
    • Migration Guide to JMap Server Lima
  • Applications
    • JMap Server Applications
    • JMap Pro User Guide
      • Introduction
        • User Interface
        • Navigating on the Map
        • Map Management
        • Map Settings
      • Map Layers
        • Layer Management
        • Elements Explorer
        • Thematic Maps
        • Layer Metadata
        • Layer Settings
          • General
          • Style
          • Thematics
          • Labeling
          • Mouseover
          • Filters
          • Advanced
        • Editable Layers
          • Editing Data
          • Personal Layers
      • Tools
        • Labeling
        • Interactive Selection
        • Information
          • Information Report
          • Geometry Information
          • Mouseover
        • Snap
        • Measurement
        • Search Tools
          • Attribute Queries
          • Spatial Queries
        • Collaboration Tools
          • Map Contexts
          • Sharing Maps
          • Printing Maps
      • Application Settings
      • Keyboard and Mouse Shortcuts
    • JMap NG User Guide
      • Introduction
        • Connecting to JMap NG
        • User Interface
        • Navigating on the Map
        • Profile and User Settings
      • The Data
        • The Layers Panel
        • Data Layers
          • Displaying Layers
          • Thematics
          • Layer Information
          • Geographic Extent of the Layer
          • Filter Elements on the Map
          • Making Layer Elements Selectable
      • I Wish to...
        • Display Element Information
          • Tooltips
          • Information Reports
        • Perform Searches
        • Select Elements on the Map
        • Measure Distances and Surfaces
        • Add Annotations to the Map
        • Edit Data
        • Create and Manage Customized Maps
        • Export / Print a Map
    • JMap Survey User Guide
      • Introduction
        • Working With an iOS Device
        • Working With an Android Device
        • Logging In
        • User Interface
      • The Data
      • I Wish to...
        • Access Information Associated With an Object
        • Perform Searches
        • Create Objects
        • Modify Objects
        • Work in Offline Mode
        • Synchronize Data with JMap Server
        • Log Out
    • JMap Web
      • JMap Web User Guide
  • Extensions
    • Edition
      • User Interface
      • Basic Concepts
      • I Wish to...
        • Edit Layers Geometries
          • Edition Tools
          • Selecting Elements
          • Node and Polygon Operations
          • Vertical Position and Element Duplication
          • WKT Geometries
        • Perform Spatial Operations
          • Geoprocessing
          • Spatial Tools
    • Export
    • Import
      • Importation Procedure
        • Importing MIF Files
        • Importing SHP Files
        • Importing CSV Files
        • Importing NMEA Data
        • Importing Data From WMS
    • Documents
      • Configuring JMap Documents
        • Selecting Data Sources to Associate Documents with
        • Configuring Document Depots
        • Managing repositories
        • Making Documents available in apps
      • Documents for JMap Pro
        • Graphical Interface
        • Associating Documents with Map Elements
        • Searching for Documents
        • Displaying the List of Documents Associated with Elements
      • Documents for JMap NG
        • Graphical Interface
        • Searching for Documents
        • Showing Selected Documents
      • Documents for JMap Survey
    • Tracking
      • Administrator
      • User
    • JMap NG Configuration
      • Configuration
  • Developer
    • JMap Server REST API
    • JMap Admin REST API
    • JMap Pro / Server API
    • JMap Web API
    • JMap Server SDK
    • JMap NG Developer Manual
      • Startup Options
      • Extensions
      • Examples
        • Start the JMap NG Core library
        • Start the JMap NG App
        • Add a JMap NG App extension
        • Toggle a JMap layer visibility
        • Add a layer to display custom data from GeoJSON file
        • Locate and select features by attribute query
        • Add an event on move end
        • Add attributions on the map
        • Locate and select feature by id
        • Locate and select feature(s) by location
        • Custom mouseover on a layer
        • Create a custom form in a div
      • Changelog
  • Knowledge Base
    • Knowledge Base
Propulsé par GitBook

K2 Geospatial 2024

Sur cette page
  • A simple example
  • A more complete example
Exporter en PDF
  1. Developer
  2. JMap NG Developer Manual
  3. Examples

Add a JMap NG App extension

PrécédentStart the JMap NG AppSuivantToggle a JMap layer visibility

Dernière mise à jour il y a 1 an

JMap NG extensions are plug-in modules taht can exetend the functionalities present in JMap NG App. You can develop and add your own extensions.

For more information about JMap NG extensions, refer to this .

The JMap NG App extension API documentation is available .

A simple example

The example bellow shows a simple extension that creates a panel and displays some text on it.

Try it out in

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <meta charset="UTF-8">
    <style>
      html,
      body {
        padding: 0px;
        margin: 0px;
        height: 100%;
        width: 100%;
      }
    </style>
  </head>
  <body>
  	<script type="text/javascript">
      const extensionId = "my-extension"
      window.JMAP_OPTIONS = {
        restBaseUrl: "https://jmapdoc.jmaponline.net/services/rest/v2.0",
        anonymous: true,
        projectId: 1,
        map: {
          center: {
            x: -74.17355888315548,
            y: 45.504030591808856
          },
          zoom: 8.04872607654608
        },
        hideMainLayout: true,
        application: {
          panel: `${extensionId}-panel`,
          extensions: [{
            id: extensionId,
            panelIcon: "fa-unlock-alt", // this is a font-awesome icon, but you can pass an image url
            panelTitle: "My custom extension",
            panelTooltip: "My custom extension",
            onPanelCreation: containerId => {
              const container = document.getElementById(containerId)
              const span = document.createElement("span")
              span.id = "my-text"
              span.innerHTML = "This is a custom panel"
              container.append(span)
            },
            onPanelDestroy: (containerId) => {
              document.getElementById(containerId)
              const text = document.getElementById("my-text")
              if (text) {
                text.remove()
              }
            }
          }]
        }
      }
    </script>
    <script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/jmap-app-js@7_Kathmandu_HF3"></script>
  </body>
</html>

There is another way to load your extension, after the JMap NG App has been loaded.

You can register the previous extension like this:

JMap.Application.Extension.register({
  id: "my-extension",
  panelIcon: "fas fa-wrench",
  panelTitle: "My custom extension",
  panelTooltip: "My custom extension",
  onPanelCreation: containerId => {
    const container = document.getElementById(containerId)
    const span = document.createElement("span")
    span.id = "my-text"
    span.innerHTML = "This is a custom panel"
    container.append(span)
  },
  onPanelDestroy: (containerId) => {
    document.getElementById(containerId)
    const text = document.getElementById("my-text")
    if (text) {
      text.remove()
    }
  }
})

A more complete example

The example bellow shows you a more sophisticated extension named "Favourite locations".

It adds points on the map where you click, and displays a list of your "favourite" locations. You can also toggle the visibility of the point layer.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <meta charset="UTF-8" />
    <style>
      html,
      body {
        padding: 0px;
        margin: 0px;
        height: 100%;
        width: 100%;
      }
    </style>
  </head>

  <body>
    <script type="text/javascript">
      function getFavouriteExtension(extensionId) {
        const LAYER_ID = "favourite-custom-layer"
        const CLICK_LISTENER_ID = "favourite-click-listener"
        const ACTION_ADD = "FAVOURITE_ADD_LOCATION"
        const ACTION_DEL = "FAVOURITE_DEL_LOCATION"
        const ACTION_SET_VISIBILITY = "FAVOURITE_SET_LAYER_VISIBILITY"
        let panelContainerId
        let visibilityContainerId
        let locationsContainerId
        let reduxUnsubscribe
        let map
        let previousLocationCount = 0
        let previousLayerVisibility = true
        // return the JMap application current redux state
        function getAppState() {
          return JMap.getDataStore().getState().external["jmap_app"]
        }
        // return the favourite extension current redux state
        function getFavouriteState() {
          return JMap.getDataStore().getState().external[extensionId]
        }
        // return the primary color in use by JMap Application
        function getPrimaryColor() {
          return getAppState().ui.theme.palette.text.primary
        }
        // return the secondary color in use by JMap Application
        function getSecondaryColor() {
          return getAppState().ui.theme.palette.text.secondary
        }
        /**
         * This is the favourite service.
         * It is where we change the redux store values,
         * then the reduxChangeHandler function will react to state changes.
         **/
        const favouriteSVC = {
          // returns all existing locations
          getLocations: () => getFavouriteState().locations.slice(),
          // return true if the layer is displayed on the map
          getLayerVisibility: () => getFavouriteState().isLayerVisible,
          // add a location in the redux store
          add: location =>
            JMap.getDataStore().dispatch({
              type: ACTION_ADD,
              location: location
            }),
          // remove a location in the redux store at the index
          del: index =>
            JMap.getDataStore().dispatch({
              type: ACTION_DEL,
              index: index
            }),
          // if false, hide the layer on the map, else show it
          setLayerVisibility: visibility =>
            JMap.getDataStore().dispatch({
              type: ACTION_SET_VISIBILITY,
              visibility: visibility
            })
        }
        /**
         * This is the redux reducer, a pure javascript function.
         * It reacts to the actions you dispatch, and changes the data in the store.
         **/
        function reduxReducer(currentFavouriteState, action) {
          if (!currentFavouriteState) {
            currentFavouriteState = {
              locations: [],
              isLayerVisible: previousLayerVisibility
            }
          }
          switch (action.type) {
            case ACTION_ADD: {
              const newFavouriteState = { ...currentFavouriteState, locations: currentFavouriteState.locations.slice() }
              newFavouriteState.locations.push(action.location)
              return newFavouriteState
            }
            case ACTION_DEL: {
              const newFavouriteState = { ...currentFavouriteState, locations: currentFavouriteState.locations.slice() }
              newFavouriteState.locations.splice(action.index, 1)
              return newFavouriteState
            }
            case ACTION_SET_VISIBILITY: {
              return { ...currentFavouriteState, isLayerVisible: action.visibility }
            }
          }
          return currentFavouriteState
        }
        // Create the dom elements to display the layer visibility checkbox
        function displayLayerVisibility() {
          if (!visibilityContainerId) {
            visibilityContainerId = `${panelContainerId}-visibility`
          }
          const panelContainer = document.getElementById(panelContainerId)
          panelContainer.style.color = getPrimaryColor()
          panelContainer.style.padding = "1rem"
          const container = document.createElement("div")
          container.id = visibilityContainerId
          const span = document.createElement("span")
          span.innerHTML = "Display locations on map"
          container.append(span)
          const input = document.createElement("input")
          input.type = "checkbox"
          input.style.cursor = "pointer"
          input.style.marginLeft = "1rem"
          input.checked = favouriteSVC.getLayerVisibility()
          input.onclick = () => favouriteSVC.setLayerVisibility(!favouriteSVC.getLayerVisibility())
          container.append(input)
          panelContainer.append(container)
        }
        // Create the dom elements to display the locations list
        function displayLocations() {
          if (!locationsContainerId) {
            locationsContainerId = `${panelContainerId}-locations`
          }
          const panelContainer = document.getElementById(panelContainerId)
          const container = document.createElement("div")
          container.id = locationsContainerId
          container.style.marginTop = "1rem"
          container.style.display = "flex"
          container.style.flexDirection = "column"
          const locations = favouriteSVC.getLocations()
          if (locations.length === 0) {
            const span = document.createElement("span")
            span.innerHTML = "Click on the map to add your favourite locations"
            span.style.color = getSecondaryColor()
            container.append(span)
          } else {
            for (var i = 0; i < locations.length; i++) {
              const location = locations[i]
              const index = i
              const locationContainer = document.createElement("div")
              locationContainer.style.marginTop = "1rem"
              locationContainer.style.display = "flex"
              locationContainer.style.alignItems = "center"
              locationContainer.style.justifyContent = "space-between"
              const locationSpan = document.createElement("span")
              locationSpan.innerHTML = `LNG = ${location.x.toFixed(5)} | LAT = ${location.y.toFixed(5)}`
              locationContainer.append(locationSpan)
              const button = document.createElement("button")
              button.innerHTML = "X"
              button.title = "Click to remove the location"
              button.style.cursor = "pointer"
              button.onclick = () => favouriteSVC.del(index)
              locationContainer.append(button)
              container.append(locationContainer)
            }
          }
          panelContainer.append(container)
        }
        // Remove in the dom the container, given the container id
        function removeContainer(containerId) {
          const container = document.getElementById(containerId)
          if (container) {
            container.remove()
          }
        }
        function refreshLocations() {
          removeContainer(locationsContainerId)
          displayLocations()
        }
        // Locations have changed in the store, we add or remove it in the mapbox source.
        function refreshLayer() {
          map.getSource(LAYER_ID).setData({
            type: "FeatureCollection",
            features: getFavouriteState().locations.map(l => ({
              type: "Feature",
              geometry: { type: "Point", coordinates: [l.x, l.y] }
            }))
          })
        }
        /**
         * The redux function that is called when the redux state changed.
         * If a favourite value has changed it refreshes the ui or the map.
         **/
        function reduxChangeHandler() {
          const state = getFavouriteState()
          if (previousLocationCount !== state.locations.length) {
            previousLocationCount = state.locations.length
            refreshLocations()
            refreshLayer()
          }
          if (previousLayerVisibility !== state.isLayerVisible) {
            previousLayerVisibility = state.isLayerVisible
            map.setLayoutProperty(LAYER_ID, "visibility", state.isLayerVisible ? "visible": "none")
          }
        }
        /**
         * The map interactor, more details on:
         * https://k2geospatial.github.io/jmap-app/latest/modules/jmap.map.interaction.html
         **/
        const mapInteractor = {
          init: mapboxMap => {
            map = mapboxMap
            map.addSource(LAYER_ID, {
              type: "geojson",
              data: { type: "FeatureCollection", features: [] }
            })
            map.addLayer({
              id: LAYER_ID,
              type: "circle",
              source: LAYER_ID,
              paint: {
                "circle-radius": 10,
                "circle-color": "#0066ff"
              }
            })
            JMap.Event.Map.on.click(CLICK_LISTENER_ID, params => {
              favouriteSVC.add(params.location)
            })
            JMap.Event.Map.deactivate(CLICK_LISTENER_ID)
          },
          activate: () => {
            JMap.Map.getMap().doubleClickZoom.disable()
            JMap.Event.Map.activate(CLICK_LISTENER_ID)
          },
          deactivate: () => {
            JMap.Map.getMap().doubleClickZoom.enable()
            JMap.Event.Map.deactivate(CLICK_LISTENER_ID)
          },
          terminate: () => {
            JMap.Event.Map.remove(CLICK_LISTENER_ID)
            map.removeLayer(LAYER_ID)
            map.removeSource(LAYER_ID)
          }
        }
        // Returns the extension object that will be registered by the JMap Application
        return {
          id: extensionId,
          panelIcon: "fa-thumbtack",
          panelTitle: "My favourite locations",
          panelTooltip: "My favourite locations",
          onPanelCreation: containerId => {
            if (!panelContainerId) {
              panelContainerId = containerId
            }
            displayLayerVisibility()
            displayLocations()
            reduxUnsubscribe = JMap.getDataStore().subscribe(reduxChangeHandler)
          },
          onPanelDestroy: () => {
            removeContainer(visibilityContainerId)
            removeContainer(locationsContainerId)
            reduxUnsubscribe()
          },
          interactor: mapInteractor,
          serviceToExpose: favouriteSVC,
          storeReducer: reduxReducer
        }
      }
      const extensionId = "favourite"
      window.JMAP_OPTIONS = {
        restBaseUrl: "https://jmapdoc.jmaponline.net/services/rest/v2.0",
        anonymous: true,
        projectId: 1,
        map: {
          center: {
            x: -73.92251114687645,
            y: 45.52559621002098
          },
          zoom: 9.07038517536697
        },
        hideMainLayout: true,
        application: {
          panel: `${extensionId}-panel`, // will display the favourite panel when application starts
          extensions: [getFavouriteExtension(extensionId)] // will register the favourite extension
        }
      }
    </script>
    <script defer type="text/javascript" src="https://cdn.jsdelivr.net/npm/jmap-app-js@7_Kathmandu_HF3"></script>
  </body>
</html>

Try it out in

section
here
Codepen.io
Codepen.io
A more comple example