block by shimizu 6b7123b893fca8440e70216cddfcfe52

2017 Submarine Cable

Full Screen

海底ケーブルを地球儀風に表示。

データ元 Submarine Cable Map

index.html

<!DOCTYPE html>
<html xmlns="//www.w3.org/1999/xhtml">
<head>
<title>Submarine Cable</title>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.css"/>
<style>
html, body {
    width: 100%;
    height: 100%;
    margin: 0px;
    padding: 0px;
    background-color: black;
}
#warpper {
    width: 100%;
    height: 100%;      
}

svg {
    width: 100%;
    height: 100%;    
}
.tooltip {
  border: 1px solid black;
  background-color: white;
  padding: 5px 8px 4px 8px;
  border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
}
</style>
</head>
<body>
<div id="warpper"><svg></svg></div>


<script src="//unpkg.com/d3@5.0.0/dist/d3.min.js"></script>    
<script src="//npmcdn.com/@turf/turf/turf.min.js"></script>

<script>
const tooltip = d3.select("body")
    .append("div")
    .attr("class", "tooltip")
    .style("position", "absolute")
    .style("z-index", "10")
    .style("visibility", "hidden")
    .on("click", function(){
        d3.select(this)
        .style("visibility", "hidden")
    })
            
    
const warpper = d3.select("#warpper").node(); //firefox hacks
const svg = d3.select("svg");    
const stage = svg.append("g");
const seaLayer = stage.append("g").attr("class", "seaLayer");
const landLayer = stage.append("g").attr("class", "landLayer");
const cableLayer = stage.append("g").attr("class", "cableLayer");
const pointLayer = stage.append("g").attr("class", "pointLayer");

const projection = d3.geoOrthographic();
const path = d3.geoPath();

const initialScale = projection.scale();
const sensitivity = 58*2;

const  loadGeobuf = (file, callback) => {
        const oReq = new XMLHttpRequest();
        oReq.open("GET", file, true);
        oReq.responseType = "arraybuffer";

        oReq.onload = (oEvent) => {
            const pd = new Pbf(new Uint8Array(oReq.response));
            const geojson =  geobuf.decode(pd);
            console.log(geojson)
            callback(geojson);
        };

        oReq.send();
    };

const p1 = d3.json("cable.geojson");
const p2 = d3.json("countries.geojson");
const p3 = d3.csv("fusion-landing-points-201803141423.csv");

Promise.all([p1, p2, p3]).then(init);

   


function init(data){
    const cable = data[0];
    const countries = data[1];
    const point = data[2];
    
    const parser = new DOMParser();

    const pointGeoJSON = point.map(d => {
       d.coordinates =   parser.parseFromString(d.coordinates, 'text/xml');
       const lnglat = d.coordinates.firstChild.textContent.split(",");
       
       d.lng = +lnglat [0];
       d.lat = +lnglat[1];
       
       delete d.coordinates;
       return turf.point([d.lng, d.lat], {name:d.name})
    })
    

  
    path.projection(projection);

    seaLayer.append("path")
        .datum({type: "Sphere"})
        .attr("fill", "#eee")   
    
    
    landLayer
        .selectAll("path")
        .data(countries.features) 
        .enter()
        .append("path")
        .attr("fill", "rgb(200,200,203)")
        .attr("stroke", "rgb(127, 135, 143)")
    
    cableLayer 
        .selectAll("path")
        .data(cable.features) 
        .enter()
        .append("path")
        .attr("fill", "none")
        .attr("stroke-width", 1.5)
        .attr("stroke-opacity", 0.6)
        .attr("stroke", "rgb(0,65,255)")
        .on("mouseout", function(d){
            d3.select(this).attr("stroke", "rgb(0,65,255)")
            .attr("stroke-opacity", 0.6)
        })
        .on("mouseover", function(d){
            d3.select(this).attr("stroke", "rgb(255,0,0)")
              .attr("stroke-opacity", 1)
            const dp = d.properties;
            const  content = `${dp.Name}<br>${dp.length}`;
              
            tooltip
                .style("top", (d3.event.pageY-100)+"px")
                .style("left",(d3.event.pageX-100)+"px")
                .style("visibility", "visible")
                .style("background-color", "rgb(180,235,250)")
                .html(content);
                
        });

    
    pointLayer.selectAll("path")
        .data(pointGeoJSON)
        .enter()
        .append("path")
        .attr("fill", "white")
        .attr("stroke", "black")
        .on("mouseout", function(d){
            d3.select(this).attr("fill", "white")
        })
        .on("mouseover", function(d){
            d3.select(this).attr("fill", "red")
            const dp = d.properties;
            const  content = `${dp.name}`;
              
            tooltip
                .style("top", (d3.event.pageY-100)+"px")
                .style("left",(d3.event.pageX-100)+"px")
                .style("visibility", "visible")
                .style("background-color", "rgb(250,250,250)")
                .html(content);
                
        });
    
    
   render();
}

function render(){
  
    const w = warpper.clientWidth  || warpper.offsetWidth;
    const h = warpper.clientHeight || warpper.offsetHeight;

    projection
      .scale(d3.min([w, h]) / 2) 
      .translate([w/2, h/2])
      //.preclip(d3.geoClipCircle(90))
      
    path.projection(projection);    
    
    seaLayer.select("path").attr("d", path); 
    landLayer.selectAll("path").attr("d", path);    
    cableLayer.selectAll("path").attr("d", path);
    pointLayer.selectAll("path").attr("d", path);
    
    
}

var drag = d3.drag().on("drag", dragged);
var zoom = d3.zoom()
        .scaleExtent([1 / 2, 12])
        .on("zoom", zoomed)

svg
    .call(zoom)
    .on("mousedown.zoom", null)
    
svg.call(drag)
   
function zoomed() {
    stage.attr("transform", d3.event.transform);
}

function dragged(){
    const rotate = projection.rotate();
    const k = sensitivity / projection.scale();
    projection.rotate([
        rotate[0] + d3.event.dx * k,
        rotate[1] - d3.event.dy * k,
    ])
    render();
     
}

window.addEventListener("resize", this.resize());

function resize() {
  let t;

  return event => {
    if (t !== false) {
      clearTimeout(t);
    }
    t = setTimeout(() => {
      render();
    }, 100);
  };
}

</script>

</body>

</html>