Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Анимированный кластер #201

Open
yadik64 opened this issue Oct 5, 2023 · 8 comments
Open

Анимированный кластер #201

yadik64 opened this issue Oct 5, 2023 · 8 comments

Comments

@yadik64
Copy link

yadik64 commented Oct 5, 2023

Добрый день.

Кластер состоит из объектов людей на карте у каждого объекта есть личная фотография.
Когда эти объекты собираются в кластер, изображение кластера должно меняться раз в секунду на фотографию входящего в него объекта. И так по кругу.

Просмотрел документацию и тестовый проект, но не нашел способа реализовать подобное.
Буду очень благодарен за ответ.

@maxal9999
Copy link
Contributor

Добрый день.
https://docs.2gis.com/ru/ios/sdk/reference/7.3/SimpleClusterObject#nav-lvl1--var%20objects
У SimpleClusterObject есть проперти objects со списком входящих в кластер объектов.
SimpleMapObject можно скастить к Marker
https://docs.2gis.com/ru/ios/sdk/reference/7.3/Marker
и получить иконку icon.
У сформированного кластера иконку можно менять через
https://docs.2gis.com/ru/ios/sdk/reference/7.3/SimpleClusterObject#nav-lvl1--var%20setIcon

То есть таким образом, в SimpleClusterRendererImpl при формировании кластера можно запустить таску на обновление иконки.

Самое интересное - как идентифицировать кластер после его формирования. Нужно в userData установить какой то идентификатор, который нужно сохранить.
https://github.com/2gis/mobile-sdk-ios-demo/blob/master/app/Views/DemoPages/Clustering/ClusteringDemoViewModel.swift#L32
Также нужно сохранить позицию камеры, при которой был сформирован кластер.
https://docs.2gis.com/ru/ios/sdk/reference/7.3/BaseCamera#nav-lvl1--var%20position

Ну а далее, в таске по обновлению иконки, первый раз находим кластер в MapObjectManager для сохранения ссылки на него. Для этого вызываем
https://docs.2gis.com/ru/ios/sdk/reference/7.3/MapObjectManager#nav-lvl1--clusteringObjects
Обходим все объекты, сравниваем userData с необходимым нам идентификатором, находим нужный и все. Находить нужно только 1 раз, если в MapObjectManager не изменяется.

@yadik64
Copy link
Author

yadik64 commented Oct 8, 2023

Добрый день. https://docs.2gis.com/ru/ios/sdk/reference/7.3/SimpleClusterObject#nav-lvl1--var%20objects У SimpleClusterObject есть проперти objects со списком входящих в кластер объектов. SimpleMapObject можно скастить к Marker https://docs.2gis.com/ru/ios/sdk/reference/7.3/Marker и получить иконку icon. У сформированного кластера иконку можно менять через https://docs.2gis.com/ru/ios/sdk/reference/7.3/SimpleClusterObject#nav-lvl1--var%20setIcon

То есть таким образом, в SimpleClusterRendererImpl при формировании кластера можно запустить таску на обновление иконки.

Самое интересное - как идентифицировать кластер после его формирования. Нужно в userData установить какой то идентификатор, который нужно сохранить. https://github.com/2gis/mobile-sdk-ios-demo/blob/master/app/Views/DemoPages/Clustering/ClusteringDemoViewModel.swift#L32 Также нужно сохранить позицию камеры, при которой был сформирован кластер. https://docs.2gis.com/ru/ios/sdk/reference/7.3/BaseCamera#nav-lvl1--var%20position

Ну а далее, в таске по обновлению иконки, первый раз находим кластер в MapObjectManager для сохранения ссылки на него. Для этого вызываем https://docs.2gis.com/ru/ios/sdk/reference/7.3/MapObjectManager#nav-lvl1--clusteringObjects Обходим все объекты, сравниваем userData с необходимым нам идентификатором, находим нужный и все. Находить нужно только 1 раз, если в MapObjectManager не изменяется.

Спасибо за ответ. Я обязательно это попробую. Но у меня есть еще одна проблема с методом renderCluster. Как я заметил он работает не на главном потоке, что приводит к сбою мой механизм формирования иконки для класетра. Сам кластер это SwiftUI.View я передаю в него изображение маркера и кол-во элементов кластера, после чего вызываю метод snapshot() для получения UIImage на основе View. Метод snapshot() может работать только на главном потоке. Так же я заметил что если вернуть SimpleClusterOptions(icon: nil) то маркеры не отображаются на карте даже когда они не в кластере.

@MainActor
    func renderCluster(cluster: SimpleClusterObject) -> SimpleClusterOptions {
        if let annotation = cluster.objects.first?.userData as? ChildAnnotation {
            
            let uiImage = YClusterAnnotationView(image: annotation.image,
                                                 count: Int(cluster.objectCount))
                .snapshot()
            
            var icon = self.imageFactory.make(image: uiImage)
            
            return SimpleClusterOptions(
                icon: icon,
                iconMapDirection: nil,
                text: nil,
                textStyle: nil,
                iconWidth: LogicalPixel(30.0),
                userData: "",
                zIndex: ZIndex(value: 6)
            )
        }
        
        return SimpleClusterOptions(icon: nil)
    }

Есть ли возможность вызвать renderCluster на главном потоке?

@maxal9999
Copy link
Contributor

Есть ли возможность вызвать renderCluster на главном потоке?

Нет, такой возможности нет. Как вариант, можно кластеру проставить временно заглушку, отправить задачу на главный поток, и установить иконку уже потом.

@yadik64
Copy link
Author

yadik64 commented Oct 11, 2023

Есть ли возможность вызвать renderCluster на главном потоке?

Нет, такой возможности нет. Как вариант, можно кластеру проставить временно заглушку, отправить задачу на главный поток, и установить иконку уже потом.

Если формирование кластера идет не на главном потоке есть хотя бы какой то callback сообщающий о том что кластер сформирован и можно его изменить?

@maxal9999
Copy link
Contributor

Например, можно заложиться на
https://docs.2gis.com/ru/ios/sdk/reference/7.3/Map#nav-lvl1--var%20dataLoadingStateChannel
То есть во время создания кластера он будет создаст, когда закончатся любые загрузки карты.

@maxal9999
Copy link
Contributor

Версия 7.4.0 опубликована. Теперь все ок?

@yadik64
Copy link
Author

yadik64 commented Nov 17, 2023

RPReplay_Final1700210160.mp4

Версия 7.4.0 опубликована. Теперь все ок?

Да, смена иконки работает. Спасибо. Но проблему с анимацией кластера до конца решить не удалось.
При смене зума у вас почему то создается еще один кластер, хотя это тот же самый кластер только с другим зумом. И это приводит к проблемам. Например если выбрать кластер и поменять ему иконку, а потом поменять зум иконка вернется в состояние "не выбран", вернем зум назад и кластер сново с иконкой в состоянии "выбран". Это все можно видеть в вашем тестовом проекте.
Формирование кластера не на главном потоке, отсутствие кэлбэков, разные экземпляры одного и того же кластера с разным зумированием делает их практически невозможными для кастомизации.
Хотелось бы видеть работу с кластерами пусть не такую как в MapKit, но хотябы как в YandexMapsMobile

@maxal9999
Copy link
Contributor

У нас кластеризация быстрее работает, чем у Яндекса или Гугла, за счет как раз выстраивания дерева кластеризация сразу же после добавления объектов.
ЧТо касается того, что на новом зум уровне это другой кластер - это правильно, так как новый кластер на другом зум уровне формируется как суперпозиция всех кластеров на уровень ниже.

Формирование кластера не на главном потоке, отсутствие кэлбэков, разные экземпляры одного и того же кластера с разным зумированием делает их практически невозможными для кастомизации.

Это очень спорный месс, так как:

  1. Не на главном потоке - мы никак не вешаем UI.
  2. Разные экземпляры - я объяснил выше почему так. Но на каждое формирование на каждом зуме все равно вызывается функция по формированию кластера.
  3. Отсутствие колбэков - вот тут можно подумать.

Мы готовы доработать еще кластеризацию, даже в 7 версию. Но нужен список требований того, что сейчас не хватает. Добавление колбэка о том, что кластер сформирован - этого достаточно?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants