如何动态更改图标源

How can I change icon source dynamically

我有下面的代码

var content = document.getElementById('popup-content');
var center = ol.proj.transform([44.6753, 25.7136], 'EPSG:4326', 'EPSG:3857'); //initial position of map
            //  ol.proj.fromLonLat([44.6753, 25.7136])
var view = new ol.View({
        center: center,  
        zoom: 6   
});  // {"unique_id": "Riyadh", "lat": 24.7136, "lon": 46.6753, "speed": 1}

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

straitSource = new ol.source.Vector({ wrapX: true });

var clusterLayer = new ol.layer.Vector({
  source: new ol.source.Cluster({
    source: straitSource,
    distance: 40
  })
});

map = new ol.Map({
    layers: [OSMBaseLayer, clusterLayer],
    target: 'map',
    view: view,
    controls: [new ol.control.FullScreen(), new ol.control.Zoom()]
});

var icon = new ol.style.Icon({
        anchor: [0.5, 0.5],   // Default value is the icon center.
        scale: 0.3,
        color: '#ffcd46',
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/truck128.png'
});

var iconStyle = new ol.style.Style({
    image: icon
});

var styleCache = {};
clusterLayer.setStyle(function(feature) {
    var size = feature.get('features').length;
    if (size == 1 && map.getView().getZoom() > 16) {  // size == 1 && resolution < map.getView.getResolutionForZoom(6)
          // if a cluster of one show the normal icon
          return iconStyle
    } else {
          // otherwise show the number of features
          var style = styleCache[size];
          if (!style) {
            style = new ol.style.Style({
              image: new ol.style.Circle({
                radius: 10,
                stroke: new ol.style.Stroke({
                  color: '#fff'
                }),
                fill: new ol.style.Fill({
                  color: '#3399CC'
                })
              }),
              text: new ol.style.Text({
                text: size.toString(),
                fill: new ol.style.Fill({
                  color: '#fff'
                })
              })
            });
            styleCache[size] = style;
          }
          return style;
    }
});


// Popup showing the position the user clicked
var container = document.getElementById('popup');
var popup = new ol.Overlay({
    element: container,
    autoPan: true,
    autoPanAnimation: {
        duration: 1000
    }
});

/* Add a pointermove handler to the map to render the popup.*/
map.on('click', function (evt) {    // 'pointermove'
      var cluster = map.forEachFeatureAtPixel(evt.pixel, function (feat) {
        return feat;
      },{
        // restrict to the cluster layer
        layerFilter: function(layer) {
          return (layer === clusterLayer);
        }
      });

      if (cluster && map.getView().getZoom() > 16) {
          map.addOverlay(popup);
          var coordinate = evt.coordinate;    //default projection is EPSG:3857 you may want to use ol.proj.transform
          // list all the features in the cluster
          content.innerHTML = '';
          cluster.get('features').forEach(function(feature) {
            content.innerHTML += (feature.get('desc') + '<br>');
          });
          popup.setPosition(coordinate);
      } else {
          popup.setPosition(undefined);      
      }
});

我希望能够在达到的条件下更改图标源,例如:

if(obj.free_op) {/* use green truck icon*/}
else { /* use red truck icon */} }

更新

获得答案后的完整代码,问题是根据收到的最新更新,为所有用户定义了 freebusy 图标:

map initiation:

<script>
var content = document.getElementById('popup-content');
var center = ol.proj.transform([44.6753, 25.7136], 'EPSG:4326', 'EPSG:3857'); /
            //  ol.proj.fromLonLat([44.6753, 25.7136])
var view = new ol.View({
        center: center,  
        zoom: 6   
});  

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

straitSource = new ol.source.Vector({ wrapX: true });

var clusterLayer = new ol.layer.Vector({
  source: new ol.source.Cluster({
    source: straitSource,
    distance: 40
  })
});

map = new ol.Map({
    layers: [OSMBaseLayer, clusterLayer],
    target: 'map',
    view: view,
    controls: [new ol.control.FullScreen(), new ol.control.Zoom()]
});

var container = document.getElementById('popup');
var popup = new ol.Overlay({
    element: container,
    autoPan: true,
    autoPanAnimation: {
        duration: 1000
    }
});

/* Add a pointermove handler to the map to render the popup.*/
map.on('click', function (evt) {    // 'pointermove'
      var cluster = map.forEachFeatureAtPixel(evt.pixel, function (feat) {
        return feat;
      },{
        // restrict to the cluster layer
        layerFilter: function(layer) {
          return (layer === clusterLayer);
        }
      });

      if (cluster && map.getView().getZoom() > 13) {
          map.addOverlay(popup);
          var coordinate = evt.coordinate;    //default projection is EPSG:3857 you may want to use ol.proj.transform
          // list all the features in the cluster
          content.innerHTML = '';
          cluster.get('features').forEach(function(feature) {
            content.innerHTML += (feature.get('desc') + '<br>');
          });
          popup.setPosition(coordinate);
      } else {
          popup.setPosition(undefined);      
      }
});

const list = document.querySelector('#menuList');

const searchBar = document.forms['search-truck'].querySelector('input');
searchBar.addEventListener('keyup', function(e){
  const trucks = Array.from(list.getElementsByTagName('li'));
  const term = e.target.value.toLowerCase();
  trucks.forEach(function(truck){
    const title = truck.textContent.toLowerCase();
    if(title.includes(term)){ 
      truck.style.display = 'inline-block';
    }
    else { 
      truck.style.display = 'none';
    } 
  })
})

function arrayRemove(arr, value) {
   return arr.filter(function(ele){
       return ele != value;
   });
}
</script>

Socket handling

<script>
    var socket = new WebSocket("ws://127.0.0.1:8080/ws");

    var menuList = document.querySelector('#menuList');

    var devices = [];  // new Array();
    var markers = {};  // new Object();

    socket.onopen = function (event) {}
    socket.onoclose = function (event) {}
    socket.onerror = function (error) {
        console.log('Error ${error.message}')
    }
    socket.onmessage = function (event) {
        console.log(event.data)
        var messages = document.getElementById("messages");
        messages.innerHTML += event.data;
        var obj = JSON.parse(event.data);
       // console.log(obj);
        var device = obj.unique_id;
        var data=[{"Lon":19.455128,"Lat":41.310575}];

        var li = document.createElement('li');
       // li.textContent = obj.unique_id;   // .innerHTML
        li.appendChild(document.createTextNode(obj.unique_id));
        li.id = obj.unique_id;

        const trucks = Array.from(list.getElementsByTagName('li'));

        let found = trucks.findIndex((e) => e.id == obj.unique_id);
        if (found === -1) {
            li.setAttribute("lon", obj.lon);
            li.setAttribute("lat", obj.lat);
            menuList.appendChild(li);
        } else {
            const index = trucks.findIndex((e) => e.id === li.id);
            trucks[index].setAttribute("lon", obj.lon);
            trucks[index].setAttribute("lat", obj.lat);
        }

        menuList.addEventListener("click", function(e) {
            if (e.target && e.target.matches("li")) {
               var lon = Number(e.target.getAttribute('lon'));
               var lat = Number(e.target.getAttribute('lat'));
               view.animate({center: new ol.proj.fromLonLat([lon, lat])}, {zoom: 15.1});
            }
        });
if(obj.free_op) {console.log('obj.free_op 1: '+obj.free_op)}
else {console.log('obj.free_op 2: '+obj.free_op)}

var stdStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 0.5],   // Default value is the icon center.
        scale: 0.3,          // resize imge
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/man_human-128.png'
    })
});

var freeStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 0.5],   // Default value is the icon center.
        scale: 0.3,          // resize imge
        color: '#49fc82',    // green
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/man_human-128.png'
    })
});

var busyStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 0.5],   // Default value is the icon center.
        scale: 0.3,
        color: '#ff704d',     // busy
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/man_human-128.png'
    })
});

var styleCache = {};

clusterLayer.setStyle(function(feature) {
    var size = feature.get('features').length;
    if (size == 1 && map.getView().getZoom() > 13) {
         if (obj.free_op) { return freeStyle; }  
         else { return busyStyle; }  
    } else {
          var style = styleCache[size];
          if (!style) {
            style = new ol.style.Style({
              image: new ol.style.Circle({
                radius: 10,
                stroke: new ol.style.Stroke({
                  color: '#fff'
                }),
                fill: new ol.style.Fill({
                  color: '#3399CC'
                })
              }),
              text: new ol.style.Text({
                text: size.toString(),
                fill: new ol.style.Fill({
                  color: '#fff'
                })
              })
            });
            styleCache[size] = style;
          }
          return style;
    }
});

var desc = `Person/Vehicle: <h5>` + obj.unique_id + `<h5>
          <form id="task_form" action="/" method="post" accept-charset="utf-8">
          <input type="hidden" name="status" value='New'>
          <input type="hidden" name="command" value='Task'>
          <input type="hidden" name="truck_id" value=` + obj.unique_id + `>
          Task: <input type="text" name="task"><br>
          Details: <textarea name="details" rows="4" cols="50"></textarea><br>
          Customer Name: <input type="text" name="customer"><br>
          Mobile: <input type="number" name="mobile"><br>
          Address: <br>
          <input type="number" name="lon" placeholder="longitude">
          <input type="number" name="lat" placeholder="latitude"><br>
          <textarea name="address" placeholder="Address details/notes" rows="4" cols="50"></textarea><br>
          Schedule: <input type="date" name="datePicker" value= "2019-01-01"
          min="2019-01-01" max="2020-12-31">
          <input type="time" name="timePicker" value="00:00"><br><br><br>
          </form>
          <button onclick="handleFormSubmit(document.forms['task_form'], '/')">Login</button>
`
        var iconFeature = new ol.Feature({
            geometry: new ol.geom.Point(ol.proj.transform([obj.lon, obj.lat], 'EPSG:4326', 'EPSG:3857')),
            type: 'Point',
            desc:  desc
        });

        iconFeature.setStyle(stdStyle);

        if(!devices.includes(device)) {
            devices.push(device);
        var coordinates = [obj.lon, obj.lat];
            markers[device]= iconFeature;
            straitSource.addFeature(iconFeature);
        } else {
           // devices = devices.filter(function(value, index, arr){ return value != device; });
            straitSource.removeFeature(markers[device]);
            straitSource.addFeature(iconFeature);
            markers[device]= iconFeature;
        }   
    };
</script>

ol.style.Icon 没有 setSrc 方法,因此您需要为每个来源创建一个。然后根据需要在 ol.style.Style 中设置:

if (size == 1 && map.getView().getZoom() > 16) {  // size == 1 && resolution < map.getView.getResolutionForZoom(6)
      // if a cluster of one show the normal icon
      iconStyle.setImage(obj.free_op ? greenIcon : redIcon);
      return iconStyle
} else { }

或为每个图标创建一个完整的 ol.style.Style 并 return 在您的样式函数中适当的一个:

if (size == 1 && map.getView().getZoom() > 16) {  // size == 1 && resolution < map.getView.getResolutionForZoom(6)
      // if a cluster of one show the normal icon
      if (obj.free_op) { return greenIconStyle; }
      else { return redIconStyle; }
} else { }

完整代码如下所示:

var greenIconStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 0.5],
        scale: 0.3,
        color: '#ffcd46',
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/greenIcon.png'
    })
});

var redIconStyle = new ol.style.Style({
    image: new ol.style.Icon({
        anchor: [0.5, 0.5],
        scale: 0.3,
        color: '#ffcd46',
        crossOrigin: 'anonymous',
        src: 'http://127.0.0.1:8081/static/img/redIconStyle.png'
    })
});

if (size == 1 && map.getView().getZoom() > 16) {  
   if (obj.free_op) { return greenIconStyle; }
         else { return redIconStyle; }
    } else {
}

iconFeature.setStyle( obj.free_op ? greenIconStyle : redIconStyle)

更新 您需要将卡车的 free_op 值设置为特征 属性

    var iconFeature = new ol.Feature({
        geometry: new ol.geom.Point(ol.proj.transform([obj.lon, obj.lat], 'EPSG:4326', 'EPSG:3857')),
        type: 'Point',
        desc:  desc,
        free_op: obj.free_op
    });

并在样式函数中进行测试

clusterLayer.setStyle(function(feature) {
    var features = feature.get('features');
    var size = features.length;
    if (size == 1 && map.getView().getZoom() > 13) {
         if (features[0].get('free_op')) { return freeStyle; }  
         else { return busyStyle; }  
    } else { }