Arrows indicating the direction of a LineString feature in Openlayers 4

I'm attempting to create a LineString with arrows at the end of each line to indicate the direction of the route. I found an example on the official site: The example code in the link creates arrows through user drawing, but I need arrows for a given LineString. In my code, I have included icons for the start and end points of the route. When I include

'route': new ol.style.Style({
      stroke: new ol.style.Stroke({
        width: 6, color: [23, 120, 22, 0.6]
      })
    }),

in styles, my code functions properly. However, when I try to incorporate the style for LineString from the example, it throws an error stating "Uncaught TypeError: c.Y is not a function".

Below is my code snippet:

var points = [
  [76.8412, 43.2245], [76.8405, 43.2210], [76.8479, 43.2200], [76.8512, 43.2220]
];

var route = new ol.geom.LineString(points);
route.transform('EPSG:4326', 'EPSG:3857');

var routeFeature = new ol.Feature({
  type: 'route',
  geometry: route
});
var startMarker = new ol.Feature({
  type: 'icon-a',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[0]))
});
var endMarker = new ol.Feature({
  type: 'icon-b',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[points.length - 1]))
});

var styles = {
  'route': function(feature) {
    var geometry = feature.getGeometry();
    var styles = [
      // linestring
      new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-a.png'
    })
      })
    ];

    geometry.forEachSegment(function(start, end) {
      var dx = end[0] - start[0];
      var dy = end[1] - start[1];
      var rotation = Math.atan2(dy, dx);
      // arrows
      styles.push(new ol.style.Style({
        geometry: new ol.geom.Point(end),
        image: new ol.style.Icon({
          src: 'https://openlayers.org/en/v4.6.3/examples/data/arrow.png',
          anchor: [0.75, 0.5],
          rotateWithView: true,
          rotation: -rotation
        })
      }));
    });

    return styles;
  },
  'icon-a': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-a.png'
    })
  }),
  'icon-b': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-b.png'
    })
  })
};

var vectorLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [routeFeature, startMarker, endMarker]
  }),
  style: function(feature) {
    return styles[feature.get('type')];
  }
});

var center = ol.proj.fromLonLat([76.8512, 43.2220]);
var map = new ol.Map({
  target: document.getElementById('map'),
  view: new ol.View({
    center: center,
    zoom: 15,
    minZoom: 2,
    maxZoom: 19
  }),
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ]
});
#map {
  /* just for testing purposes */
  width: 100%;
  min-width: 100px;
  max-width: 500px;
  margin-top: 50px;
  height: 50px;
}
<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v4.6.4/build/ol-debug.js"></script>
<div id="map"></div>

Answer №1

If you want to improve debugging, consider using ol-debug.js instead of ol.js. This uncompressed version can be more helpful in identifying issues. The specific exception you are encountering is:

TypeError: style.getImage is not a function (Line 30443)

This error arises when your styles object is a mix of functions and plain Style objects.

In most cases, OpenLayers can handle this mix seamlessly. However, when you provide a function to vectorLayer, the problem surfaces. OpenLayers recognizes that a function is provided and executes it. The expected return value of that function should be a style object. But for route, a function is being returned instead!

Therefore, when OpenLayers calls:

style: function(feature) {
    return styles[feature.get('type')];
}

It fetches styles for icon-a and icon-b, but encounters a function for route.

You need to update your style function to address this special case:

style: function(feature) {
  const myStyle = stylesMap[feature.get('type')];
  if (myStyle instanceof Function) {
    return myStyle(feature);
  }
  return myStyle;
}

Note: Reusing the same variable name (styles) is not recommended as it can result in unexpected bugs.

For implementation reference, refer to the example below:

...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be causing a react element to fail to update?

I'm currently working on a React component that interacts with a MaterialUi text form. The component utilizes a useState hook to update based on the input received. My goal is to have another variable update when the form is submitted, which will be d ...

What is the process for specifying a method on a third-party class in TypeScript?

I'm facing a challenge while trying to extend a third-party class in TypeScript. The issue is that I am unable to access any existing methods of the class within my new method. One possible solution could be to redeclare the existing methods in a sep ...

URL validation RegEx in AngularJs using Javascript

I am looking for the following URLs to return as true other.some.url some.url some.url/page/1 The following URL should be flagged as false somerandomvalue Here is the regex I have been experimenting with so far: /^(?:http(s)?:\/\/) ...

How can I transform an HTML element into a textarea using CSS or JavaScript?

While browsing a webpage, I discovered a <div> element with the class .plainMail and I want to find a way to easily select all its text by simply pressing Ctrl+A. Currently using Firefox 22, I am considering converting the div.plainMail into a texta ...

The padding of elements changes accordingly as the dimensions (width/height) of the header are adjusted

Currently, I'm tackling the challenges of working on my website and trying to understand JavaScript better. I am facing an issue where I want my aside menu's padding to adjust when my header shrinks in height. Furthermore, at the end of the web ...

Retrieve Element By Class Name in JavaScript

How can I modify the border color at the bottom of the .arrow_box:after? Javascript Solution document.getElementsByClassName("arrow_box:after")[0].style.borderBottomColor = "blue"; Despite trying this solution, it seems to be ineffective! For a closer ...

Avoid running multiple YouTube views simultaneously within an AngularJS application

Currently, I have an Angularjs application that displays a list of Youtube videos utilizing the videogular node module. An issue has arisen where users can play multiple Youtube videos simultaneously, leading to potential violations of Youtube's poli ...

Vitest encountered an issue fetching a local file

I am currently working on testing the retrieval of a local file. Within my project, there exists a YAML configuration file. During production, the filename may be altered as it is received via a web socket. The code functions properly in production, but ...

Display data from a PHP array in a JavaScript alert box

Within my Wordpress registration form, I am attempting to display the $error array in an alert message. I have experimented with using console.log(), but it does not show any output. Even when using JSON.stringify(), the alert only displays the word: true ...

Do you have any recommendations for a jQuery plugin that can create a sleek horizontal scrolling image gallery?

Recently, I came across the Smooth div scroll plugin developed by Thomas Kahn, and it fits my requirements perfectly. However, I have encountered a bug that seems to be persisting. The issue arises when both mousewheel scroll and touch scroll are enabled s ...

Iterate through a local storage object using JavaScript's looping mechanism

I am currently working on a project to create a shopping cart using local storage. I have initialized the local storage with the following code: var cart = {}; cart.products = []; localStorage.setItem('cart', JSON.stringify(cart)); I then use ...

When attempting to access http://localhost:3000/highLightTitle.png using Next.js, a 404 error (Not Found) was encountered in the content

Despite not having any mention of GET http://localhost:3000/highLightTitle.png in my Next.js project code, I am encountering an error related to this issue. The error can be viewed here, and specifically at line 199 in content.js which can be seen here. T ...

Can we create a process that automatically transforms any integer field into a hashed string?

Is there a non-hacky way to hash all IDs before returning to the user? I have explored the documentation extensively but haven't found a solution that covers all scenarios. I am working with Postgres and Prisma ORM, managing multiple models with rela ...

Dealing with errors when implementing an Angular 2 route guard that returns an Observable of type boolean can be a

My route guard is implemented as follows: @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private authenticationSvc: AuthenticationService) { } canActivate(): Observable<boolean> { return this. ...

The property 'label' is not found in the 'string' type in Typescript

Below is the code snippet I am using: interface State { resourceGroup: QuickPickItem | string; } setEvent(state.resourceGroup?.label).catch(err => console.error(err)); When executing this code, I encountered the following error messa ...

Achieving a Full-Screen Three.js Canvas in React: A step-by-step guide on spanning the view height and width of a webpage

I've been working on tweaking the code found in this particular example: How to connect Threejs to React? This is the snippet of code I am focusing on: import React, { Component } from 'react' import * as THREE from 'three' clas ...

What could be causing my form not to Submit when attempting submission without utilizing the submit button?

Here is the code for my validation: $(function () { function validateForm() { // Code to validate form inputs } $('#myform').submit(validateForm); }); After this, I want to submit the form when a certain action occurs: < ...

Whenever I navigate to a new page in my NEXTJS project, it loads an excessive number of modules

I am currently working on a small Next.js project and facing an issue where the initial load time is excessively long. Whenever I click on a link to navigate to a page like home/product/[slug], it takes around 12 seconds to load due to compiling over 2000 ...

Encountering a problem when trying to create a node in Neo4j using Node.js

Here is my code for a Node.js application using Neo4j: var neo4j = require('neo4j-driver').v1; var express = require('express'); var logger = require('morgan'); var path = require('path'); var bodyParser =require(&a ...

Discovering a specific property of an object within an array using Typescript

My task involves retrieving an employer's ID based on their name from a list of employers. The function below is used to fetch the list of employers from another API. getEmployers(): void { this.employersService.getEmployers().subscribe((employer ...