markmarkoh / datamaps

Customizable SVG map visualizations for the web in a single Javascript file using D3.js
http://datamaps.github.io
MIT License
3.78k stars 1.01k forks source link

Update on resize #12

Closed valloq closed 8 years ago

valloq commented 11 years ago

Any plans to allow the map to redraw automatically when the browser is resized?

markmarkoh commented 11 years ago

I didn't yet, but that's a good idea. I'll take a look to see what that entails, but feel free to implement it yourself and send a pull request!

ao commented 9 years ago

Any updates regarding this yet?

markmarkoh commented 9 years ago

What makes resizing difficult in DataMaps is that when you use plugins - like bubbles and arcs, you have to resize & reposition those as well.

I haven't come up with a clean solution that let's you resize everything in place without doing a clear and redraw at different size.

justmarkup commented 9 years ago

@markmarkoh What's the current status of responsive/resize - are you already working on that?

I played around with datamaps today and I have the following solution in mind to make it responsive/resizable.

First I set a data attribute (data-width) with the inital width to the svg element .attr('data-width', width || element.offsetWidth)''

Then onresize I get the new width (clientWidth) of the svg element, and set transform: scale( newsize/oldsize) to the graph () within the svg.

This works great so far (tested in Chrome and Firefox), example here: http://justmarkup.com/datamaps/

What do you think?

markmarkoh commented 9 years ago

I think that looks fantastic @justmarkup

Can you send a PR with your changes?

gabrielfagundez commented 9 years ago

This PR is great! @markmarkoh, do you know when this issue will be merged?

gabrielfagundez commented 9 years ago

@justmarkup I could finally apply your changes in my map, but I have a problem. Bubbles are not being properly located after a resize. Am I doing something wrong or this is not part of your commit? Thanks.

justmarkup commented 9 years ago

@gabrielfagundez just tested with bubbles and commited a potential fix for it https://github.com/justmarkup/datamaps/commit/bf6838cb897eb96716efaafb0bc64b570a6e93e6

Does this fix your problem?

gabrielfagundez commented 9 years ago

@justmarkup,

Sure! First of all, add this function in your script:

function exampleData(){
    return [
      { name: '1500 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'low', latitude: 39.0063135, longitude: -94.6243611 },
      { name: '5000 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'high', latitude: 42.3345364, longitude: -115.7274832 },
      { name: '2000 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'low', latitude: 27.5797542, longitude: -81.913157 },
      { name: '3000 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'medium', latitude: 39.5968159, longitude: -74.9709652 },
      { name: '1000 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'low', latitude: 24.8840622, longitude: -111.4532579 },
      { name: '4000 Messages', radius: 1 + Math.floor(Math.random() * 50), fillKey: 'medium', latitude: 33.874101, longitude: -84.45825 }
    ]
  }

Then, create a timeout, which adds the bubbles into the map. Given that your example has a global variable called map (with the datamap object), we can add this method into the script:

setTimeout(function() {
  map.bubbles(exampleData());
}, 1000);

This method will add new bubbles every 1 second. If you resize the map, new bubbles will be located in a wrong position.

Let me know if you need more details, or code.

Thanks.

gabrielfagundez commented 9 years ago

@justmarkup yes! Your fix works fine in my sample :). Bubbles are being updated properly.

justmarkup commented 9 years ago

@gabrielfagundez perfect, thanks! If you find any other issues please let us know.

maeishoj commented 9 years ago

Got it. It's awesome!

However why does that map zoom out insanely much when I zoom in if responsive is set to true?

maeishoj commented 9 years ago

On line 67 of datamaps: d3.select(this.options.element).style({'position': 'relative', 'padding-bottom': '60%'}); if I comment that out (or if i remove padding-bottom) solves my issue. Not sure why padding bottom is needed nor why it causes my map to shrink to 3px x 2px :/

maeishoj commented 9 years ago

@justmarkup I have a problem with the resize.

I am highlighting continents on hover. then when clicking on a continent i'm zooming into it's most-centered country. and everything works fine. When I do so, I have to open a sidebar from the left, which resized my main div where the map is to 66% (from 100% it was initially) (resize is not called automatically when this happens). So I thought to call map.resize() after I have my new width and height for my div (that contains the map).

This also works fine. However the map is now resized and not zoomed in any longer in my wished area. Even though the zoom in code is the same and I call that right after map.resize() this doesn't work anylonger... you can see it here: bacp-staging.azurewebsites.net

I would appreciate it anyone could help me out :/

justmarkup commented 9 years ago

@maeishoj

Hi, could you please provide a reduced test case, it's hard to debug your site as their is a lot of other logic involved and the sidebar currently goes crazy here in my Chrome/Firefox. You can also contact me via hallo@justmarkup and I am happy to help.

maeishoj commented 9 years ago

@justmarkup Hey there. Thanks for your assistance. I wrote you a mail.

However as I mentioned what happens is basically that as soon as i add: window.addEventListener('resize', function(event) { map.resize(); });

and I resize the map, the the zoom doesn't work anylonger, which I am not sure why.

My zooming is implemented as described here: (http://bl.ocks.org/mbostock/2206590) . Anyone has any idea of why this may be?

justmarkup commented 9 years ago

The problem was that you were zooming by setting transform via an attribute, if you use style instead everything works, see example: justmarkup.com/tests/datamap-zoom.html

Artenuvielle commented 9 years ago

The resize works like a charm but the borderwidth of the countries are not updated. If I initialize the map at a very big scale the borderwidth is something like 5px (haven't checked the exact value). Upon downscaling the map this does not change which causes a map with a width of 100px to be pretty much all black.

justmarkup commented 9 years ago

Hi @Artenuvielle

you are right, the borderwidth gets calculated wrong. I just pushed a potential fix for this in my repo: https://github.com/justmarkup/datamaps/commit/62388898fdf1608e407451e4f121eec86078d6f1 Can you please check if this also solves your issue.

For testing you could add this line of JavaScript to your site:

d3.select('.datamap').select('g').selectAll('path').style('vector-effect', 'non-scaling-stroke');
adrianbj commented 9 years ago

Not directly related to this issue, but like @Artenuvielle I had issues with the padding-bottom:60%. I changed it to 30% and everything looks great. Otherwise there was way too much padding, both top and bottom. The custom map in question is very "landscape" in it's dimensions: https://gist.github.com/adrianbj/ea7b8c60dea3bfb0a2a1

Seems like the padding-bottom approach is never going to work properly in all situations.

justmarkup commented 9 years ago

Well, padding-bottom: 60% (more accurately 56.25%) only works for maps with a ratio of 16:9

But as this is added via CSS anyway I don't see a problem here. You can always change that value of your map is not 16:9

adrianbj commented 9 years ago

@justmarkup - of course, and I did override the css to suit my map's dimensions, but I guess I was thinking there might be a more universal approach to using padding-bottom? If not, I think it would be useful to mention it in the docs in the responsive section.

adrianbj commented 9 years ago

Actually thinking through this a little more - the site I am working on is going to have many different maps, all with very different aspect ratios. The one codebase will need to control all these maps, so the padding-bottom will need to be added dynamically based on the dimensions of the map, so I am going to need to grab these dynamically and set then automatically set the padding-bottom based on the aspect ratio. Shouldn't be too difficult, but I am wondering if that calculation could be made in the core of datamaps instead of hard-coding the value?

justmarkup commented 9 years ago

@adrianbj Yes you are right, we should change this and add it to the core. I think I found a solution, can you please add this:

d3.select(this.options.element).style({'padding-bottom': ((parseInt(d3.select(this.options.element).select('svg').style('height')) / parseInt(d3.select(this.options.element).select('svg').style('width'))) * 100) + '%'});

after this line

d3.select(this.options.element).select('svg').style({'position': 'absolute', 'width': '100%', 'height': '100%'});

and check if this solves the issue for you?

adrianbj commented 9 years ago

Thanks for looking into this, but unfortunately that doesn't work. The values returned for width and height are completely affected by the initial padding-bottom value. I am actually at a bit of a loss on how to get dimensions of the svg.

I just played around with adding a new aspectRatio option that you can define in the map setup. So if you define it as 0.3, then I use that like this:

d3.select(this.options.element).style({'position': 'relative', 'padding-bottom': (this.options.aspectRatio*100) + '%'});

Not sure if you guys think this might be a reasonable approach to the problem. Obviously it would be better if it could be automatically calculated.

Obviously my changes to support this are very simple, but let me know if you'd like a PR.

justmarkup commented 9 years ago

Just tried other methods to get the correct height of the svg, but also without luck.

I like your solution @adrianbj , would be great if you could do a PR. As the default value, we should use 0.5625 (16:9) so sites relying on the current implementation won't break.

adrianbj commented 9 years ago

Done! https://github.com/markmarkoh/datamaps/pull/198

Please let me know if there is anything amiss with the PR - I didn't compile any files as documented, so hopefully it's all ok.

Downchuck commented 9 years ago

@adrianbj Looks like this issue could be closed. That said: using the custom USA map without height being set on the container seems to be buggy. The map has about 30% whitespace padding above it in those cases.. (container.style.width = '100%', no height set).

johhorn commented 9 years ago

@justmarkup I also have issues with zoom on responsive maps, but changing the .attr to .style as suggested previously (justmarkup.com/tests/datamap-zoom.html) does not seem to help. Any suggestions on how to make it work?

The example I have based my zoom on: http://jsbin.com/boribamugo/1/edit?html,output

dvolz commented 8 years ago

Does anyone know if this is supposed to work in Internet Explorer? I am not finding it working at all in IE 9-11.

ifedapoolarewaju commented 8 years ago

@dvolz a fix for this was merged recently https://github.com/markmarkoh/datamaps/pull/235 but I don't think it got released yet