地軸を傾けながらSVGで地球儀を表示する
以前、svgで地球儀を描き回転させるという記事を書きましたが、その記事についてお問い合わせいただき、メールにて返信したところmailer-daemonさんに「次の受信者への送達は、恒久的に失敗しました。メールアドレスが存在しません」と言われてしまって返信できなかったのでブログの記事として掲載しておきます。
地軸を傾けながら地球儀を表示する
右に23.4度傾けて表示しています。
グループ(g)要素のtransform属性でrotateを指定し全体を傾けています。
サンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
/*地図を表示するステージを追加*/ const stage = d3.select("svg"); const rotateStage = stage.append("g"); const seaLayer = rotateStage.append("g"); const landLayer = rotateStage.append("g"); const projection = d3.geoOrthographic() //投影法を指定 const path = d3.geoPath()//geometryをsvgのパスに変換する関数 d3.json("conuntries.topojson", function(json){ //地図情報の読み込み const data = topojson.feature(json, json.objects.conuntries).features; //topojson->geojson変換 /*プロジェクション設定*/ projection .rotate([0,0,0]) //x,y,z回転 .clipAngle(90); //表示する角度 180度を指定すると裏側の大陸まで表示される /*パスジェネレーターにプロジェクションを設定*/ path.projection(projection); /*海面を描画するためのパスをDOMに追加*/ seaLayer.append("path") .datum({type: "Sphere"}) .attr("fill", "blue") /*地図を表示するためのパスをDOMに追加*/ landLayer .selectAll("path") .data(data) .enter() .append("path") .style("background-color", "blue") .attr("fill", "green") .attr("stroke", "#222") .on("mouseover", function(){ d3.select(this).attr("fill", "red"); }) .on("mouseout", function(){ d3.select(this).transition().duration(500).attr("fill", "green"); }) }); /*地形を回転させる*/ const draw = () => { let i = 0; return () => { const w = stage.node().clientWidth; const h = stage.node().clientHeight; rotateStage.attr("transform", `rotate(23.4, ${w/2}, ${h/2})`)//画面の中心を軸にステージを23.4度傾ける i = i+0.5; projection .rotate([i,0,0]) //rotateのx値を増やして横に回転させる .scale(d3.min([w, h]) / 2) //画面サイズを元に地球儀の大きさを決定 .translate([w/2, h/2]) //画面中央に表示されるように移動する path.projection(projection); //path関数をアップデート seaLayer.select("path").attr("d", path); //海面用パスを描画 landLayer.selectAll("path").attr("d", path); //地図用パスを描画 } } setInterval(draw(), 100); //定期的に回転させる |
topojsonについて
topojsonはgeojsonに比べると効率のよいデータ形式なのでファイルサイズが小さくて済むのですが、最終的にはtopojson.jsを使ってクライアント側でgeojson形式に戻して使う仕様になっています。
なので、topojsonデータが用意できない時はgeojsonのままでも問題ありません。
featuresプロパティの中身を、パスジェネレータに渡してあげれば後はD3がパスデータに変換してくれます。
Widonws端末しかなくて、それでもgeojson形式のデータをtopojson形式のデータに変換したいときは、mapshaperというWebサービスを使うという方法もあります。