Based on this Martín González’s block, shows how to properly select the colours taking the neighbours in account as in this other block, which is based on this other one by Jason Davies!
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="spam.js"></script>
<script src="rbush.min.js"></script>
<script>
var width = 960,
height = 600
var i = 0
var color = d3.scale.category20()
var graticule = d3.geo.graticule()
// Canvas radial gradient
var x = width / 2,
y = height / 2,
// Radii of the start glow.
innerRadius = 220,
// Radii of the end glow.
outerRadius = 300,
// Radius of the entire circle.
radius = 200
d3.json("world-50m.json", function(error, d) {
topojson.presimplify(d)
var neighbors = topojson.neighbors(d.objects.countries.geometries)
var countries = topojson.feature(d, d.objects.countries)
countries.features.forEach(function(d, i) {
d.properties.color = d3.max(neighbors[i], function(n) { return countries.features[n].properties.color; }) + 1|0
});
var map = new StaticCanvasMap({
element: "body",
width: width,
height: height,
projection: d3.geo.orthographic()
.clipAngle(90)
.precision(0.1)
.scale(250),
data: [
{
features: countries,
static: {
prepaint: function(parameters) {
parameters.context.beginPath()
parameters.path({type: "Sphere"})
parameters.context.lineWidth = 2
parameters.context.strokeStyle = "rgb(198, 197, 197)"
parameters.context.stroke()
var gradient = parameters.context.createRadialGradient(x, y, innerRadius, x, y, outerRadius)
gradient.addColorStop(0, 'rgb(248, 248, 248)')
gradient.addColorStop(1, 'rgb(210, 210, 210)')
parameters.context.fillStyle = gradient
parameters.context.fill()
parameters.context.beginPath()
parameters.path(graticule())
parameters.context.lineWidth = 0.2
parameters.context.strokeStyle = 'rgba(30,30,30, 0.5)'
parameters.context.stroke()
},
paintfeature: function(parameters, d) {
parameters.context.lineWidth = 0.8 / parameters.scale
parameters.context.strokeStyle = "rgba(0,0,0, 0.6)"
parameters.context.stroke()
parameters.context.fillStyle = color(d.properties.color)
parameters.context.fill()
}
}
}
]
})
map.init()
})
</script>
(function(){"use strict";function rbush(maxEntries,format){if(!(this instanceof rbush))return new rbush(maxEntries,format);this._maxEntries=Math.max(4,maxEntries||9);this._minEntries=Math.max(2,Math.ceil(this._maxEntries*.4));if(format){this._initFormat(format)}this.clear()}rbush.prototype={all:function(){return this._all(this.data,[])},search:function(bbox){var node=this.data,result=[],toBBox=this.toBBox;if(!intersects(bbox,node.bbox))return result;var nodesToSearch=[],i,len,child,childBBox;while(node){for(i=0,len=node.children.length;i<len;i++){child=node.children[i];childBBox=node.leaf?toBBox(child):child.bbox;if(intersects(bbox,childBBox)){if(node.leaf)result.push(child);else if(contains(bbox,childBBox))this._all(child,result);else nodesToSearch.push(child)}}node=nodesToSearch.pop()}return result},collides:function(bbox){var node=this.data,toBBox=this.toBBox;if(!intersects(bbox,node.bbox))return false;var nodesToSearch=[],i,len,child,childBBox;while(node){for(i=0,len=node.children.length;i<len;i++){child=node.children[i];childBBox=node.leaf?toBBox(child):child.bbox;if(intersects(bbox,childBBox)){if(node.leaf||contains(bbox,childBBox))return true;nodesToSearch.push(child)}}node=nodesToSearch.pop()}return false},load:function(data){if(!(data&&data.length))return this;if(data.length<this._minEntries){for(var i=0,len=data.length;i<len;i++){this.insert(data[i])}return this}var node=this._build(data.slice(),0,data.length-1,0);if(!this.data.children.length){this.data=node}else if(this.data.height===node.height){this._splitRoot(this.data,node)}else{if(this.data.height<node.height){var tmpNode=this.data;this.data=node;node=tmpNode}this._insert(node,this.data.height-node.height-1,true)}return this},insert:function(item){if(item)this._insert(item,this.data.height-1);return this},clear:function(){this.data={children:[],height:1,bbox:empty(),leaf:true};return this},remove:function(item){if(!item)return this;var node=this.data,bbox=this.toBBox(item),path=[],indexes=[],i,parent,index,goingUp;while(node||path.length){if(!node){node=path.pop();parent=path[path.length-1];i=indexes.pop();goingUp=true}if(node.leaf){index=node.children.indexOf(item);if(index!==-1){node.children.splice(index,1);path.push(node);this._condense(path);return this}}if(!goingUp&&!node.leaf&&contains(node.bbox,bbox)){path.push(node);indexes.push(i);i=0;parent=node;node=node.children[0]}else if(parent){i++;node=parent.children[i];goingUp=false}else node=null}return this},toBBox:function(item){return item},compareMinX:function(a,b){return a[0]-b[0]},compareMinY:function(a,b){return a[1]-b[1]},toJSON:function(){return this.data},fromJSON:function(data){this.data=data;return this},_all:function(node,result){var nodesToSearch=[];while(node){if(node.leaf)result.push.apply(result,node.children);else nodesToSearch.push.apply(nodesToSearch,node.children);node=nodesToSearch.pop()}return result},_build:function(items,left,right,height){var N=right-left+1,M=this._maxEntries,node;if(N<=M){node={children:items.slice(left,right+1),height:1,bbox:null,leaf:true};calcBBox(node,this.toBBox);return node}if(!height){height=Math.ceil(Math.log(N)/Math.log(M));M=Math.ceil(N/Math.pow(M,height-1))}node={children:[],height:height,bbox:null,leaf:false};var N2=Math.ceil(N/M),N1=N2*Math.ceil(Math.sqrt(M)),i,j,right2,right3;multiSelect(items,left,right,N1,this.compareMinX);for(i=left;i<=right;i+=N1){right2=Math.min(i+N1-1,right);multiSelect(items,i,right2,N2,this.compareMinY);for(j=i;j<=right2;j+=N2){right3=Math.min(j+N2-1,right2);node.children.push(this._build(items,j,right3,height-1))}}calcBBox(node,this.toBBox);return node},_chooseSubtree:function(bbox,node,level,path){var i,len,child,targetNode,area,enlargement,minArea,minEnlargement;while(true){path.push(node);if(node.leaf||path.length-1===level)break;minArea=minEnlargement=Infinity;for(i=0,len=node.children.length;i<len;i++){child=node.children[i];area=bboxArea(child.bbox);enlargement=enlargedArea(bbox,child.bbox)-area;if(enlargement<minEnlargement){minEnlargement=enlargement;minArea=area<minArea?area:minArea;targetNode=child}else if(enlargement===minEnlargement){if(area<minArea){minArea=area;targetNode=child}}}node=targetNode}return node},_insert:function(item,level,isNode){var toBBox=this.toBBox,bbox=isNode?item.bbox:toBBox(item),insertPath=[];var node=this._chooseSubtree(bbox,this.data,level,insertPath);node.children.push(item);extend(node.bbox,bbox);while(level>=0){if(insertPath[level].children.length>this._maxEntries){this._split(insertPath,level);level--}else break}this._adjustParentBBoxes(bbox,insertPath,level)},_split:function(insertPath,level){var node=insertPath[level],M=node.children.length,m=this._minEntries;this._chooseSplitAxis(node,m,M);var splitIndex=this._chooseSplitIndex(node,m,M);var newNode={children:node.children.splice(splitIndex,node.children.length-splitIndex),height:node.height,bbox:null,leaf:false};if(node.leaf)newNode.leaf=true;calcBBox(node,this.toBBox);calcBBox(newNode,this.toBBox);if(level)insertPath[level-1].children.push(newNode);else this._splitRoot(node,newNode)},_splitRoot:function(node,newNode){this.data={children:[node,newNode],height:node.height+1,bbox:null,leaf:false};calcBBox(this.data,this.toBBox)},_chooseSplitIndex:function(node,m,M){var i,bbox1,bbox2,overlap,area,minOverlap,minArea,index;minOverlap=minArea=Infinity;for(i=m;i<=M-m;i++){bbox1=distBBox(node,0,i,this.toBBox);bbox2=distBBox(node,i,M,this.toBBox);overlap=intersectionArea(bbox1,bbox2);area=bboxArea(bbox1)+bboxArea(bbox2);if(overlap<minOverlap){minOverlap=overlap;index=i;minArea=area<minArea?area:minArea}else if(overlap===minOverlap){if(area<minArea){minArea=area;index=i}}}return index},_chooseSplitAxis:function(node,m,M){var compareMinX=node.leaf?this.compareMinX:compareNodeMinX,compareMinY=node.leaf?this.compareMinY:compareNodeMinY,xMargin=this._allDistMargin(node,m,M,compareMinX),yMargin=this._allDistMargin(node,m,M,compareMinY);if(xMargin<yMargin)node.children.sort(compareMinX)},_allDistMargin:function(node,m,M,compare){node.children.sort(compare);var toBBox=this.toBBox,leftBBox=distBBox(node,0,m,toBBox),rightBBox=distBBox(node,M-m,M,toBBox),margin=bboxMargin(leftBBox)+bboxMargin(rightBBox),i,child;for(i=m;i<M-m;i++){child=node.children[i];extend(leftBBox,node.leaf?toBBox(child):child.bbox);margin+=bboxMargin(leftBBox)}for(i=M-m-1;i>=m;i--){child=node.children[i];extend(rightBBox,node.leaf?toBBox(child):child.bbox);margin+=bboxMargin(rightBBox)}return margin},_adjustParentBBoxes:function(bbox,path,level){for(var i=level;i>=0;i--){extend(path[i].bbox,bbox)}},_condense:function(path){for(var i=path.length-1,siblings;i>=0;i--){if(path[i].children.length===0){if(i>0){siblings=path[i-1].children;siblings.splice(siblings.indexOf(path[i]),1)}else this.clear()}else calcBBox(path[i],this.toBBox)}},_initFormat:function(format){var compareArr=["return a"," - b",";"];this.compareMinX=new Function("a","b",compareArr.join(format[0]));this.compareMinY=new Function("a","b",compareArr.join(format[1]));this.toBBox=new Function("a","return [a"+format.join(", a")+"];")}};function calcBBox(node,toBBox){node.bbox=distBBox(node,0,node.children.length,toBBox)}function distBBox(node,k,p,toBBox){var bbox=empty();for(var i=k,child;i<p;i++){child=node.children[i];extend(bbox,node.leaf?toBBox(child):child.bbox)}return bbox}function empty(){return[Infinity,Infinity,-Infinity,-Infinity]}function extend(a,b){a[0]=Math.min(a[0],b[0]);a[1]=Math.min(a[1],b[1]);a[2]=Math.max(a[2],b[2]);a[3]=Math.max(a[3],b[3]);return a}function compareNodeMinX(a,b){return a.bbox[0]-b.bbox[0]}function compareNodeMinY(a,b){return a.bbox[1]-b.bbox[1]}function bboxArea(a){return(a[2]-a[0])*(a[3]-a[1])}function bboxMargin(a){return a[2]-a[0]+(a[3]-a[1])}function enlargedArea(a,b){return(Math.max(b[2],a[2])-Math.min(b[0],a[0]))*(Math.max(b[3],a[3])-Math.min(b[1],a[1]))}function intersectionArea(a,b){var minX=Math.max(a[0],b[0]),minY=Math.max(a[1],b[1]),maxX=Math.min(a[2],b[2]),maxY=Math.min(a[3],b[3]);return Math.max(0,maxX-minX)*Math.max(0,maxY-minY)}function contains(a,b){return a[0]<=b[0]&&a[1]<=b[1]&&b[2]<=a[2]&&b[3]<=a[3]}function intersects(a,b){return b[0]<=a[2]&&b[1]<=a[3]&&b[2]>=a[0]&&b[3]>=a[1]}function multiSelect(arr,left,right,n,compare){var stack=[left,right],mid;while(stack.length){right=stack.pop();left=stack.pop();if(right-left<=n)continue;mid=left+Math.ceil((right-left)/n/2)*n;select(arr,left,right,mid,compare);stack.push(left,mid,mid,right)}}function select(arr,left,right,k,compare){var n,i,z,s,sd,newLeft,newRight,t,j;while(right>left){if(right-left>600){n=right-left+1;i=k-left+1;z=Math.log(n);s=.5*Math.exp(2*z/3);sd=.5*Math.sqrt(z*s*(n-s)/n)*(i-n/2<0?-1:1);newLeft=Math.max(left,Math.floor(k-i*s/n+sd));newRight=Math.min(right,Math.floor(k+(n-i)*s/n+sd));select(arr,newLeft,newRight,k,compare)}t=arr[k];i=left;j=right;swap(arr,left,k);if(compare(arr[right],t)>0)swap(arr,left,right);while(i<j){swap(arr,i,j);i++;j--;while(compare(arr[i],t)<0)i++;while(compare(arr[j],t)>0)j--}if(compare(arr[left],t)===0)swap(arr,left,j);else{j++;swap(arr,j,right)}if(j<=k)left=j+1;if(k<=j)right=j-1}}function swap(arr,i,j){var tmp=arr[i];arr[i]=arr[j];arr[j]=tmp}if(typeof define==="function"&&define.amd)define("rbush",function(){return rbush});else if(typeof module!=="undefined")module.exports=rbush;else if(typeof self!=="undefined")self.rbush=rbush;else window.rbush=rbush})();