OpenLayers – Add and Change Border Color of a Marker

markersopenlayersweb-mapping

I want to add a border color to the icons in OpenLayers. I also, want to be able to change the color of this border depending on the attribute of the marker. Is there any easy way to do this?
The code below allows you to click the icon and make a border color appear. However, I want the color to be their from the beginning and not depend on the clicks. Also, I want it to change depending on the variable. If anyone has any idea please let me know.

class MapComponent implements OnInit {

  map:Map;
  iconVectorSource: VectorSource;
  iconVectorLayer: VectorLayer;

  iconArr: Feature[] = [];

  constructor() { }

  ngOnInit() {

  this.map = new Map({
    target: 'map',
    view: new View({
      projection: 'EPSG:4326',  
      center: [114.190750, 22.339914],
      zoom: 12,
      minZoom: 12,
    }),

    layers:[
      new TileLayer({
        source: new OSM()
      }),
    ]
  });
  this.addIcons();
  this.addSelect();

  }
  public addIcons(){
    let icon1 = new Feature({
      geometry: new Point([114.190750, 22.339914]),
      imgSrc: 'assets/purple.png',
    });

    icon1.set('style',this.createStyle(icon1.get('imgSrc'), undefined));

    this.iconArr.push(icon1);
    this.iconVectorSource = new VectorSource({
      features: this.iconArr,
      wrapX: false,
    });
    //creates a layer and use the source in the layer
    this.iconVectorLayer = new VectorLayer({
      source: this.iconVectorSource,
      style: function(feature){
        return feature.get('style');
      },
    });
    this.map.addLayer(this.iconVectorLayer);

  }

  public addSelect(){
    var select = new Select({
      style: function(feature) {
        var image = feature.get('style').getImage().getImage();

          var canvas = document.createElement('canvas');
          var ctx = canvas.getContext('2d');
          var activeColor = "red"; //set border color
          var dArr = [-1,-1, 0,-1, 1,-1, -1,0, 1,0, -1,1, 0,1, 1,1], // offset array
              s = 2,  // thickness scale
              i = 0,  // iterator
              x = 2,  // final x position
              y = 2;  // final y position

          //set new canvas dimentions adjusted for border
          canvas.width = image.width + s + s;
          canvas.height = image.height + s + s;

          // draw images at offsets from the array scaled by s
          for(; i < dArr.length; i += 2)
          ctx.drawImage(image, x + dArr[i]*s, y + dArr[i+1]*s);

          // fill with color
          ctx.globalCompositeOperation = "source-in";
          ctx.fillStyle = activeColor;
          ctx.fillRect(0,0,canvas.width, canvas.height);

          // draw original image in normal mode
          ctx.globalCompositeOperation = "source-over";
          ctx.drawImage(image, x, y,image.width, image.height);

          //create new openlayers icon style from canvas
          return new Style({
              image: new Icon(/** @type {olx.style.IconOptions} */ ({
              crossOrigin: 'anonymous',
              src: undefined,
              img: canvas,
              imgSize: canvas ? [canvas.width, canvas.height] : undefined
            }))
          });

      }
    });
    this.map.addInteraction(select);
  }

  public createStyle(src, img) {
    return new Style({
      image: new Icon(/** @type {olx.style.IconOptions} */ ({
        crossOrigin: 'anonymous',
        src: src,
        img: img,
        imgSize: img ? [img.width, img.height] : undefined
      }))
    });
  }

}

Best Answer

If you are not changing style on clicks you wouldn't need a Select interaction. Move the activeColor definition outside the function (you will have some other code which changes it) then inside the layer style function check if the color has changed (the feature will need to store color as well as style) and change the style to match the new color if necessary.

class MapComponent implements OnInit {

  map:Map;
  iconVectorSource: VectorSource;
  iconVectorLayer: VectorLayer;
  activeColor: string;

  iconArr: Feature[] = [];

  constructor() { }

  ngOnInit() {

  this.map = new Map({
    target: 'map',
    view: new View({
      projection: 'EPSG:4326',  
      center: [114.190750, 22.339914],
      zoom: 12,
      minZoom: 12,
    }),

    layers:[
      new TileLayer({
        source: new OSM()
      }),
    ]
  });
  this.activeColor = 'red'; //set border color
  this.addIcons();

  }
  public addIcons(){
    let icon1 = new Feature({
      geometry: new Point([114.190750, 22.339914]),
      imgSrc: 'assets/purple.png',
    });

    icon1.set('style',this.createStyle(icon1.get('imgSrc'), undefined));

    this.iconArr.push(icon1);
    this.iconVectorSource = new VectorSource({
      features: this.iconArr,
      wrapX: false,
    });
    //creates a layer and use the source in the layer
    this.iconVectorLayer = new VectorLayer({
      source: this.iconVectorSource,
      style: function(feature) {
        if (feature.get('color') !== this.activeColor) {

          var image = feature.get('style').getImage().getImage();

          var canvas = document.createElement('canvas');
          var ctx = canvas.getContext('2d');
          var dArr = [-1,-1, 0,-1, 1,-1, -1,0, 1,0, -1,1, 0,1, 1,1], // offset array
              s = 2,  // thickness scale
              i = 0,  // iterator
              x = 2,  // final x position
              y = 2;  // final y position

          //set new canvas dimentions adjusted for border
          canvas.width = image.width + s + s;
          canvas.height = image.height + s + s;

          // draw images at offsets from the array scaled by s
          for(; i < dArr.length; i += 2)
          ctx.drawImage(image, x + dArr[i]*s, y + dArr[i+1]*s);

          // fill with color
          ctx.globalCompositeOperation = "source-in";
          ctx.fillStyle = this.activeColor;
          ctx.fillRect(0,0,canvas.width, canvas.height);

          // draw original image in normal mode
          ctx.globalCompositeOperation = "source-over";
          ctx.drawImage(image, x, y,image.width, image.height);

          //create new openlayers icon style from canvas
          var newStyle = new Style({
              image: new Icon(/** @type {olx.style.IconOptions} */ ({
              crossOrigin: 'anonymous',
              src: undefined,
              img: canvas,
              imgSize: canvas ? [canvas.width, canvas.height] : undefined
            }))
          });

          feature.set('style', newStyle);
          feature.set('color', this.activeColor);

        }
        return feature.get('style');
      },
    });
    this.map.addLayer(this.iconVectorLayer);
  }

  public createStyle(src, img) {
    return new Style({
      image: new Icon(/** @type {olx.style.IconOptions} */ ({
        crossOrigin: 'anonymous',
        src: src,
        img: img,
        imgSize: img ? [img.width, img.height] : undefined
      }))
    });
  }

}