0

I want to paint several clusters red, but when zoom the red flags disappear. I code on vue3 optionAPI.

script.js

import View from 'ol/View'
import Map from 'ol/Map'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'

import VectorLayer from 'ol/layer/Vector'
import Point from 'ol/geom/Point';
import LineString from 'ol/geom/LineString';
import VectorSource from 'ol/source/Vector';
import Feature from 'ol/Feature'
import {
    Circle as CircleStyle,
    Fill,
    Stroke,
    Style,
    Text,
} from 'ol/style';
import Overlay from 'ol/Overlay';
import Cluster from "ol/source/Cluster"

import { useGeographic } from 'ol/proj';
import 'ol/ol.css'
import './style.css'
import axios from 'axios'
export default {
    name: 'MapContainer',
    components: {},`your text`
    props: {},
    data() {
        return {
            place: [43.984506, 56.305298],
            data: [],
            featuresPoints: [],
            featuresLines: [],
        }
    },
    methods: {
        async getData() {
            axios("https://someRestApiLink.com").then(res => {
                this.data = res.data;

                this.createFeachers();
                this.renderMap();
            });
        },

        setCircleStyle(feature) {
            const size = feature.get('features').length;

            let style = styleCache[size];
            if (!style) {
                style = new Style({
                    image: new CircleStyle({
                        radius: 10,
                        stroke: new Stroke({
                            color: '#fff',
                        }),
                        fill: new Fill({
                            color: '#3399CC',
                        }),
                    }),
                    text: new Text({
                        text: size.toString(),
                        fill: new Fill({
                            color: '#fff',
                        }),
                    }),
                });
                styleCache[size] = style;
            }
            return style;
        },

        createFeachers() {
            for (let item of this.data) {
                let coords = JSON.parse(item.coords);
                if (coords.length === 1) {
                    let feature = new Feature(new Point(coords[0].reverse()));
                    feature.mydata = item;
                    this.featuresPoints.push(feature);
                } else {
                    let rightCoords = coords.map(el => el.reverse());
                    let isValidFeacture = true;
                    for (let i = 0; i < rightCoords.length - 1; i++) {
                        if (Math.abs(rightCoords[i][0] - rightCoords[i + 1][0]) > .01) {
                            isValidFeacture = false;
                            break
                        }
                    }
                    if (!isValidFeacture) continue;
                    let feature = new Feature({
                        geometry: new LineString(rightCoords)
                    });
                    feature.setStyle(new Style({
                        stroke: new Stroke({
                            color: '#0000ff',
                            width: 3
                        })
                    }))
                    feature.mydata = item
                    this.featuresLines.push(feature);
                }
            }
        },

        createMap() {
            return new Map({
                target: this.$refs['map-root'],
                view: new View({
                    zoom: 12,
                    center: this.place
                }),
                layers: [
                    new TileLayer({
                        source: new OSM()
                    }),

                    this.createLineLayer(),
                    this.createPointLayer(),
                ],
            });
        },

        createPointLayer() {
            const styleCache = {};
            let cluster = new Cluster({
                distance: 15,
                minDistance: 6,
                source: new VectorSource({
                    features: this.featuresPoints,
                })
            });
            
            const mainCluster = new VectorLayer({
                source: cluster,
                style: function (feature) {

                    function calculateFired(cluster, length) {
                        let pointList = cluster.values_.features;

                        let countFired = 0;
                        for (let point of pointList) {
                            if (point.mydata.status === "Просрочен") {
                                countFired++;
                            }
                        }

                        return countFired === length ? "full" : countFired > 0 ? "several" : "none";
                    }

                    const size = feature.get('features').length;
                    let style = styleCache[size];
                    if (!style) {
                        let hasFired = calculateFired(feature, size);

                        style = new Style({
                            image: new CircleStyle({
                                radius: 10,
                                stroke: new Stroke({
                                    color: hasFired === "none" ? '#fff' : "#f00",
                                    // color: '#fff',
                                }),
                                fill: new Fill({
                                    color: hasFired === "full" ? "#f00" : '#3399CC',
                                    // color: '#3399CC',
                                }),
                            }),
                            text: new Text({
                                text: size.toString(),
                                fill: new Fill({
                                    color: '#fff',
                                }),
                            }),
                        });
                        styleCache[size] = style;
                        // console.log(style);
                    }
                    return style;
                },
            });
            mainCluster.mydata = this.featuresPoints.map(el => el.mydata);


            return mainCluster
        },

        createLineLayer() {
            return new VectorLayer({
                source: new VectorSource({
                    features: this.featuresLines,
                }),
            })
        },

        renderMap() {
            useGeographic();

            const createPopUp = this.createPopUp;

            var container = document.getElementById("popup");
            var content = document.getElementById("popup-content");

            const map = this.createMap();

            const overlay = new Overlay({
                element: container,
                autoPan: true
            });
            map.on('click', function (e) {
                let pixel = map.getEventPixel(e.originalEvent);
                if (document.getElementsByClassName('popup-content').length != 0) {
                    document.getElementsByClassName('popup-content')[0].style.display = 'none'
                }
                map.forEachFeatureAtPixel(pixel, function (feature) {
                    let data = feature.mydata ?? feature.values_.features.map(el => el.mydata);
                    let coodinate = e.coordinate;
                
                    content.innerHTML = createPopUp(data);

                    overlay.setPosition(coodinate);
                    map.addOverlay(overlay);
                });
            });
        },
    
        createPopUp(data) {

            let content = "";
            if (data.length) {
                let sortedData = data.sort((a, b)=> {
                    if (a.time.split(".").reverse().join("-") > b.time.split(".").reverse().join("-")) return 1;
                    if (a.time.split(".").reverse().join("-") < b.time.split(".").reverse().join("-")) return -1;
                    return 0;
                });
                for (let el of sortedData) {
                    content += `
                        <div class="popup-content__valueBlock">
                            <div class="popup-content__valueBlock__organization">
                                ${el.organization}:
                            </div>
                            <div class="popup-content__valueBlock__aimOfWorks">
                                Тип: ${el.aim_of_works}
                            </div>
                            <div class="popup-content__valueBlock__stripSurface">
                                Работы ведутся над: ${el.strip_surface}
                            </div>
                            <div class="popup-content__valueBlock__status">
                                ${el.status} - ${el.finish_date}
                            </div>
                        </div>
                    `;
                }
            } else {
                content = `
                    <div class="popup-content__valueBlock">
                        <div class="popup-content__valueBlock__organization">
                            ${data.organization}:
                        </div>
                        <div class="popup-content__valueBlock__aimOfWorks">
                            Тип: ${data.aim_of_works}
                        </div>
                        <div class="popup-content__valueBlock__stripSurface">
                            Работы ведутся над: ${data.strip_surface}
                        </div>
                        <div class="popup-content__valueBlock__status">
                            ${data.status} - ${data.time}
                        </div>
                    </div>
                `;
            }

            return `
                <div class="popup-content">
                    <span class="close" onclick="closePopup()">x</span>
                    <span class="count">Количество выбранных ордеров: ${data.length ?? 1}</span>
                    ${content}
                </div>
            `;
        },
    },
    mounted() {
        this.getData();
    },
}

I checked ol_uid of cluster when I rezoomed, and I was so surprised by changed this property at the same cluster. Also I tried to rerender map at every time when I changed zoom, but this not work too.

I think that I mb do something wrong on creating or rendering map or clusters.

  • Clusters are created dynamically so any properties you set on them will be lost when they are recreated. Instead you must set properties on the features they represent e.g. click on a cluster in https://codesandbox.io/s/cluster-forked-ukrcjc?file=/main.js and the features will be updated so a future cluster will so if all, some or none of the features were updated. – Mike Jan 25 '23 at 10:51

1 Answers1

0

I just remove cache from render function of feature. Cache which I get from doc has cache on value of cluster feature, about this on rerender clusters styles was incorrect.