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

Rotated icons are shifted in Leaflet 1.0 #8

Open
m314 opened this issue Oct 11, 2016 · 11 comments
Open

Rotated icons are shifted in Leaflet 1.0 #8

m314 opened this issue Oct 11, 2016 · 11 comments

Comments

@m314
Copy link

m314 commented Oct 11, 2016

When I loop through my markers (from a GeoJSON file) and apply marker.setRotationOrigin() and marker.setRotationAngle(), the transformations work correctly in with Leaflet 0.7.7, but not when I upgrade to Leaflet 1.0. The markers are shifted in Leaflet 1.0. Note that the shift is different if I do not set the rotation origin, but if I set the rotation origin, the (different) shift is the same no matter what I choose the origin to be.

Could this be related to this issue with shifted markers on Leaflet.PolylineDecorator?

@bbecquet
Copy link
Owner

bbecquet commented Nov 5, 2016

Hi, and sorry for taking so long.
Leaflet.RotatedMarker includes the fixes I did on the marker rotation code when it was a part of PolylineDecorator, so it may be related to the old issue but normally everything is here to fix it :)

Most of the time the issues of marker shifts are related to a rotationOrigin not set correctly, or to other CSS rules applied to your marker that conflict with the one this plugin uses.
If you still experience the problem, can you show some code and optionnally screenshot so I can have a look?

@m314
Copy link
Author

m314 commented Nov 7, 2016

Hi, thank you for getting back to me. Here's where I'm experiencing the problem. I'm loading markers from a GeoJSON and using a custom icon with an anchor that's set at the center of the icon. These markers are on top of a line, similarly to PolylineDecorator. When the markers are rotated, they should still be centered on the line.
Here's a JSFiddle with Leaflet 1.0.1 (left map--markers are shifted off of the line):
https://jsfiddle.net/qr9ntbo9/1/
and the same code with Leaflet 0.7.7 (right map--markers are still centered on the line):
https://jsfiddle.net/9z2u0apn/
markerrotated

I tried emulating your fix from Leaflet.PolylineDecorator, and it appears that adding the following lines of code to RotatedMarker fixes my issue. However, I'm not sure that I implemented it correctly.

_initIcon: function() {
            proto_initIcon.call(this);
            var TRANSFORM_ORIGIN=L.DomUtil.testProp(
                ['transformOrigin', 'WebkitTransformOrigin', 'OTransformOrigin', 'MozTransformOrigin', 'msTransformOrigin']);
            this._icon.style[TRANSFORM_ORIGIN] = '50% 50%';
        },

@bbecquet
Copy link
Owner

bbecquet commented Nov 7, 2016

Thanks for posting some code.

First, you don't need the fix from PolylineDecorator. The part about the transformOrigin rule test is already included in RotatedMarker. And the last line that actually fixes your bug is doing exactly what rotationOrigin does :)
But you need to specify it as a transform-origin CSS rule. So what you want is layer.setRotationOrigin('13px 13px');, instead of [13,13].

The reason I didn't use an array or a L.Point like iconAnchor is because it's actually a real CSS rule, which can accept other syntaxes and units. In your case, center center or 50% 50% would work the same. Maybe if I had set it as the default it would have been less confusing :/

@m314
Copy link
Author

m314 commented Nov 7, 2016

Yes, that absolutely fixes it---thank you very much!! And thank you for the quick response! :)

In case you are interested, I tracked down some other interesting behavior. I expected Leafelt.RotatedMarker to default to rotating about the custom anchor. As I was replicating this in a JSFiddle, I noticed that the plugin worked correctly without setRotationOrigin, as long as I wasn't loading from GeoJSON. When loading from GeoJSON, I set custom icons inside the onEachFeature loop, which means that the iconAnchor created with L.Marker.addInitHook() is unfortunately based on Leaflet's default icon (yielding this.options.rotationOrigin = '12px 41px'). This happens even when setIcon is called before setRotationAngle; I guess it must be because addInitHook is called earlier. Thus, using the default iconAnchor creates some strange behavior, because my icons are square (and also not the same size as Leaflet's default icon). This also explains why the plug-in wasn't reading the iconAnchor I had already set in my custom icon. Anyway, the setRotationOrigin method is exactly what's needed when I call it correctly. :)

I think that the default behavior bottom center probably makes sense for general cases. I see why setting the rotation origin with pixels makes sense to match the CSS rule, but I originally expected the syntax to match the iconAnchor syntax from Leaflet. Perhaps you could add an example syntax with pixels to the README? Something like: "If your marker icon has no tip, or you want to rotate around its center, use 'center center'. You can also rotate around a particular point with '10px 12px'."

Thank you for your help, and thank you for writing a very useful plug-in. :)

@Jmuccigr
Copy link

Jmuccigr commented Jan 2, 2017

I think I'm seeing this problem too. Here's my set up:

  • Loading points from geoJSON.
  • Setting an orientation for some points (selected via a filter).
  • Rotating the marker, which is an upward pointing arrow, right in the middle of a 256x256px square. So the arrow starts at the bottom center of the square and goes up to the top center of the square. I have the marker icon set at 12x12, but setting it a 256x256 makes no difference.
L.geoJson(temples, {
	onEachFeature: function (feature, layer) {
		layer.bindPopup(feature.properties.orientation)
		},
        pointToLayer: function (feature, latlng) {
        return L.marker(latlng, {icon: arrowIcon, rotationAngle: feature.properties.orientation, rotationOrigin: 'center, center'})
        },
        filter: function(feature, layer) {
		return (feature.properties.orientation != "");
		}
    }).addTo(orientations);

As you zoom in, you can see the markers move quite noticeably. Here's a screen shot where I'm zoomed out pretty far and the markers are all in the sea instead of on land:
moved

A few more images where I've superimposed a projection of the data as the traditional leaflet markers over one using my icons. The arrows get rotated and the circles do not (that is, the circles get placed without calling rotationAngle).

1.The first image is with the default setting, no rotationOrigin supplied. You can see from the box around the topmost arrow (which is rotated 90°) that it seems to be rotating about the bottom left point, not the bottom center. However the 180° arrow seems rotated about the center and then transposed down, so maybe that's what's happening in all the cases: the rotation is correct, but the icon gets shifted downwards by half of one of its dimensions.

none

So I made a long version of the arrow, which is taller than it is wide and redid it:

long

The arrows are now clearly translated further, so maybe it's the height that's getting involved here. The rotation is correct, but then a translation occurs.

Now if I use rotationOrigin and set that to "center, center":

center

Here the markers are all translated left. The 180° arrow also got translated up. If I count pixels, the 90° arrows shifted left 1.5x their height (or width) to the left, while the upward arrow moved left 1x its height and moved up .5x its height. So maybe there are two things going on there.

In any case, it doesn't seem to be doing what it should.

@ludik0
Copy link

ludik0 commented Jan 31, 2017

I am having the same problems like @Jmuccigr . Is there any progress ?

@ludik0
Copy link

ludik0 commented Jan 31, 2017

I believe I found my problem.

I tried to change the default origin from bottom center to center center, which did not apply because the icons had an anchor by default.

So removing the iconAnchor from the InitHook or setting the origin for each marker fixed my problem.

@Jmuccigr
Copy link

@ludik0, can you be more specific there? Did you make changes to the rotatedmarker code, or to how you called the script?

@ludik0
Copy link

ludik0 commented Jan 31, 2017

@Jmuccigr
I change something in the roatedmarker code.

in the inithook:
I changed :
this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom' ;
To:
this.options.rotationOrigin = this.options.rotationOrigin || 'center center' ;

Because in my case the marker seemed have an iconAnchor even if I never set one.
That iconAnchor was causing the shift.

I made the changes to the code because i wanted this to be the default behavior, but I could have called
marker.setRotationOrigin("center center")
on all of my markers to achieve the same.

@Jmuccigr
Copy link

Are you loading from geoJSON?

@Jmuccigr
Copy link

Solved my problem: I stupidly had a comma in the rotationOrigin, so rotationOrigin: 'center, center' instead of rotationOrigin: 'center center'.

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

4 participants