地理座標ポリゴン表示（＋正方グリッド）

こんにちは。
ポリゴンデータ（地表面の小地域）を、d3.js利用で正方グリッド（距離ベース）付きで表示してみました（手動で半透明地図に重ねています）。通常の経緯線の表示とは異なり、手間がかかりました。
<img width="498" alt="vatican.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/54617/3c3f7ea8-5526-840a-ca2c-2ba7d8f1eb8e.jpeg">

```vatican.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vatican</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
svg {font: 9px sans-serif;}
.grid .tick {stroke: #e4eded;}
.grid path {stroke-width: 0;}
.axis {shape-rendering: crispEdges;}
.axis line {fill: none; shape-rendering: crispEdges;}
.y.axis line, .y.axis path {fill: none; stroke: lightgrey;}
</style>
</head>
<body>
<div id="canvas"></div>
<script type="text/javascript">

d3.json("./data/vatican.json",
    function(geojson) {
    var geom=geojson["features"][0]["geometry"];
    var canvas={"area":[600, 360], "padding":30, "numTicks":10, "scale":0.26, "offset":80};  
    drawPoly(geom["coordinates"][0],canvas);
});

var RE = 6378137.0;
var FE = (1/298.257223563);
var E2 = FE * (2 - FE);
var E = Math.sqrt(E2);
var DEGREE = Math.PI/180;

function applyArr(func, arr) {
    return func.apply(null,arr);
}

function medArr(arr) {
    var x = minmaxArr(arr);
    return (x[0]+x[1])/2;
}

function minmaxArr(arr) {
    return [applyArr(Math.min,arr), applyArr(Math.max,arr)];
}

function mercatorProjectionEllipoidal(lonlat) {
  var lon=lonlat[0]*DEGREE, lat=lonlat[1]*DEGREE;
  var f=Math.pow((1-E*Math.sin(lat))/(1+E*Math.sin(lat)), E/2);
  return [RE*lon, RE*Math.log(f*Math.tan(lat/2+Math.PI/4))];
}

function scaleMercatorEllipoidal(lat) {
  lat*=DEGREE;
  return Math.sqrt(1-E2*Math.pow(Math.sin(lat),2))/Math.cos(lat);
}


function drawPoly(poly, canvas) {
    var scaleMercatorToCanvas = canvas["scale"]/scaleMercatorEllipoidal(medArr(poly.map(function(p){return p[1]})));

    poly = poly.map(function(lonlat) {return mercatorProjectionEllipoidal(lonlat);});
    var leftbottom = [0,1].map(function(i){return minmaxArr(poly.map(function(p){return p[i]-canvas["offset"]}))[0]});

    function mercatorToCanvas(p) {
        return [scaleMercatorToCanvas*(p[0]-leftbottom[0])+canvas["padding"], -scaleMercatorToCanvas*(p[1]-leftbottom[1])+canvas["area"][1]-canvas["padding"]];
    }

    var svg = d3.select("#canvas")
        .append("svg")
        .attr("width", canvas["area"][0])
        .attr("height", canvas["area"][1]);
    drawGridLines(svg, canvas);
    svg.append("polyline")
        .data([poly.map(mercatorToCanvas)])
        .attr("points",function(d) {return d.join(" ");})
        .attr("stroke", "#202020")
        .attr("fill", "#ffffff")
        .attr("stroke-width", 1.5)
        .attr("fill-opacity", 0);
};


function drawGridLines(svg, canvas) {
    var xScale = d3.scale.linear()
        .domain([0,canvas["area"][0]/canvas["scale"]])
        .range([canvas["padding"],canvas["area"][0]-canvas["padding"]*2]);
    var yScale = d3.scale.linear()
        .domain([0,canvas["area"][1]/canvas["scale"]])
        .range([canvas["area"][1]-canvas["padding"],canvas["padding"]]);
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient("bottom")
        .ticks(1)
        .tickSize(-canvas["area"][1], 0, 0);
    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient("left")
        .ticks(1)
        .tickSize(-canvas["area"][0], 0, 0);
    svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(0," + (canvas["area"][1] - canvas["padding"]) + ")")
        .call(xAxis);
    svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + canvas["padding"] + ",0)")
        .call(yAxis);
    var xAxisGrid = xAxis.ticks(canvas["numTicks"])
        .tickSize(-canvas["area"][1], 0)
        .tickFormat("")
        .orient("top");
    var yAxisGrid = yAxis.ticks(canvas["numTicks"])
        .tickSize(canvas["area"][0], 0)
        .tickFormat("")
        .orient("right");
    svg.append("g")
        .classed('x', true)
        .classed('grid', true)
        .call(xAxisGrid);
    svg.append("g")
        .classed('y', true)
        .classed('grid', true)
        .call(yAxisGrid);
}
</script>
</body>
</html>
```