インタラクティブグローブ-SVGとCanvas

読者の皆さん、こんにちは! 前回 、インタラクティブなホロプレットマップの作成プロセスを研究しましたが、今度はタスクを少し複雑にして、一般的に地球と呼ばれる地球の3次元モデルに進むことを提案します。 SVGバージョンとCanvasバージョンの2種類のグローブを作成します。 どちらの場合も、 d3.js JavaScriptライブラリを使用します。 各オプションには独自の利点があります。 私のパフォーマンスでは、 ブループラネットは次のとおりです。



地球



そして、大陸と海で独自の世界を作成する方法は、カットの下で見つけることができます。



開始する



まず、ジオデータを見つける必要があります。 前回同様、これらの目的にはTopoJSONを使用します。 取得方法については、「カートグラフィックの問題」セクションの前の記事をご覧ください。 したがって、1:110,000,000、または1 cm = 1,100 km(1″ = 1,736マイル)の縮尺のマ​​ップ用のTopoJSONファイルworld-110m.json



と、 id



という形式のworld-110m-country-names.tsv



を持つファイルworld-110m-country-names.tsv



world-110m-country-names.tsv



ます。国の名前。 この場合、名前を任意の言語に簡単に翻訳できるため、名前付きの外部ファイルが便利に使用されます。 すべて、地球の創造に直接進むことができます。

注:
選択した規模では、一部の小国は幾何学的な意味で「縮退」しているため、リストには174か国しかありません。


インタラクティブなグローブを描く



私たちの目標は、次のことができる世界です。





必要な人のためのテンプレート。
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Nice title</title> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/queue.v1.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> </head> <style> Your awesome CSS </style> <body> <h1>Cool Header</h1> <script> Your awesome d3.js code </script> </body> </html>
      
      







メイン変数を定義し、 DOM要素を追加します



  var width = 600, height = 500, sens = 0.25, focused; //Setting projection var projection = d3.geo.orthographic() .scale(245) .rotate([0, 0]) .translate([width / 2, height / 2]) .clipAngle(90); var path = d3.geo.path() .projection(projection); //SVG container var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); //Adding water svg.append("path") .datum({type: "Sphere"}) .attr("class", "water") .attr("d", path); var countryTooltip = d3.select("body").append("div").attr("class", "countryTooltip"), countryList = d3.select("body").append("select").attr("name", "countries");
      
      





sens



変数は、マウスでの回転の精度に責任があり、 focused



、選択された(中央の)国のトリガーとして使用されます。 ウィキペディアで使用されている投影正射投影法について読むことができます。 .clipAngle()メソッドは、球体のどの部分を表示する(または表示するかを決定します。ウィキペディアでもう一度読むことができます: 小円クリッピング 。 残りは説明を必要としないようです。



次に、 queue.jsライブラリを使用してファイルをアップロードします。これにより、非同期でこれを行うことができます。



  queue() .defer(d3.json, "data/world-110m.json") .defer(d3.tsv, "data/world-110m-country-names.tsv") .await(ready);
      
      





さて、メイン関数に移りましょう。ここでは、 ready



と呼ばれます。 まず、国名をドロップダウンリストに追加し、世界の国々を描きます。



  function ready(error, world, countryData) { var countryById = {}, countries = topojson.feature(world, world.objects.countries).features; //Adding countries to select countryData.forEach(function(d) { countryById[d.id] = d.name; option = countryList.append("option"); option.text(d.name); option.property("value", d.id); }); //Drawing countries on the globe var world = svg.selectAll("path.land") .data(countries) .enter().append("path") .attr("class", "land") .attr("d", path)
      
      





マウスイベントの処理に移りましょう。 ここでdrag.origin()には説明が必要です。要素(この場合は緯度と経度)をキャプチャするときに、「元の」(実際の)開始座標を設定できます。



  //Drag event .call(d3.behavior.drag() .origin(function() { var r = projection.rotate(); return {x: r[0] / sens, y: -r[1] / sens}; }) .on("drag", function() { var rotate = projection.rotate(); projection.rotate([d3.event.x * sens, -d3.event.y * sens, rotate[2]]); svg.selectAll("path.land").attr("d", path); svg.selectAll(".focused").classed("focused", focused = false); })) //Mouse events .on("mouseover", function(d) { countryTooltip.text(countryById[d.id]) .style("left", (d3.event.pageX + 7) + "px") .style("top", (d3.event.pageY - 15) + "px") .style("display", "block") .style("opacity", 1); }) .on("mouseout", function(d) { countryTooltip.style("opacity", 0) .style("display", "none"); }) .on("mousemove", function(d) { countryTooltip.style("left", (d3.event.pageX + 7) + "px") .style("top", (d3.event.pageY - 15) + "px"); });
      
      





国に焦点を当てて実装するには、 id



'nameで国の地理データを返す関数を作成する必要があります。 実際、ここに彼女がいます。



  function country(cnt, sel) { for(var i = 0, l = cnt.length; i < l; i++) { if(cnt[i].id == sel.value) {return cnt[i];} } };
      
      





これで、リストから選択した国に焦点を合わせて(中心に)実装に直接進むことができます。



  //Country focus on option select d3.select("select").on("change", function() { var rotate = projection.rotate(), focusedCountry = country(countries, this), p = d3.geo.centroid(focusedCountry); svg.selectAll(".focused").classed("focused", focused = false); //Globe rotating (function transition() { d3.transition() .duration(2500) .tween("rotate", function() { var r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]); return function(t) { projection.rotate(r(t)); svg.selectAll("path").attr("d", path) .classed("focused", function(d, i) { return d.id == focusedCountry.id ? focused = d : false; }); }; }) .transition(); })(); });
      
      





ここでは、すべてのソルトはtransition.tween()にあり、各補間値に対して特定の関数(回転)を呼び出すことができます。



回転、回転する青いボール。


それだけです-SVGグローブは準備ができています。 ソースはGitHubで見つけることができ(Habrahabrで読み取り専用の人に質問することもできます)、 bl.ocks.orgサービスで結果を感じることができます。



SVGの利点を見てみましょう。





地球惑星アニメーション



SVG実装では整理されているように見えるので、キャンバスでこのようなことを行う方法を見てみましょう。 地球の回転の簡単なアニメーションを作成します。 ここでの多くは、前の例と似ています。 コードは十分ではないので、私は一度にすべて持っていきます。



  var width = 800, height = 500; var projection = d3.geo.orthographic() .scale(245) .rotate([180, 0]) .translate([width / 2, height / 2]) .clipAngle(90); var canvas = d3.select("body").append("canvas") .attr("width", width) .attr("height", height); var c = canvas.node().getContext("2d"); var path = d3.geo.path() .projection(projection) .context(c); function getImage(path, callback) { var img = new Image(); img.src = path; img.onload = callback(null, img); } queue() .defer(d3.json, "data/world-110m.json") .defer(d3.tsv, "data/world-110m-country-names.tsv") .defer(getImage, "data/space.jpg") .await(ready); //Main function function ready(error, world, countryData, space) { var globe = {type: "Sphere"}, land = topojson.feature(world, world.objects.land), borders = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }); //Earth rotating (function transition() { d3.transition() .duration(15000) .ease("linear") .tween("rotate", function() { var r = d3.interpolate(projection.rotate(), [-180, 0]); return function(t) { projection.rotate(r(t)); c.clearRect(0, 0, width, height); c.drawImage(space, 0, 0); c.fillStyle = "#00006B", c.beginPath(), path(globe), c.fill(); c.fillStyle = "#29527A", c.beginPath(), path(land), c.fill(); c.strokeStyle = "#fff", c.lineWidth = .5, c.beginPath(), path(borders), c.stroke(); projection.rotate([180, 0]); }; }) .transition().duration(30).ease("linear") .each("end", transition); })(); };
      
      





回転は、ポイント[-180, 0]



[180, 0]



からポイント[-180, 0]



[180, 0]



への回転として実装されます。 したがって、「補間」は、キャッチに気付かずに、必要なことを行います。 次に、以前にそれをきれいにしてから、キャンバスにペイントを開始します。 背景、球体、大陸、国の国境を描きます。 transition



関数の再帰呼び出しにより、無限の回転が得られます。



「それでも彼女は回転します!」


さて、アニメーションを作成しました。 ソースはGitHubで見つけることができ、 bl.ocks.orgサービスを通じて宇宙の景色を楽しむことができます。



Canvasの利点を考慮してください:





おわりに



そこで、素晴らしいd3.jsライブラリを使用して作成されたいくつかの興味深い例を見てみました。 例をわかりやすく、視覚的に、非常に興味深いものにすることを試みました。 SVGとCanvasの戦いでは、最終的に友情が勝ったため、特定のテクノロジーの使用はプロジェクトのタイプに依存します。 たとえば、プロジェクトが地図作成に関連している場合、 SVGを使用することをお勧めします。マルチメディアを使用する場合は、Canvasが役立ちます。 あなたが興味を持っていたと思います。 d3.jsのさらなる開発に成功と幸運を!



All Articles