Ad

Adding Image Along With Animated Linestring

I am trying to add an image/icon style along the lineString which is animating,but image/icon style is not getting added.

Here is my style for line

var lineStyle = new ol.style.Style({
    image: new ol.style.Icon(({
        opacity: 1,
        size: 20,
        src: '/Images/Leaflet.custom.marker/red_animation_marker.png'
    })),
    stroke: new ol.style.Stroke({
        color: 'black',
        width: 5,
        lineDash: [10,5],
    })
});

Refer following link animating line for current output.

What I am trying to achieve is, there should be a marker or pointer on the head of line which will indicate that line is following certain path, an arrow icon or style.

Ad

Answer

You need a separate style for the icon which includes a geometry (which will be the current point on the line). You might also want to calculate the angle to align your icon based on that and the previous point.

var blue = new ol.style.Style({
  stroke: new ol.style.Stroke({
width: 6,
color: 'blue'
  })
});

var red = new ol.style.Style({
  stroke: new ol.style.Stroke({
width: 2,
color: 'red'
  })
});

var style = function(feature) {
  var styles = [red];
  coords = feature.getGeometry().getCoordinates().slice(-2);
  styles.push(
new ol.style.Style({
  geometry: new ol.geom.Point(coords[1]),
  image: new ol.style.Icon({
    src: 'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
    rotation: Math.atan2(coords[1][0]-coords[0][0], coords[1][1]-coords[0][1])
  })
})
  )
  return styles;
}

var raster = new ol.layer.Tile({
  source: new ol.source.OSM()
});

var vector = new ol.layer.Vector({
  source: new ol.source.Vector(),
  style: blue
});

var map = new ol.Map({
  layers: [raster, vector],
  target: 'map',
  view: new ol.View()
});

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/IvanSanchez/Leaflet.Polyline.SnakeAnim/master/route.js');
xhr.onload = function() {
  // read the route coordinates
  eval(xhr.responseText);
  // reverse the route
  var geom = new ol.geom.LineString(route.reverse());
  // change Lat/Lon to Lon/Lat
  geom.applyTransform(function(c){ return c.reverse(); });
  geom.transform('EPSG:4326', map.getView().getProjection());
  vector.getSource().addFeature(new ol.Feature(geom));  

  map.getView().fit(geom, { size: map.getSize() });
  var snake = new ol.Feature();
  snake.setStyle(style);
  vector.getSource().addFeature(snake);
  var snakeKey = animate_line(snake, geom, 30000, red);

  map.once('singleclick', function() {
ol.Observable.unByKey(snakeKey);
vector.getSource().removeFeature(snake);
  });

}
xhr.send();

function animate_line(feature, linestring, duration, completionStyle) {

  var length = linestring.getLength();
  var length_shown = 0;

  var coords = linestring.getCoordinates();
  var coords_shown = [coords[0], coords[0]];
  var geom_shown = new ol.geom.LineString(coords_shown);
  feature.setGeometry(geom_shown);

  var coordcount = 1;
  var start = new Date().getTime();
  var listenerKey = map.on('postcompose', animate);

  function animate() {

var elapsed = new Date().getTime() - start;
var toAdd = length*elapsed/duration - length_shown;
var point = linestring.getCoordinateAt(Math.min(elapsed/duration, 1));

// restart from last intermediate point and remove it
var newPart = new ol.geom.LineString(coords_shown.slice(-1));
coords_shown.pop();

// add vertices until required length exceeded
while (coordcount < coords.length && newPart.getLength() <= toAdd) {
  newPart.appendCoordinate(coords[coordcount]);
  coords_shown.push(coords[coordcount]);
  coordcount++;
}

// replace overrun vertex with intermediate point
coords_shown.pop();
coordcount--;
coords_shown.push(point);

geom_shown.setCoordinates(coords_shown);
length_shown += toAdd;

if (elapsed > duration) {
  feature.setStyle(completionStyle);
  ol.Observable.unByKey(listenerKey);
}
map.render();

  }

  return listenerKey;

}

/*
draw = new ol.interaction.Draw({
  source: vector.getSource(),
  type: 'LineString'
});

draw.on('drawend',function(evt){
  geom = evt.feature.getGeometry();
  evt.feature.setGeometry(undefined);
  animate_line(evt.feature, geom, 6000);
});
map.addInteraction(draw);
*/
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link target="_blank" rel="nofollow noreferrer" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

Same snippet plus some polygons:

var blue = new ol.style.Style({
  stroke: new ol.style.Stroke({
width: 6,
color: 'blue'
  })
});

var red = new ol.style.Style({
  stroke: new ol.style.Stroke({
width: 2,
color: 'red'
  })
});

var style = function(feature) {
  var styles = [red];
  coords = feature.getGeometry().getCoordinates().slice(-2);
  styles.push(
new ol.style.Style({
  geometry: new ol.geom.Point(coords[1]),
  image: new ol.style.Icon({
    src: 'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
    rotation: Math.atan2(coords[1][0]-coords[0][0], coords[1][1]-coords[0][1])
  })
})
  )
  return styles;
}

var raster = new ol.layer.Tile({
  source: new ol.source.OSM()
});

var vector = new ol.layer.Vector({
  source: new ol.source.Vector(),
  style: function(feature) {
if (feature.getGeometry().getType() == 'Polygon') {
  return feature.get('reached') ? red : [];
}
return blue
  }
});

var map = new ol.Map({
  layers: [raster, vector],
  target: 'map',
  view: new ol.View()
});

var poly = new ol.geom.Polygon([[[0,40], [10,60], [20,40], [10,20], [0,40]]]);
var polygons = [];
for (var i=0; i<4; i++) {
  var poly2 = poly.clone();
  poly2.translate(i*30, 0);
  polygons.push(new ol.Feature(poly2.transform('EPSG:4326', map.getView().getProjection())));
}
vector.getSource().addFeatures(polygons);

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/IvanSanchez/Leaflet.Polyline.SnakeAnim/master/route.js');
xhr.onload = function() {
  // read the route coordinates
  eval(xhr.responseText);
  // reverse the route
  var geom = new ol.geom.LineString(route.reverse());
  // change Lat/Lon to Lon/Lat
  geom.applyTransform(function(c){ return c.reverse(); });
  geom.transform('EPSG:4326', map.getView().getProjection());
  vector.getSource().addFeature(new ol.Feature(geom));  

  map.getView().fit(geom, { size: map.getSize() });
  var snake = new ol.Feature();
  snake.setStyle(style);
  vector.getSource().addFeature(snake);
  var snakeKey = animate_line(snake, geom, 30000, red);

  map.once('singleclick', function() {
ol.Observable.unByKey(snakeKey);
vector.getSource().removeFeature(snake);
  });

}
xhr.send();

function animate_line(feature, linestring, duration, completionStyle) {

  var length = linestring.getLength();
  var length_shown = 0;

  var coords = linestring.getCoordinates();
  var coords_shown = [coords[0], coords[0]];
  var geom_shown = new ol.geom.LineString(coords_shown);
  feature.setGeometry(geom_shown);

  var coordcount = 1;
  var start = new Date().getTime();
  var listenerKey = map.on('postcompose', animate);

  function animate() {

var elapsed = new Date().getTime() - start;
var toAdd = length*elapsed/duration - length_shown;
var point = linestring.getCoordinateAt(Math.min(elapsed/duration, 1));

for (var i=0; i<polygons.length; i++) {
   if (!polygons[i].get('reached') && polygons[i].getGeometry().intersectsCoordinate(point)) {
     polygons[i].set('reached', true);
   }
}

// restart from last intermediate point and remove it
var newPart = new ol.geom.LineString(coords_shown.slice(-1));
coords_shown.pop();

// add vertices until required length exceeded
while (coordcount < coords.length && newPart.getLength() <= toAdd) {
  newPart.appendCoordinate(coords[coordcount]);
  coords_shown.push(coords[coordcount]);
  coordcount++;
}

// replace overrun vertex with intermediate point
coords_shown.pop();
coordcount--;
coords_shown.push(point);

geom_shown.setCoordinates(coords_shown);
length_shown += toAdd;

if (elapsed > duration) {
  feature.setStyle(completionStyle);
  ol.Observable.unByKey(listenerKey);
}
map.render();

  }

  return listenerKey;

}
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link target="_blank" rel="nofollow noreferrer" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

Ad
source: stackoverflow.com
Ad