dc-js / dc.leaflet.js

DC charts using Leaflet maps
Apache License 2.0
52 stars 24 forks source link

Colors mixin weird behaviour #19

Open ghost opened 8 years ago

ghost commented 8 years ago

If a featureOptions are defined via anonymous function for a choropleth map before defining colors and colorAccessor, you get unexpected behaviour. eg:

  var mapDimension = birds.dimension(function(i) { return i.island; });
  var mapGroup = mapDimension.group()
      .reduce(speciesDictAdd, speciesDictRemove, speciesDictInit);
  var mapColors = d3.scale.ordinal()
    .domain(d3.extent(mapGroup.all(), function(g) {
       return d3.keys(g.value).length;
    }))
    .range(['#fef0d9', '#fdd49e', '#fdbb84', '#fc8d59',
              '#ef6548', '#d7301f', '#990000']);
  mapChart
    .width($('#map .box-body').width())
    .height(500)
    .mapOptions({scrollWheelZoom: false})
    .center([51.86, -128.28])
    .zoom(10)
    .dimension(mapDimension)
    .group(mapGroup)
    .geojson(islandData)
    .featureKeyAccessor(function(d) { return d.properties.island;})
    .featureOptions(function(d) {
        console.log(mapColors.domain());  // <<<<<<<<<<<<<<< Domain is not consistent here
        var map = d3.map(mapGroup.top(Infinity), function(d) { return d.key; });
        var grp = map.get(d.properties.island);
        var species = grp ? d3.keys(grp.value).length : -1;
        return {
          stroke: species > 0,
          fillOpacity: 0.7,
          opacity: 0.7,
          color: grp ? mapColors(species) : null
        };
    })
    .colors(mapColors)
    .colorAccessor(function(d) { return d3.keys(d.value).length; })
    .renderPopup(false);

This is due to the color domain being redefined by the dc color mixin. The above code attempts to set the stroke of each polygon equal to the same color as the polygon fill. However, because The colorAccessor is trying to redefine the domain (which is already defined), the stroke colors end up being off.

To fix this, you can define the featureOptions function after colors, and everything works as expected.

gordonwoodhull commented 8 years ago

Yeah this is a common problem with dc.js and friends - it looks like a declarative syntax but often each method is modifying something imperatively. So the order matters when you think it wouldn't. Ideally there would be an internal model which gets realized on render / redraw all at once.

gordonwoodhull commented 8 years ago

Thanks for reporting this!