Alici-EdOna
Alici-EdOna

Reputation: 1

vue3-openlayers - direction arrow on lineString as a single feature

I am trying to create a map which takes coordinates and displays a line on the map with a direction arrow from end point to start in the middle.

Now I am trying to add interaction in it so when a user selects the line or the arrow, it should be selected as a single feature.

Currently my line and arrow are selected separately because I am actually using them as different features in a layer.

How can I have the line and arrow as a single feature in vue3-openlayers specifically?

My main goal is to make the line and arrow selected together as a single feature. I have seen examples of open layers code but don't know how to use them with vue3-openlayers.

Any help or guidance related to what I need to learn to implement it is appreciated.

Below is my template code:

<div v-for="(data, index) in [[0.1,0.2], [0.3,0.4]" :key="index">
  <ol-feature>
    <ol-geom-line-string :coordinates="data"> </ol-geom-line-string>
      <ol-style>
        <ol-style-stroke
           color="purple"
           width="4"
        ></ol-style-stroke>
      </ol-style>
  </ol-feature>

  <ol-feature>
    <ol-geom-point
      :coordinates="calculateMidpoint(data)"
    ></ol-geom-point>
    <ol-style>
      <ol-style-icon
        :src="arrowIcon"
        :scale="0.06"
        :color="purple"
        :rotation="calculateRotation(data)"
      ></ol-style-icon>
    </ol-style>
  </ol-feature>
</div>

Upvotes: 0

Views: 202

Answers (1)

Alici-EdOna
Alici-EdOna

Reputation: 1

Solution:

So after a lot of trial and error I have finally been able to figure out how to add the arrow to the vector line.

So the line string is a single feature and adding an arrow as another feature on top of it is not a solution as this makes the line and the arrow as two different features.

If you use interaction to select any of these features then they will be selected separately as both items are distinct features just placed on top of one another.

The solution is to just have the LineString as a line and use styling to add the arrow image on top of it.

Here is the code:

<template>
  <ol-feature>
    <ol-geom-line-string :coordinates="coordinates"> </ol-geom-line-string>
    <ol-style :overrideStyleFunction="overrideStyleFunction"></ol-style>
  </ol-feature>
</template>

Setup Script

import { pathStyleFunction } from "./map";
import { Icon, Stroke, Style } from "ol/style";
import { LineString, Point } from "ol/geom";
import arrow from "@/assets/arrow-head.png";
import { Coordinate } from "ol/coordinate";

const props = defineProps(["strokeColor", "strokeWidth", "coordinates"]);

const overrideStyleFunction = (feature: Feature<LineString>): Style[] => {
  return pathStyleFunction(feature, props.strokeColor, props.strokeWidth);
};

const pathStyleFunction = (
  feature: Feature<LineString>,
  strokeColor: string,
  strokeWidth: number
): Style[] => {
  const geometry = feature.getGeometry();
  const styles = [
    // linestring style
    new Style({
      stroke: new Stroke({
        color: strokeColor,
        width: strokeWidth,
      }),
    }),
  ];

  if (geometry) {
    geometry.forEachSegment((start: Coordinate, end: Coordinate): void => {
      const rotation = calculateRotation(start, end);
      const mid = calculateMidpoint(start, end);

      styles.push(
        // Arrow Icon on top of line with rotation (of icon)
        new Style({
          geometry: new Point(mid),
          image: new Icon({
            src: arrow,
            rotateWithView: true,
            rotation,
            scale: 0.15,
            color: strokeColor,
          }),
        })
      );
    });
  }

  return styles;
};

This is how the LineString looks like after the custom styling (The red and blue markers are a different feature):

Upvotes: 0

Related Questions