Last updated

Line Decoration

# Simple Line Decoration

Line decoration is entity that can change shape of line. This example demonstrates existing line decorations.

import { Point } from "@int/geotoolkit/util/Point.ts";
import { LineDecoration } from "@int/geotoolkit/attributes/LineDecoration.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Line } from "@int/geotoolkit/scene/shapes/Line.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { Patterns } from "@int/geotoolkit/attributes/LineStyle.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { Dimension } from "@int/geotoolkit/util/Dimension.ts";
import { FontPainter } from "@int/geotoolkit/scene/shapes/painters/FontPainter.ts";
export const createScene = (canvas) => {
  const lineDecoration = [
    LineDecoration.Solid,
    LineDecoration.Wavy,
    LineDecoration.Double,
    LineDecoration.DoubleWavy,
    LineDecoration.getPainter(new FontPainter("src/assets/fonts/", "Roboto Condensed Light Italic", "/"), new Dimension(10, 10))
  ];
  const lines = [];
  for (let i = 1; i < lineDecoration.length; i++) {
    lines.push(new Line({
      "from": new Point(50, i * 50),
      "to": new Point(300, (i + 1) * 50),
      "linestyle": {
        "color": KnownColors.Blue,
        "width": 2,
        "pattern": Patterns.Solid
      },
      "linedecoration": lineDecoration[i]
    }));
  }
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(lines)
  });
};

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

# Custom Line Decoration

This is example how to create and register custom line decoration.

var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result)
    __defProp(target, key, result);
  return result;
};
import { LineRenderingContext } from "@int/geotoolkit/attributes/LineRenderingContext.ts";
import { Point } from "@int/geotoolkit/util/Point.ts";
import { MathUtil } from "@int/geotoolkit/util/MathUtil.ts";
import { Transformation } from "@int/geotoolkit/util/Transformation.ts";
import { Path } from "@int/geotoolkit/scene/shapes/Path.ts";
import { ILineDecoration } from "@int/geotoolkit/attributes/ILineDecoration.ts";
import { Implements, Obfuscate } from "@int/geotoolkit/decorators.ts";
import { LineDecoration } from "@int/geotoolkit/attributes/LineDecoration.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Line } from "@int/geotoolkit/scene/shapes/Line.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { Patterns } from "@int/geotoolkit/attributes/LineStyle.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
const LINE_WIDTH = 10;
let CustomRenderingState = class extends LineRenderingContext {
  constructor(context) {
    super(context);
    this._lineStyle = null;
    this._context = context;
  }
  setLineStyle(lineStyle, area) {
    this._context.setLineStyle(lineStyle, area);
    this._lineStyle = lineStyle;
    return this;
  }
  drawLine(x1, y1, x2, y2) {
    const transformation = this._context.getTransformation();
    const p1 = transformation.transformXY(x1, y1).clone();
    const p2 = transformation.transformXY(x2, y2).clone();
    const distance = Point.getDistance(p1, p2);
    let angle = 0;
    const px1 = p1.x, py = p1.y;
    let px2;
    if (MathUtil.equals(p1.y, p2.y)) {
      px2 = p2.x;
    } else if (MathUtil.equals(p1.x, p2.x)) {
      angle = (p2.y < p1.y ? -1 : 1) * Math.PI / 2;
      px2 = px1 + distance;
    } else {
      angle = Math.asin(Math.abs(p1.y - p2.y) / distance);
      if (p2.y < p1.y) {
        if (p2.x < p1.x) {
          angle = -(Math.PI - angle);
        } else {
          angle = -angle;
        }
      } else if (p2.x < p1.x) {
        angle = angle + Math.PI / 2;
      }
      px2 = px1 + distance;
    }
    this._context.setTransformation(new Transformation());
    const path = new Path({
      "linestyle": this._lineStyle
    });
    let currentY = -LINE_WIDTH * 0.5;
    path.moveTo(px1, py + currentY);
    for (let i = px1 + LINE_WIDTH; i <= px2; i += LINE_WIDTH) {
      currentY = -currentY;
      path.lineTo(i, py + currentY);
    }
    const reminder = (px2 - px1) % LINE_WIDTH;
    if (reminder > 0) {
      path.lineTo(px2, py + (currentY > 0 ? currentY - reminder : currentY + reminder) / LINE_WIDTH);
    }
    path.rotate(angle, p1.x, p1.y);
    path.render(this._context);
    path.dispose();
    this._context.setTransformation(transformation);
  }
};
CustomRenderingState = __decorateClass([
  Obfuscate()
], CustomRenderingState);
let CustomLine = class {
  getName() {
    return "custom";
  }
  getLineWidth(lineStyle) {
    return LINE_WIDTH;
  }
  createLineRenderingContext(context) {
    return new CustomRenderingState(context);
  }
};
CustomLine = __decorateClass([
  Obfuscate(),
  Implements(ILineDecoration)
], CustomLine);
LineDecoration.registerLineDecoration("custom", new CustomLine());
export const createScene = (canvas) => {
  const lineDecoration = LineDecoration.getLineDecoration("custom");
  const line = new Line({
    "from": new Point(50, 50),
    "to": new Point(300, 300),
    "linestyle": {
      "color": KnownColors.Blue,
      "width": 2,
      "pattern": Patterns.Solid
    },
    "linedecoration": lineDecoration
  });
  return new Plot({
    "canvaselement": canvas,
    "root": new Group().addChild(line)
  });
};

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