openstreetmap / openstreetmap-website

The Rails application that powers OpenStreetMap
https://www.openstreetmap.org/
GNU General Public License v2.0
2.2k stars 910 forks source link

Replace scale with zoom level in Export tab #368

Open Zverik opened 11 years ago

Zverik commented 11 years ago

Values like 1:25384 appearing in Export tab seem arbitrary and don't really tell user anything, since scale is hardly applicable to web maps. I propose to replace the scale with zoom level, defaulting to the level of the currently opened map. To allow more precise control it could allow floating-point values.

pnorman commented 11 years ago

I've built apps that call the mapnik API directly and I don't know how the scale is evaluated. It'd be nice to know what we're replacing.

Is it based on an OCG standard pixel and a scale to meter?

I don't really think zoom level is a great alternative, it's arbitrary and is just a detail of the behind the scenes method of transferring the map from servers to a client.

The best I can think of is meters:pixel

Zverik commented 11 years ago

The thing is, people who are unfamiliar with mapnik, or any other specialized GIS software, have little idea how this number will affect their output image. Zoom level, on the other hand, is what they work with: it is present in URLs, and sometimes in editing software (e.g. TileMill, Maperitive). Algorithms for converting scale to zoom level and vice-versa are widely published, even in our wiki. I'm not sure mapnik follows that formula, but I have no doubt it's not obsured and not at all complex.

pnorman commented 11 years ago

I think meters/pixel is more useful than zoom level. To do anything other than trial and error with zoom level is difficult, and we don't want something that requires digging in the wiki.

It is flat-out impossible to convert between zoom level and scale unless you assume a given pixel size. Zoom level gives you mercator meters per pixel, scale is mercator meters per cm on display/paper/etc.

Something that is non-ideal is that we're really controlling two independent settings with one here, one is the size of the map in pixels or the scale of the map, and the other is the rendering style chosen. If you're going to anything other than 90DPI screen, you want to adjust both because if your printer prints at 600dpi, you're faced with either unimaginably small road widths, text you need a magnifying glass to read and invisible POI icons, or pixelated output.


How about this for an idea? First, suppose the area you select is x by y pixels on your display.

Then ask for a zoom in the export pane, and generate an image of zoom * x by zoom * y. If someone wants a map twice as large as what they selected, they do a zoom of 2. Of course, as you zoom the map display in/out you'd want to adjust the zoom in the export pane.

Zverik commented 11 years ago

Zoom coefficient relative to the displayed bounding box size is an idea similar to one I proposed: instead of adding 1 to the zoom level, you specify coefficient of 2. The downside is, zoom level affects map detalization: features at zoom 13 significantly differ from zoom 12, for example. Such coefficient, as well as scale, obscures this, and I think detalization of the map is the major reason for a user to alter scale/zoom level/zoom coeff (the second one being getting as bigger image as possible).

Size of a pixel is hard-coded somewhere in mapnik style: I remember there are pre-calculated values, from which it is possible to derive a required equation. As of now, I think there are three different algorithms (with different coefficients, I presume) to calculate scale based on zoom level: in mapnik style, in leaflet scale bar, and in the export tab. If that doesn't confuse you, I think you are not in a target group for this issue :)

pnorman commented 11 years ago

Well yes, but that downside applies no matter what we call the current input, so it's not really relevant unless you also change the backend handling the export calls, and there are additional issues with that[1]

Our approaches are related, current_display_zoom_level * zoom = export_zoom_level.

The problem is that zoom level is meaningless to most people. It isn't relevant for most mapping, it isn't something that they'd have any experience elsewhere, and it's not even something most GIS people would know about.

Zoom is a concept they're more likely to be familiar with. They input a zoom of 2×, they get an image that is twice the size of what they have selected.

[1]: The osm.org stylesheet does not work with different sized pixels because the icons are PNGs and will either be shrunk or be pixelated and look bad. It is actually possible to get the effect of changing the size of a pixel by changing the scale parameter passed to mapnik.render, see https://github.com/pnorman/mapbook/blob/master/mapbook.py#L203.

Zverik commented 11 years ago

First: current scale field is counterintuitive, because it doesn't allow a user to predict what they would be getting. There is no option of "give me the exact same picture I see". Zoom coefficient (that you propose) or zoom level (that I propose) would fix that.

A scale, as in paper maps, is irrelevant in web mapping. Everyone has different monitors, and when it comes to printing, you can't really guess. So the scale number in the Export tab is just a number for a mapnik renderer, which affects a) size of an image a user would receive; b) map detalization. I'm not sure why those two are connected: image size has no meaning for vector exports (pdf and svg).

I have just made an image for myself using the Export tab. I've put some arbitrary number, and for map view of z15 got a small map image of zoom level around 13.5, judging by features present. There are almost no street names, and a railway station isn't labelled. If I wanted to have the same image I was seeing, but 4 times smaller, I'd be disappointed: it is not the same. So, not only image size was changed (which zoom coefficient you are proposing implies), but also a number of features present on a map extract.

Now, you assume zoom level is an unfamiliar concept for regular users. I agree: it is, as well as scale, and even zoom coefficient (why not enter target image size, and instead make a silly calculator: there is a size displayed near the field, so it's "enter 2 and see those numbers multiplied by 2"?). But in terms of control and predictability I am sure zoom level is the best we can do. Target image size is displayed: a user can tweak zoom level to get dimensions they need. We can emphasize the floating point by putting a default value with it: "15.0". Users are familiar with discrete zoom levels, since every popular web map has them. User do know that map presentation differs for different zoom levels, and they either would be happy with the picture they see (of a current zoom level), or would wish to specify the required detallization: e.g. when selecting an area that is larger than their screen size, or for printing with a high (or low) dpi.

The other way we could give a user such control, is to have two input fields: for zoom level (integer) and for dpi (disabled for vector output). But I doubt that would pass, because it complicates the form and is less understandable if the image is needed not for printing.

pnorman commented 11 years ago

So, not only image size was changed (which zoom coefficient you are proposing implies), but also a number of features present on a map extract.

Unfortunately this is going to always happen, I spent days trying to figure out how to best adjust these kind of options when writing mapbook. It also turns out it's flat out impossible with the current osm.xml style using images for some features.

I'll just quote @systemed on this

01:17 <RichardF> pnorman: Mapnik's scale logic is somewhere between weird and broken... presenting sane UI for that is always going to be very hard

I also think it doesn't matter for the immediate purposes of this pull. I think what we want to nail down first is presenting a UI for getting the number of pixels right. It may require that we also do stuff behind the scenes to make sure that the appropriate "zoom level rendering" is shown but this depends on some stylesheet stuff first.

How about this for a UI? Pardon the bad ascii-art

User selects an area and zooms in/out like now

    Options
------------------
Format [PNG]
Zoom  [A]X
<-----------|------>
  '  '  '  '  '  '
Image Size [C] X [D]
------------------
<Export>

The ' ' ' ' are ticks on the slider to give a guide to where .25x, .5x, 1x, 2x, 4x, etc are.

Not 100% sold on the slider, but presenting it anyways

The user adjusts A or the slider to change the zoom which live-updates values C and D. If they type in C or D then it live-updates A, the slider and the other size field.

When the press it generates an image, which uses approximately the same cartography of the zoom level they currently have displayed.

The last bit might need to wait and be implemented later, because doing that right likely involves changes to the backend that handles the export call.