Programmatic select cluster

by Vladimir Vershinin

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol.js"></script>
<script src="https://unpkg.com/[email protected]/lib/index.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/lib/style.css">
<div id="app">
  <button @click="getFeatures">
    Load
  </button>
  <button v-for="(f, idx) in features" :key="idx" @click="selectFeature(f)">{{idx}} {{ f.getId() }}</button>

  <vl-map ref="map" data-projection="EPSG:4326">
    <vl-view ref="mapView" :zoom.sync="zoom" :center.sync="center"></vl-view>

    <vl-layer-tile>
      <vl-source-osm :crossOrigin="null" />
    </vl-layer-tile>

    <vl-interaction-select ref="select">
      <vl-style-func :factory="styleFunc"></vl-style-func>
    </vl-interaction-select>

    <vl-layer-vector id="features" render-mode="image" @mounted="getFeatures">
      <vl-source-cluster :features.sync="clusterFeatures" :distance="50">
        <vl-source-vector ref="featuresSource"></vl-source-vector>
      </vl-source-cluster>
      
      <vl-style-func :factory="vectorStyleFunc"></vl-style-func>
    </vl-layer-vector>
  </vl-map>
</div>

CSS

html,
body,
#app {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

JavaScript

new Vue({
  el: '#app',
  data() {
    return {
      zoom: 2,
      center: [0, 0],
      features: [],
      clusterFeatures: [],
    }
  },
  computed: {
    places() {
      return _.range(0, 2).map(i => {
        let geom = [_.random(-50, 50), _.random(-50, 50)];
        return {
          id: "random-" + i,
          geom
        };
      });
    },
  },
  methods: {
    selectFeature(feature) {
      const selectinteraction = this.$refs.select;

			const cluster = this.clusterFeatures.find(cluster => {
        return cluster.properties.features.find(f => f.id === feature.getId())
      })

      selectinteraction.unselectAll();
      selectinteraction.select(cluster);
      
      //selectinteraction.$interaction.getFeatures().push(feature) // SAME RESULT
      
      /* selectinteraction.$interaction.dispatchEvent({
        type: 'select',
        selected: [featurePoly],
        deselected: []
      }); */ // SAME RESULT
    },
    styleFunc() {
      return (feature, res) => {
        return [
          new ol.style.Style({
            image: new ol.style.Circle({
              radius: 10,
              fill: new ol.style.Fill({
                color: "green"
              }),
              stroke: new ol.style.Stroke({
                color: "blue",
                width: 5
              })
            })
          })
        ];
      };
    },

    getFeatures() {
      const sourceVm = this.$refs.featuresSource
      sourceVm.$source.clear()
      const features = this.places.map(i => {
        const featureId = i.id
        const geometry = new ol.geom.Point(i.geom)
        geometry.transform('EPSG:4326', 'EPSG:3857')

        const feature = new ol.Feature({
          id: featureId,
          geometry: geometry,
        })
        feature.setId(featureId)

        return feature
      })
      this.features = features;

      sourceVm.$source.addFeatures(features)
    },

    vectorStyleFunc() {
      return (feature, res) => {
        return [
   ...