GeoJSONですが、仕様と要件の性質上ある意味あたりまえだと思いますが、頂点をよろしく曲線で結ぶ仕様はないようです*1。
でも、下記図みたいな、こんな感じのことをしたいこともあるよね?ということで調べてみて、d3.jsで試してみましたの例です。
あたかも独自のテクニックで、d3.jsを拡張したりしたかのような言い回しですが、実際は、以下のブログを参考にさせていただきました。
また、折れ線の曲線化にあたり、補間曲線のバリエーション例が豊富な次のブログを参考にさせていただきました。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="aichi.js"></script> </head> <body> <script> //外部からデータ読み込み const geojson = pref const width = 800, height = 800 //svg初期化など const svg = d3.select("body").append("svg").attr("width", width).attr("height", height) //GeoJSONデータの頂点を滑らかな曲線で結ぶようなpathを生成する関数 ※GeoJSONのデータの入り方は分岐のない一筆書きの形式を前提にしている。万能ではない。 const namerakaHenkan = (d) => { //https://shimz.me/blog/google-map-api/4618 さんのアイディアを参考にした console.log(d) //メルカトル図法でのgeoPathパスジェネレーター作成 const scale = 16000 const center = [137.341, 34.647] const proj = d3.geoMercator() .center(center) .translate([width / 2, height / 2]) .scale(scale) const path = d3.geoPath().projection(proj) // GeoJSONデータから、それに対応したSVGのpathオブジェクトを生成〜座標の配列を取り出す const geopath = path(d) console.log(geopath) /* M400,400L325.4395343547949,394.90783940438087L333.2586094037324,405.09123940300924L348.3382541409592,397.6237730675293L370.9577212468066,384.381118750538L379.056048976061,379.2861289060111L388.5506401069142,384.381118750538L392.7394303116962,386.0792434899704L391.0639142297805, ...L439.65388060530677,391.1730024366243Z のようなデータになっている。 */ const points = geopath.replace(/M|Z/, "").split("L").map((d) => d.split(",")) // SVGのpath命令となっている文字列から「点」の座標に該当する部分を抜き出す console.log(points) /* [ ["400", "400"], ["325.4395343547949", "394.90783940438087"], ["333.2586094037324", "405.09123940300924"], ... ] のように変換 */ // 折れ線情報(points)を表すx,y座標の配列を引数にとる、d3.line().curve()を使って、なめらかな曲線のSVGのpathを生成する let cuv = null cuv = d3.curveBasisClosed // 以下バリエーション //cuv = d3.curveCardinalClosed.tension(0.9) //cuv = d3.curveCatmullRom.alpha(0.9) //cuv = d3.curveCardinal.tension(0.9) //cuv = d3.curveNatural //cuv = d3.curveBasis const interpolate = d3.line().x((d) => parseFloat(d[0])).y((d) => parseFloat(d[1])).curve(cuv) const namerakaPath = interpolate(points) console.log(namerakaPath) /* → */ return namerakaPath } const map = svg.append("g").selectAll("path") .data(geojson.features) .enter() .append("path") .attr('d', (d) => namerakaHenkan(d)) // なめらか変換のpath .style("stroke", "gray") .style("fill", "yellow") // おまけのZoom & Drug移動機能 const zoomeffect = () => { let t = d3.event.transform map .attr('transform', t) .attr('stroke-width', 1 / t.k) } svg. call(d3.zoom().on('zoom', zoomeffect)) </script> </body> </html>
◆インプットにしたGeoJSONデータのファイル(aichi.js)
なんちゃって愛知県シェープです。 これを冒頭の図に示したように、なめらか愛知県シェープに変換して表示することになります。
let pref = { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "MultiPolygon", "coordinates": [ [[ [137.341, 34.647], [137.074, 34.662], [137.102, 34.632], [137.156, 34.654], [137.237, 34.693], [137.266, 34.708], [137.300, 34.693], [137.315, 34.688], [137.309, 34.700], [137.351, 34.727], [137.311, 34.803], [137.250, 34.805], [137.214, 34.815], [137.186, 34.792], [137.168, 34.787], [137.105, 34.791], [136.996, 34.816], [136.955, 34.854], [136.976, 34.893], [136.971, 34.908], [136.934, 34.874], [136.936, 34.854], [136.921, 34.828], [136.969, 34.725], [136.976, 34.701], [136.851, 34.748], [136.837, 34.875], [136.828, 34.961], [136.869, 35.008], [136.873, 35.071], [136.884, 35.088], [136.857, 35.059], [136.843, 35.041], [136.849, 35.077], [136.838, 35.030], [136.809, 35.049], [136.780, 35.033], [136.769, 35.021], [136.677, 35.128], [136.677, 35.241], [136.864, 35.372], [136.991, 35.424], [137.047, 35.336], [137.067, 35.308], [137.102, 35.301], [137.185, 35.253], [137.345, 35.272], [137.408, 35.234], [137.520, 35.273], [137.570, 35.282], [137.576, 35.220], [137.655, 35.228], [137.759, 35.221], [137.823, 35.211], [137.823, 35.158], [137.802, 35.130], [137.778, 35.099], [137.704, 34.972], [137.639, 34.892], [137.549, 34.843], [137.496, 34.786], [137.483, 34.673], [137.340, 34.647] ]]] } }, ] }
以上です。
このテーマはもう少し頑張ってアドホックだけど上手い(おいしい)方法が編み出せたらと思っていますが、ひとまずここまで。
付録:その他
私の主観ベースですが、d3.jsの基礎的なところは次の記事にまとめてあります。 また、本項にある d3.line()のもっとシンプルな使い方の例も入っています。
*1:間違ってたらごめんなさい。