Custom Drawing

Custom Drawing

Info

Custom Drawing API is available on v8.1.0 and later

Pointr Web SDK is customizable and allows you to draw your data or any element to on top of its UI. We have 3 different APIs you can use: Marker, Popup and Layer. In this document we’ll walkthrough of their use cases and their differences.

Markers are HTML elements that you can use to mark map. It is highly customizable and interactive.

Default marker is added

Layers are belong to map and allows you to add a new layer for your data. There are different kind of layers and cluster support for some of them.

Cat icons are added using symbol layer

Yellows circles are added using CircleLayer

These are just a few use cases for layers. Marker API is great when you need a few points and requirement for complex interaction cases. But Layer API is great for displaying large datasets and clusters.

We use both two API for the UI of Pointr WEB SDK. For example if you long click to somewhere we use Marker API to mark that custom point. And the all level data you see on the map is a layer that gets update on each level update.

Marker API

Markers are user interface elements that can be added to the map. Markers are exist outside of the map’s canvas element. They’re customizable interactive HTML elements.

While using Marker API you need to use Feature object to specify location of markers.

Please see API References for detailed information but essentially Feature gets 2 parameters: first one is for properties and the second one is for geometry.

For the geometry part “type”: “Point” must be set for marker api and coordinates should contain an array [longitude, latitude]. coordinates[0] must be longitude and coordinates[1] must be latitude.

Default Marker - Level based

To use marker firstly you need to create a point typed Feature object.

sid is siteInternalIdentifier, bid is building internalIdentifier and lvl is level index where marker belongs to. If you pass those parameters marker will only appear at that building’s level is selected

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    { sid: 1, bid: 1, lvl: 1 },
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  mapViewController.addMarker(myMarkerFeature);
});

Default Marker - Always Visible

When you don’t provide sid, bid and lvl information marker will be always visible in given coordinate

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    {},
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  const myMarker = mapViewController.addMarker(myMarkerFeature);
});

Remove Marker

mapViewController.removeMarker(myMarker);

Default Marker - Zoom Options

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    {},
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  const myMarker = mapViewController.addMarker(myMarkerFeature, undefined, {
    minzoom: 3,
    maxzoom: 18,
  });
});

Custom Marker - Image

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    {},
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  const customElement = document.createElement("div");
  customElement.className = "marker";
  customElement.style.backgroundImage = "url(https://pointrapps.blob.core.windows.net/core-web-sdk/sdk-v8/icons/64x64-pamuk.jpg)";
  customElement.style.width = "64px";
  customElement.style.height = "64px";
  const myMarker = mapViewController.addMarker(myMarkerFeature, customElement);
});

Custom marker - clicked

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    {},
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  const customElement = document.createElement("div");
  customElement.className = "marker";
  customElement.style.backgroundImage = "url(https://pointrapps.blob.core.windows.net/core-web-sdk/sdk-v8/icons/64x64-pamuk.jpg)";
  customElement.style.width = "64px";
  customElement.style.height = "64px";
  // ADD click event to your element
  customElement.addEventListener("click", function () {
    window.alert("Marker clicked");
  });
  const myMarker = mapViewController.addMarker(myMarkerFeature, customElement);
});

Custom Marker - Button

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const myMarkerFeature = new PointrWebSDK.Feature(
    {},
    { type: "Point", coordinates: [-71.01881422, 42.36932431] }
  );
  const myBtn = document.createElement("button");
  myBtn.textContent = "Special Offers";
  myBtn.onclick = () => {
    window.open("https://pointr.tech", "_blank");
  };
  mapViewController.addMarker(myMarkerFeature, myBtn);
});

Available options:

anchor: string. default: ‘center’ . A string indicating the part of the Marker that should be positioned closest to the coordinate . Options are ‘center’ , ‘top’ , ‘bottom’ , ‘left’ , ‘right’ , ‘top-left’ , ‘top-right’ , ‘bottom-left’ , and ‘bottom-right’ .

offset: The offset in pixels as a PointLike object to apply relative to the element’s center. Negatives indicate left and up.

draggable: boolean. default: falseA boolean indicating whether or not a marker is able to be dragged to a new position on the map.

clickTolerance: number. default: 0. The max number of pixels a user can shift the mouse pointer during a click on the marker for it to be considered a valid click.

rotation: number. default: 0. The rotation angle of the marker in degrees, relative to its respective rotationAlignment setting. A positive value will rotate the marker clockwise.

pitchAlignment: string.default: ‘auto’. ‘map’ aligns the Marker to the plane of the map. ‘viewport’ aligns the Marker to the plane of the viewport. ‘auto’ automatically matches the value of rotationAlignment .

rotationAlignment: string. default: ‘auto’. ‘map’ aligns the Marker ‘s rotation relative to the map, maintaining a bearing as the map rotates. ‘viewport’ aligns the Marker ‘s rotation relative to the viewport, agnostic to map rotations. ‘auto’ is equivalent to viewport .

Popup API

Popups are interactive elements that can be added to markers on the map. They display customizable HTML content and provide additional information or actions related to a specific location.

When using the Popup API, the primary function is to add popups to the map or associate them with existing markers.

Add Popup

To add a popup on the map, you need to create a Point typed Feature object and -optionally- provide the HTML content for the popup. The feature’s geometry must be of type “Point,” and the popup will be associated with the specified location.

const myFeature = new PointrWebSDK.Feature(
  { sid: 1, bid: 1, lvl: 1 },
  { type: "Point", coordinates: [-71.01881422, 42.36932431] }
);
const myPopup = mapViewController.addPopup(myFeature, "Popup Content");

Add Popup with HTML Element Content

To associate an HTML element with an existing marker, use the addPopupToMarker method. Provide the marker object and the HTML element as the content for the popup.

const myPopup = mapViewController.addPopup(myFeature, '<h2>This is a custom popup content!</h2>');

Remove Popup

To remove a popup from the map, use the removePopup method, passing the popup object you wish to remove.

mapViewController.removePopup(myPopup);

Add Popup to Marker

To associate a popup with an existing marker, use the addPopupToMarker method. Provide the marker object and the popup object you want to associate.

const myMarker = mapViewController.addMarker(myFeature);
const myPopup = mapViewController.addPopupToMarker(myMarker, "Popup Content");

Note: Make sure that the marker is already added to the map before associating a popup with it.

Available Options

anchor: string. default: ‘center’. Specifies the part of the popup that should be positioned closest to the coordinate.

className: string. Space-separated CSS class names to add to the popup container.

closeButton: boolean. default: true. If true, a close button will appear in the top right corner of the popup.

closeOnClick: boolean. default: true. If true, the popup will close when the map is clicked.

closeOnMove: boolean. default: false. If true, the popup will close when the map moves.

focusAfterOpen: boolean. default: true. If true, the popup will try to focus the first focusable element inside the popup.

maxWidth: string. default: ‘240px’. A string that sets the CSS property of the popup’s maximum width.

offset: (number | PointLike | Object). A pixel offset applied to the popup’s location.

Negative offsets indicate left and up. The offset can be specified as a single number, a PointLike object, or an object of Points specifying an offset for each anchor position.

Layer API

To access and use layer api you need to create a layer then call mapViewController’s addLayer function. Lastly, you need to set your data to that layer.

Example use case:

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const layer = new PointrWebSDK.CircleLayer({
    "circle-color": "yellow",
  });
  mapViewController.addLayer(layer);
  mapViewController.updateFeatures(layer, pointFeatures);
});

As you can see in the example first step is to create CircleLayer.

Then we’re calling mapViewController’s addLayer function with the layer we created

Last step is to set feature data to layer.

To be able to create a feature array you can use the sample below

pointFeatures = [];
const feature = new PointrWebSDK.Feature(propertiesObject, {
  type: "Point",
  coordinates: [longitude, latitude],
});
pointFeatures.push(feature);

Add Cluster

In order to visualize points as clusters, you must give a clusterOptions object to the addLayer method. When clusterOptions object is provided, the addLayer method returns an array that consists of 3 Layer Objects: The layer you want to add, a Circle Layer to indicate cluster, a SymbolLayer that displays point_count on each cluster. Therefore, if you want to remove, hide or show a clustered layer, you need to call related functions for each of those layers.

Via clusterOptions object, you can set cluster circle radius, cluster circle color, font size and font families. Default values of those are:

// Font and textSize is used for the text that indicates number of points in a
// cluster
const clusterOptions = {
  clusterFonts: ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
  textSize: 12, // px
  // This example is made with 3 steps ( 3 types of circles, this can be changed)
  // Blue, 20 px circles when point count is less than 100,
  // Yellow, 30 px circles when point count is between 100 and 750,
  // Pink, 40 px circles when point count is more than 750,
  circleColor: [
    "step",
    ["get", "point_count"],
    "#51bbd6",
    100,
    "#f1f075",
    750,
    "#f28cb1",
  ],
  circleRadius: ["step", ["get", "point_count"], 20, 100, 30, 750, 40],
};

If you want to use those default options given above, you can give an empty object {} as cluster options to the addLayer method.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  mapViewController.addLayer(layer, {});
  
});

Clustered Layer with default colors

E.g. overwriting colors:

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  mapViewController.addLayer(layer, {
    circleColor: [
      "step",
      ["get", "point_count"],
      "#51bbd6",
      100,
      "#3fa31a",
      250,
      "#d48231",
      500,
      "#f1f075",
      750,
      "#f28cb1",
    ],
  });
  
});

Result:

Clustered Layer with overwritten colors

Remove Layer

It is possible to remove an added layer from the map. You can use the removeLayer method of mapViewController. removeLayer method takes the layer to remove as argument.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  const exampleLayer = new PointrWebSDK.CircleLayer({
    "circle-color": "green",
    "circle-radius": 5,
  });
  
  mapViewController.removeLayer(exampleLayer);
});

Change Visibility

Instead of removing and adding layers again, you can simply change layer visibility with hideLayer and showLayer methods of mapViewController.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  mapViewController.hideLayer(exampleLayer);
  
  mapViewController.showLayer(exampleLayer);
  
}

Level Based Layers

If a level is specified in the features given to the added layer, the layer would be visible only on that level, otherwise it would be visible on all levels.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  const pointFeatures = features.map((feature) => {
    return new PointrWebSDK.Feature(
      {
        lvl: feature.properties.lvl,
        bid: feature.properties.bid,
        sid: feature.properties.sid
      },
      {
        type: feature.geometry.type,
        coordinates: feature.geometry.coordinates
      }
    )
  });
  
  mapViewController.updateFeatures(layer, pointFeatures);
  
})

Read Data from onClick event

You can subscribe to mapView’s click event to handle the click on layers. MapView emits features that correspond to the clicked point. With the following code piece, you can subscribe to click event and then show an alert message when your newly added layer is clicked.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapClicked, function (features) {
  features.forEach((feature) => {
    if (element.layer.id === exampleLayer.id) {
      alert("CLICKED ON " + JSON.stringify(element.properties));
    }
  });
});

Result:

Layer Priority

addLayer method of mapViewController has a third optional argument: aboveLayerId which is the ID of an existing layer to insert the new layer before. So that the newly added layer appears visually beneath the existing layer whose ID is given. If this argument is not specified, the layer will be appended to the end of the layers array and appear visually above all other layers.

Consider the following example:

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  const pointFeatures = features.map((feature) => {
    return new PointrWebSDK.Feature(
      {
        lvl: feature.properties.lvl,
        bid: feature.properties.bid,
        sid: feature.properties.sid,
      },
      { type: feature.geometry.type, coordinates: feature.geometry.coordinates }
    );
  });

  layer1 = new PointrWebSDK.CircleLayer({
    "circle-color": "pink",
    "circle-radius": 5,
  });

  layer2 = new PointrWebSDK.CircleLayer({
    "circle-color": "blue",
    "circle-radius": 5,
  });

  mapViewController.addLayer(layer1);
  mapViewController.updateFeatures(layer1, pointFeatures);

  mapViewController.addLayer(layer2);
  mapViewController.updateFeatures(layer2, pointFeatures);
});

Both layer1 and layer2 are provided with the same features and radius, but different colors. Since there is no aboveLayerId specified in addLayer methods, layer2, the one added later will appear above.

Default order

Without changing the order, only giving the aboveLayerId priority can be changed:

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  mapViewController.addLayer(layer1);
  mapViewController.updateFeatures(layer1, pointFeatures);

  mapViewController.addLayer(layer2, undefined, layer1.id);
  mapViewController.updateFeatures(layer2, pointFeatures);
  
});

Please note that, when aboveLayerId is given, clusterOptions prop should also be given.

Result:

When order changed by giving aboveLayerId

Add Icon

You can add icon to map by creating a SymbolLayer object. First, you need to load an image from an external URL and add it to the style by calling addImage method of mapViewConroller and provide and image id and url of the image file. While creating the SymbolLayer object, you must give the image id as a property.

const mapView = mapViewController.getView();
mapView.on(mapView.events.mapReady, async () => {
  
  await mapViewController.addImage(
    "cat",
    "https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png"
  );
  const layer = new PointrWebSDK.SymbolLayer({
    "icon-image": "cat",
    "icon-size": 0.1,
  });
  mapViewController.addLayer(layer);
  mapViewController.updateFeatures(layer, pointFeatures);
  
});

Result:

Layer Types and Options

Circle Layer

A circle layer renders one or more filled circles on a map. You can use a circle layer to configure the visual appearance of point geometry typed features. A circle layer renders circles whose radius are measured in screen units.

const layer = new PointrWebSDK.CircleLayer(options);

Available options:

circle-blur: Optional. Default is 0. Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.

circle-color: Optional. Default is “#000000”. The fill color of the circle.

circle-opacity: Optional number between 0 and 1. Default is 1. The opacity at which the circle will be drawn.

circle-radius: Optional number greater than or equal to 0. Units in pixels. Default is 5. Circle radius.

circle-stroke-color: Optional color. Default is”#000000”. The stroke color of the circle.

circle-stroke-opacity: Optional number between 0 and 1 inclusive. Default is 1. The opacity of the circle’s stroke.

circle-stroke-width: Optional number greater than or equal to 0. Units in pixels. Default is 0. The width of the circle’s stroke. Strokes are placed outside of the circle-radius.

visibility: Optional enum. One of “visible”, “none”. Defaults to “visible”

minzoom: Optional number between 0-24. Default is 0. This property sets visibility of layer according to given zoom level. 0 is always visible. 24 is only visible at max zoom. To set visibility to level phase set it to 17. To set visibility to site phase set it to 15

maxzoom: Optional number between 0-24. Default is 24

Symbol Layer

A symbol layer renders icon and text labels at points on a map. You can use a symbol layer to configure the visual appearance of labels for features.

const layer = new PointrWebSDK.SymbolLayer(options);

Available options:

icon-anchor: Optional enum. One of “center”, “left”, “right”, “top”, “bottom”, “top-left”, “top-right”, “bottom-left”, “bottom-right”. Defaults to “center”. Requires icon-image.

Part of the icon placed closest to the anchor.

icon-ignore-placement: Optional boolean. Defaults to false. Requires icon-image.

If true, other symbols can be visible even if they collide with the icon.

icon-image: Optional resolvedImage.Name of image in sprite to use for drawing an image background.

icon-offset: Optional array of numbers. Defaults to [0,0]. Requires icon-image. Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up. Each component is multiplied by the value of icon-size to obtain the final offset in pixels. When combined with icon-rotate the offset will be as if the rotated direction was up.

icon-opacity: Optional number between 0 and 1 inclusive. Defaults to 1. Requires icon-image.

The opacity at which the icon will be drawn.

icon-optional: Optional boolean. Defaults to false. Requires icon-image. Requires text-field.

If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.

icon-overlap: Optional enum. One of “never”, “always”, “cooperative”. Requires icon-image.

Allows for control over whether to show an icon when it overlaps other symbols on the map. If icon-overlap is not set, icon-allow-overlap is used instead.

icon-pitch-alignment: Optional enum. One of “map”, “viewport”, “auto”. Defaults to “auto”. Requires icon-image.

Orientation of icon when map is pitched. “map”: The icon is aligned to the plane of the map.

“viewport”: The icon is aligned to the plane of the viewport.”auto”: Automatically matches the value of icon-rotation-alignment.

icon-rotate: Optional number. Units in degrees. Defaults to 0. Requires icon-image.

icon-rotation-alignment: Optional enum. One of “map”, “viewport”, “auto”. Defaults to “auto”. Requires icon-image.In combination with symbol-placement, determines the rotation behavior of icons.”map”: When symbol-placement is set to point, aligns icons east-west. When symbol-placement is set to line or line-center, aligns icon x-axes with the line. “viewport”:

Produces icons whose x-axes are aligned with the x-axis of the viewport, regardless of the value of symbol-placement. “auto”: When symbol-placement is set to point, this is equivalent to viewport. When symbol-placement is set to line or line-center, this is equivalent to map.

icon-size: Optional number greater than or equal to 0. Units in factor of the original icon size. Defaults to 1. Requires icon-image. Scales the original size of the icon by the provided factor. The new pixel size of the image will be the original pixel size multiplied by icon-size. 1 is the original size; 3 triples the size of the image.

symbol-placement: Optional enum. One of “point”, “line”, “line-center”. Defaults to “point”.

Label placement relative to its geometry. “point”: The label is placed at the point where the geometry is located. “line”: The label is placed along the line of the geometry. Can only be used on LineString and Polygon geometries.”line-center”: The label is placed at the center of the line of the geometry. Can only be used on LineString and Polygon geometries. Note that a single feature in a vector tile may contain multiple line geometries.

text-allow-overlap: Optional boolean. Defaults to false. Requires text-field. Disabled by text-overlap.If true, the text will be visible even if it collides with other previously drawn symbols.

text-anchor: Optional enum. One of “center”, “left”, “right”, “top”, “bottom”, “top-left”, “top-right”, “bottom-left”, “bottom-right”. Defaults to “center”. Requires text-field. Part of the text placed closest to the anchor.

text-color: Optional color. Defaults to “#000000”. Requires text-field. The color with which the text will be drawn.

text-field: Optional formatted. Defaults to “”.

Value to use for a text label. If a plain string is provided, it will be treated as a formatted with default/inherited formatting options.

text-font: Optional array of strings. Defaults to [“Open Sans Regular”,”Arial Unicode MS Regular”]. Requires text-field.Font stack to use for displaying text.

text-justify: Optional enum. One of “auto”, “left”, “center”, “right”. Defaults to “center”. Requires text-field.

text-offset: Optional array of numbers. Units in ems. Defaults to [0,0]. Requires text-field. Disabled by text-radial-offset. Supports interpolateexpressions.

Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up. If used with text-variable-anchor, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position.

text-opacity: Optional number between 0 and 1 inclusive. Defaults to 1. Requires text-field.

The opacity at which the text will be drawn.

text-padding: Optional number greater than or equal to 0. Units in pixels. Defaults to 2. Requires text-field. Size of the additional area around the text bounding box used for detecting symbol collisions.

text-pitch-alignment: Optional enum. One of “map”, “viewport”, “auto”. Defaults to “auto”. Requires text-field.Orientation of text when map is pitched.

text-rotate: Optional number. Units in degrees. Defaults to 0. Requires text-field. Rotates the text clockwise.

text-rotation-alignment: Optional enum. One of “map”, “viewport”, “viewport-glyph”, “auto”. Defaults to “auto”. Requires text-field.

text-size:. Optional number greater than or equal to 0. Units in pixels. Defaults to 16. Requires text-field. Font size.

text-transform: Optional enum. One of “none”, “uppercase”, “lowercase”. Defaults to “none”. Requires text-field.Specifies how to capitalize text, similar to the CSS text-transform property.

visibility: Optional enum. One of “visible”, “none”. Defaults to “visible”.

Whether this layer is displayed.

minzoom: Optional number between 0-24. Default is 0. This property sets visibility of layer according to given zoom level. 0 is always visible. 24 is only visible at max zoom. To set visibility to level phase set it to 17. To set visibility to site phase set it to 15

maxzoom: Optional number between 0-24. Default is 24

FillLayer

Green area is added as fill layer

A fill layer renders one or more filled (and optionally stroked) polygons on a map. You can use a fill layer to configure the visual appearance of polygon features.

const layer = new PointrWebSDK.FillLayer(options);

Available options:

fill-color: Optional color. Defaults to “#000000”. The color of the filled part of this layer. This color can be specified as rgba with an alpha component and the color’s opacity will not affect the opacity of the 1px stroke, if it is used.

fill-opacity: Optional number between 0 and 1 inclusive. Defaults to 1.The opacity of the entire fill layer. In contrast to the fill-color, this value will also affect the 1px stroke around the fill, if the stroke is used.

visibility: Optional enum. One of “visible”, “none”. Defaults to “visible”.Whether this layer is displayed.

minzoom: Optional number between 0-24. Default is 0. This property sets visibility of layer according to given zoom level. 0 is always visible. 24 is only visible at max zoom. To set visibility to level phase set it to 17. To set visibility to site phase set it to 15

maxzoom: Optional number between 0-24. Default is 24

FillExtrusionLayer

Green area is added as fill extrusion layer

A fill-extrusion layer renders one or more filled (and optionally stroked) extruded (3D) polygons on a map. You can use a fill-extrusion layer to configure the extrusion and visual appearance of polygon features.

const layer = new PointrWebSDK.FillExtrusionLayer(options);

Available options:

fill-extrusion-base: Optional number greater than or equal to 0. Units in meters. Defaults to 0. Requires fill-extrusion-height. The height with which to extrude the base of this layer. Must be less than or equal to fill-extrusion-height.

fill-extrusion-color: Optional color. Defaults to “#000000”. The base color of the extruded fill.

fill-extrusion-height: Optional number greater than or equal to 0. Units in meters. Defaults to 0.

The height with which to extrude this layer.

fill-extrusion-opacity: Optional number between 0 and 1 inclusive. Defaults to 1. The opacity of the entire fill extrusion layer.

visibility: Layout property. Optional enum. One of “visible”, “none”. Defaults to “visible”. Whether this layer is displayed.

minzoom: Optional number between 0-24. Default is 0. This property sets visibility of layer according to given zoom level. 0 is always visible. 24 is only visible at max zoom. To set visibility to level phase set it to 17. To set visibility to site phase set it to 15

maxzoom: Optional number between 0-24. Default is 24


Last update: January 2, 2024
Back to top