0

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.

CKool
  • 3
  • 4

1 Answers1

1

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 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 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>
Mike
  • 16,042
  • 2
  • 14
  • 30
  • I am unable to remove that icon when animation is complete.How can I achieve this? – CKool Apr 12 '19 at 07:54
  • Probably best done with an option to change the style on completion, I've added one to the demo. – Mike Apr 12 '19 at 10:53
  • Actually I was looking for any getImage() event or something like that so that I can manipulate the icon only and not the entire Linestring,Because the linestring has connection with other functions in my case. – CKool Apr 12 '19 at 11:32
  • Hello ,recently I have come up with a new scenario where I want to stop the animation at any point of time and remove animated line so far traveled.How can I achieve this? – CKool Apr 17 '19 at 10:26
  • If the animate function returns the postcompose listener key you could use it to stop the animation, e.g. by clicking on the map. – Mike Apr 17 '19 at 10:54
  • Thank you for your last reply but, I m trying to remove the so far traveled animation permanently from the map on an event(for that matter here you are referring map click event).How this can be achieved? – CKool Apr 18 '19 at 05:18
  • You can remove the feature from the source. Just make sure the required variables are in scope, and take care the code doesn't try to remove something twice which will cause an error. – Mike Apr 18 '19 at 13:51
  • Hello,I want to achieve 3D effect for open layers map.For eg.one green line in under the blue line both are getting animated but overlapped with each other .So how to use 3D view so as viewer can see both overlapped lined on map. – CKool Apr 30 '19 at 04:50
  • The simplest way would be to use a narrow stroke for the top line and wider stroke for the line it overlaps. – Mike Apr 30 '19 at 09:13
  • Hello, I applied Console.log() after var point = linestring.getCoordinateAt(Math.min(elapsed/duration, 1)); Its resulting very high number where actual co-ordinates vary in low range (eg. +- 0 to +- 180) How can I achieve 'point' in normal range? – CKool Apr 30 '19 at 14:29
  • hello I am trying to achieve following output but Could not. https://imgur.com/Nl9NSsm As the thin red line animates and reaches point 'A' , Polygon 'A' should be visible , when red animating line reaches 'B' polygon 'B' should be visible and so on. ( In our Case current Co-ordinates of moving pointer are achieved by 'Point'.) – CKool May 02 '19 at 10:16
  • Use `polygon.intersectsCoordinate(point)` to check if the point is in a polygon and set the style or use the style function to display it if required. See https://openlayers.org/en/v4.6.5/apidoc/ol.geom.Polygon.html#intersectsCoordinate – Mike May 02 '19 at 16:00