Last updated

Symbol Painters

A Symbol in CarnacJS is a light weight shape that inherits from AnchoredShape and it is drawn by SymbolPainters. CarnacJS has a catalog of pre-built SymbolPainters which consists of various geometrical shapes. It also has a domain specific or standard Oil&Gas SymbolPainters.
This tutorial demonstrates how to create different types of Symbols using the built in SymbolPainters and also shows how easy it is to write a Custom Painter.

# Symbol Basics

Symbols are shapes defined by a Symbol Painter. They are anchored shapes defined by coordinates, width and height, an anchor, and a symbol painter.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { TrianglePainter } from "@int/geotoolkit/scene/shapes/painters/TrianglePainter.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function createScene(canvas) {
  const triangle = new SymbolShape({
    "ax": 100,
    "ay": 100,
    "width": 30,
    "height": 60,
    "alignment": AnchorType.Center,
    "sizeisindevicespace": false,
    "painter": TrianglePainter,
    "linestyle": {
      "color": KnownColors.DarkBlue,
      "width": 2
    },
    "fillstyle": KnownColors.Orange
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(triangle)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Painters

A catalog of symbol painters included with GeoToolkitJS. Different positions of anchor point relative to symbol shape are demonstrated. Position of anchor is marked with small red square.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { CirclePainter } from "@int/geotoolkit/scene/shapes/painters/CirclePainter.ts";
import { CrossPainter } from "@int/geotoolkit/scene/shapes/painters/CrossPainter.ts";
import { DiamondPainter } from "@int/geotoolkit/scene/shapes/painters/DiamondPainter.ts";
import { PlusPainter } from "@int/geotoolkit/scene/shapes/painters/PlusPainter.ts";
import { SquarePainter } from "@int/geotoolkit/scene/shapes/painters/SquarePainter.ts";
import { StarPainter } from "@int/geotoolkit/scene/shapes/painters/StarPainter.ts";
import { TrianglePainter } from "@int/geotoolkit/scene/shapes/painters/TrianglePainter.ts";
import { PlusBarPainter } from "@int/geotoolkit/scene/shapes/painters/PlusBarPainter.ts";
import { Star5Painter } from "@int/geotoolkit/scene/shapes/painters/Star5Painter.ts";
import { FillStyle } from "@int/geotoolkit/attributes/FillStyle.ts";
import { LineStyle } from "@int/geotoolkit/attributes/LineStyle.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function makeAnchorShape(x, y) {
  return new SymbolShape({
    "ax": x,
    "ay": y,
    "width": 7,
    "height": 7,
    "painter": SquarePainter,
    "fillstyle": "red"
  });
}
function createScene(canvas) {
  const shapes = [];
  shapes.push(new SymbolShape(125, 75, 50, 50, AnchorType.RightBottom, false, CirclePainter));
  shapes.push(new SymbolShape(200, 75, 50, 50, AnchorType.BottomCenter, false, CrossPainter));
  shapes.push(new SymbolShape(275, 75, 50, 50, AnchorType.LeftBottom, false, DiamondPainter));
  shapes.push(new SymbolShape(125, 150, 50, 50, AnchorType.RightCenter, false, PlusPainter));
  shapes.push(new SymbolShape(200, 150, 50, 50, AnchorType.Center, false, SquarePainter));
  shapes.push(new SymbolShape(275, 150, 50, 50, AnchorType.LeftCenter, false, StarPainter));
  shapes.push(new SymbolShape(128, 225, 50, 50, AnchorType.RightTop, false, TrianglePainter));
  shapes.push(new SymbolShape(200, 225, 50, 50, AnchorType.TopCenter, false, PlusBarPainter));
  shapes.push(new SymbolShape(275, 225, 50, 50, AnchorType.LeftTop, false, Star5Painter));
  const fillStyle = new FillStyle(KnownColors.Orange);
  const lineStyle = new LineStyle(KnownColors.DarkBlue, 2);
  for (const shape in shapes) {
    shapes[shape].setFillStyle(fillStyle).setLineStyle(lineStyle);
  }
  const anchors = [];
  anchors.push(makeAnchorShape(125, 75));
  anchors.push(makeAnchorShape(200, 75));
  anchors.push(makeAnchorShape(275, 75));
  anchors.push(makeAnchorShape(125, 150));
  anchors.push(makeAnchorShape(200, 150));
  anchors.push(makeAnchorShape(275, 150));
  anchors.push(makeAnchorShape(125, 225));
  anchors.push(makeAnchorShape(200, 225));
  anchors.push(makeAnchorShape(275, 225));
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(shapes).addChild(anchors)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# O&G Painters

A catalog of Oil&Gas dedicated symbolpainters included with GeoToolkitJS.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { LocationPermit } from "@int/geotoolkit/scene/shapes/painters/oilandgas/LocationPermit.ts";
import { LocationPermitExpired } from "@int/geotoolkit/scene/shapes/painters/oilandgas/LocationPermitExpired.ts";
import { Dry } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Dry.ts";
import { Injection } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Injection.ts";
import { Lost } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Lost.ts";
import { Unknown } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Unknown.ts";
import { ShowGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/ShowGas.ts";
import { DryShowGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/DryShowGas.ts";
import { GasShowOil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/GasShowOil.ts";
import { DryShowOil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/DryShowOil.ts";
import { DryShowOilGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/DryShowOilGas.ts";
import { ShowOil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/ShowOil.ts";
import { Gas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Gas.ts";
import { Oil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Oil.ts";
import { OilGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/OilGas.ts";
import { OilShowGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/OilShowGas.ts";
import { ShowOilGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/ShowOilGas.ts";
import { PluggedGasShowOil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedGasShowOil.ts";
import { PluggedGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedGas.ts";
import { PluggedOil } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedOil.ts";
import { PluggedOilGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedOilGas.ts";
import { PluggedOilShowGas } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedOilShowGas.ts";
import { PluggedInjection } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedInjection.ts";
import { Observation } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Observation.ts";
import { Brine } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Brine.ts";
import { WaterSupply } from "@int/geotoolkit/scene/shapes/painters/oilandgas/WaterSupply.ts";
import { PluggedBrine } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedBrine.ts";
import { PluggedWaterSupply } from "@int/geotoolkit/scene/shapes/painters/oilandgas/PluggedWaterSupply.ts";
import { Water } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Water.ts";
import { FillStyle } from "@int/geotoolkit/attributes/FillStyle.ts";
import { LineStyle } from "@int/geotoolkit/attributes/LineStyle.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function createScene(canvas) {
  const shapes = [];
  shapes.push(new SymbolShape(57, 100, 50, 50, AnchorType.Center, false, LocationPermit));
  shapes.push(new SymbolShape(114, 100, 50, 50, AnchorType.Center, false, LocationPermitExpired));
  shapes.push(new SymbolShape(171, 100, 50, 50, AnchorType.Center, false, Dry));
  shapes.push(new SymbolShape(229, 100, 50, 50, AnchorType.Center, false, Injection));
  shapes.push(new SymbolShape(286, 100, 50, 50, AnchorType.Center, false, Lost));
  shapes.push(new SymbolShape(343, 100, 50, 50, AnchorType.Center, false, Unknown));
  shapes.push(new SymbolShape(57, 200, 50, 50, AnchorType.Center, false, ShowGas));
  shapes.push(new SymbolShape(114, 200, 50, 50, AnchorType.Center, false, DryShowGas));
  shapes.push(new SymbolShape(171, 200, 50, 50, AnchorType.Center, false, GasShowOil));
  shapes.push(new SymbolShape(229, 200, 50, 50, AnchorType.Center, false, DryShowOil));
  shapes.push(new SymbolShape(286, 200, 50, 50, AnchorType.Center, false, DryShowOilGas));
  shapes.push(new SymbolShape(343, 200, 50, 50, AnchorType.Center, false, ShowOil));
  shapes.push(new SymbolShape(57, 300, 50, 50, AnchorType.Center, false, Gas));
  shapes.push(new SymbolShape(114, 300, 50, 50, AnchorType.Center, false, Oil));
  shapes.push(new SymbolShape(171, 300, 50, 50, AnchorType.Center, false, OilGas));
  shapes.push(new SymbolShape(229, 300, 50, 50, AnchorType.Center, false, OilShowGas));
  shapes.push(new SymbolShape(286, 300, 50, 50, AnchorType.Center, false, ShowOilGas));
  shapes.push(new SymbolShape(343, 300, 50, 50, AnchorType.Center, false, PluggedGasShowOil));
  shapes.push(new SymbolShape(57, 400, 50, 50, AnchorType.Center, false, PluggedGas));
  shapes.push(new SymbolShape(114, 400, 50, 50, AnchorType.Center, false, PluggedOil));
  shapes.push(new SymbolShape(171, 400, 50, 50, AnchorType.Center, false, PluggedOilGas));
  shapes.push(new SymbolShape(229, 400, 50, 50, AnchorType.Center, false, PluggedOilShowGas));
  shapes.push(new SymbolShape(286, 400, 50, 50, AnchorType.Center, false, PluggedInjection));
  shapes.push(new SymbolShape(343, 400, 50, 50, AnchorType.Center, false, Observation));
  shapes.push(new SymbolShape(57, 500, 50, 50, AnchorType.Center, false, Brine));
  shapes.push(new SymbolShape(114, 500, 50, 50, AnchorType.Center, false, WaterSupply));
  shapes.push(new SymbolShape(171, 500, 50, 50, AnchorType.Center, false, PluggedBrine));
  shapes.push(new SymbolShape(229, 500, 50, 50, AnchorType.Center, false, PluggedWaterSupply));
  shapes.push(new SymbolShape(286, 500, 50, 50, AnchorType.Center, false, Water));
  const fillStyle = new FillStyle(KnownColors.Orange);
  const lineStyle = new LineStyle(KnownColors.DarkBlue, 2);
  for (const shape in shapes) {
    shapes[shape].setFillStyle(fillStyle).setLineStyle(lineStyle);
  }
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(shapes)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Geometry Painter

A geometry symbol painter can be used to reuse simple geometry as symbol. For example to create composite symbol based on other symbols.

import { Rect } from "@int/geotoolkit/util/Rect.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { Text } from "@int/geotoolkit/scene/shapes/Text.ts";
import { GeometryPainter } from "@int/geotoolkit/scene/shapes/painters/GeometryPainter.ts";
import { Dry } from "@int/geotoolkit/scene/shapes/painters/oilandgas/Dry.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function createScene(canvas) {
  const symbol = new SymbolShape({
    "ax": 100,
    "ay": 100,
    "width": 60,
    "height": 60,
    "alignment": AnchorType.Center,
    "painter": new GeometryPainter({
      "geometry": new Group().setBounds(new Rect(0, 0, 60, 60)).addChild([
        new SymbolShape({
          "ax": 30,
          "ay": 30,
          "width": 60,
          "height": 60,
          "alignment": AnchorType.Center,
          "painter": Dry,
          "linestyle": KnownColors.Green
        }),
        new Text({
          "ax": 60,
          "ay": 0,
          "alignment": AnchorType.RightTop,
          "sizeisindevicespace": true,
          "text": "NE",
          "textstyle": {
            "color": KnownColors.Blue,
            "font": "14px sans-serif"
          }
        })
      ])
    })
  });
  symbol.setCss({
    "css": [
      ".geotoolkit.scene.shapes.SymbolShape {",
      "   linestyle: " + KnownColors.DarkBlue + ";",
      "}",
      ".geotoolkit.scene.shapes.Text {",
      "   textstyle-color: " + KnownColors.Green + ";",
      "}"
    ].join("")
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(symbol)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Custom Painter

A custom symbol painter can be used to create your own symbols. To create a custom painter, define a function that accepts a symbol, bounding box, and rendering context.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function PluggedBrineWellSymbolPainter(symbol, bbox, context) {
  context.setFillStyle(symbol.getFillStyle());
  context.setLineStyle(symbol.getLineStyle());
  context.drawLine(bbox.getLeft(), bbox.getTop(), bbox.getRight(), bbox.getBottom());
  context.drawEllipse(bbox.getLeft(), bbox.getTop(), bbox.getWidth(), bbox.getHeight());
  context.drawLine(bbox.getLeft(), bbox.getBottom(), bbox.getRight(), bbox.getTop());
  context.fillPath();
  context.stroke();
}
function createScene(canvas) {
  const symbol = new SymbolShape(100, 100, 60, 60, AnchorType.Center, false, PluggedBrineWellSymbolPainter).setFillStyle(KnownColors.Orange).setLineStyle({
    "color": KnownColors.DarkBlue,
    "width": 2
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(symbol)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Font Painter

A font symbol painter can be used to create symbols from font. To create a font painter, specify the font location, font family(must match with font name) and string that contains symbols codes.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { FontPainter } from "@int/geotoolkit/scene/shapes/painters/FontPainter.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import font from "/src/assets/fonts/Noto Sans Bold.ttf?import";
function createScene(canvas) {
  const symbol = new SymbolShape({
    ax: 50,
    ay: 80,
    width: 80,
    height: 80,
    preserveaspectratio: true,
    alignment: AnchorType.Center,
    painter: new FontPainter(font, '"Noto Sans Bold"', "\xA9"),
    fillstyle: KnownColors.Orange,
    linestyle: {
      "color": KnownColors.DarkBlue,
      "width": 2
    }
  });
  const symbol1 = new SymbolShape({
    ax: 150,
    ay: 80,
    width: 80,
    height: 80,
    preserveaspectratio: true,
    alignment: AnchorType.Center,
    painter: new FontPainter(font, '"Noto Sans Bold"', "\u2117"),
    fillstyle: KnownColors.Orange,
    linestyle: {
      "color": KnownColors.DarkBlue,
      "width": 2
    }
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild([symbol, symbol1])
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# LineAndSymbol Painter

LineAndSymbol Painter is used specially for Line Chart to display Line and symbol. To create LineAndSymbol Painter, specify the painter to be displayed with Line.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { LineAndSymbolPainter } from "@int/geotoolkit/scene/shapes/painters/LineAndSymbolPainter.ts";
import { Star5Painter } from "@int/geotoolkit/scene/shapes/painters/Star5Painter.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
function createScene(canvas) {
  const symbol = new SymbolShape({
    ax: 100,
    ay: 100,
    width: 150,
    height: 150,
    alignment: AnchorType.Center,
    painter: new LineAndSymbolPainter(Star5Painter),
    fillstyle: KnownColors.Orange,
    linestyle: {
      "color": KnownColors.DarkBlue,
      "width": 2
    }
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(symbol)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Image Painter

A image symbol painter can be used to create symbols from image. To create a image painter, specify the url image.

import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { ImagePainter } from "@int/geotoolkit/scene/shapes/painters/ImagePainter.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import image from "/src/assets/images/apple.png?import";
function createScene(canvas) {
  const symbol = new SymbolShape({
    ax: 80,
    ay: 80,
    width: 64,
    height: 64,
    preserveaspectratio: true,
    alignment: AnchorType.Center,
    painter: new ImagePainter(image)
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(symbol)
  });
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));