The project uses a Yandex map with many of its own tag icons. These icons are created as html markup and, depending on a number of conditions, a modifier is added to the markup (as an additional class to the html element), which slightly changes the appearance of the icon.

All parameters are written to properties and then get from there to the build function of the icon template. I like this approach with modifiers very much, because it allows you to restrict yourself to just two templates, and not a few dozen, and minimizes duplication of code.

This is how it looks like:

let placemark = factory.createClass(` <div class="map-placemark-container"> <div class="map-placemark-small" data-placemark-id="$[properties.objectId]"> <i class="icon-small icon-categories icon-categories-$[properties.categoryId]"></i> </div> </div> `, { build: function() { placemark.superclass.build.call(this); let properties = this.getData().properties, element = this.getElement().querySelector('.map-placemark-small'); if(properties.get('categoryColor')) { element.style.backgroundColor = `#${properties.get('categoryColor')}`; } if(properties.get('objectStatus')) { let status = properties.get('objectStatus'); element.classList .add('map-placemark-small_status', `map-placemark-small_status-${status}`); } 

And stuff like that. I would like to add another modifier that will be assigned to the objects that the mouse cursor is over (and get out when the mouse leaves the object). I have already written a mouseenter event handler, and the class is assigned to the object, but the icon itself is not redrawn.

Therefore, there are several questions:

  1. Is it possible to change the icon when you hover in the current decision? For example, to initiate the redrawing of the icon with the new properties inside the mouseenter? If not, how is it more intelligent to implement a change of icon when hovering? Add a selected icon to a special collection? Create a new template specifically for these elements and assign it to iconLayout when you hover?
  2. What is the most correct approach to the design of many diverse icons in terms of the architecture of maps?

Thank!

UPD: here is an example of how to solve the problem described. The presented code is simply monstrous (besides, I had to duplicate the entire layout of the icon in the new my # hovered-template layout, so it is doubly monstrous), I am sure that this can be done in a more elegant way. The code below is a handler function that artificially causes a redrawing of a layout for an icon when the mouse is hovering over it and restoring the previous layout and active area of ​​the icon when the mouse leaves the object.

  placemark.events.add('mouseenter', (e) => { let placemark = e.get('target'); placemark.properties.set('isHovered', true); placemark.properties.set('lastShape', placemark.options.get('iconShape')); placemark.properties.set('lastTemplate', placemark.options.get('iconLayout')); placemark.options.set('iconLayout', 'my#hovered-placemark'); placemark.options.set('iconShape', { type: 'Rectangle', coordinates: [[-25, -25], [25, 25]] }); }); placemark.events.add('mouseleave', (e) => { let placemark = e.get('target'); placemark.options.set('iconLayout', placemark.properties.get('lastTemplate')); placemark.options.set('iconShape', placemark.properties.get('lastShape')); placemark.properties.unset(['lastShape', 'lastTemplate', 'isHovered']); }); 
  • In short: when I hover over an object, I need to set a property and call the function of drawing the icon layout (build). So far, we have managed to achieve this in two ways: 1) when hovering over the label, remove it from the map and re-add it to the map 2) re-assign the iconLayout option when hovering over the label. Since the templates are set in lines and cached, I had to create a complete copy of the icon layout. Both ways are monstrous. - Tilonorrinco

2 answers 2

http://jsfiddle.net/3y64qo87/18/

Everything is much simpler: put dynamic content in options. If you change the label options present in the template, it will be redrawn.

 placemark.options.set('iconMoreClassesForGodClasses', 'bar') 
  • Thank! From the very beginning I tried to do exactly that, but it did not work, due to the fact that the name of the custom option did not begin with the icon. Managed to cut the code somewhere in half! - Tilonorrinco

The problem is solved, in the least crutch way in the framework of the technical solution described in the problem.

How did I solve the problem?

Very simple, through working with a sample of geoQuery. The solution looks like this:

 //функция-обработчик наведения на иконку //все объекты карты хранятся в коллекции selectedObjectCollection setObjectHovered(id) { let hovered = ymaps.geoQuery(this.hoveredObjectCollection), all = ymaps.geoQuery(this.selectedObjectCollection), active = all.search(`properties.objectId = ${id}`) .search('geometry.type = "Point"'); //сбрасываем модификатор у прошлого выделенного элемента hovered.unsetProperties('isHovered'); hovered.addTo(this.selectedObjectCollection); if(active.getLength()) { active.setProperties('isHovered', true); active.addTo(this.hoveredObjectCollection); } } 

Now I plan to rewrite this solution a bit, abandoning a separate collection for selected objects and limiting it only to geo-queries.

The problem is solved, but if someone has thoughts on an even more elegant solution of the problem, I will be grateful for the answers.