Question

I'm using d3.js with google maps in a vain attempt to visualise wireless coverage. the basic idea is that each point on the map would represent an access point and i would use a voronoi diagram from these points as a crude approximation of coverage etc.

so based on this demo, i have the following:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.min.js"></script>
    <link rel="stylesheet" href="http://mbostock.github.com/d3/ex/colorbrewer.css">
    <style type="text/css">

html, body, #map {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

.stations {
  position: absolute;
}

.stations, .stations svg {
  position: absolute;
}

.stations border {
  position: absolute;
 stroke: black;
 stroke-width: 2px;
}

.stations svg {
  width: 60px;
  height: 20px;
  padding-right: 100px;
  font: 10px sans-serif;
}

.stations circle {
  fill: brown;
  stroke: black;
  stroke-width: 1.5px;
}

    </style>
  </head>
  <body>
    <div id="map"></div>
    <script type="text/javascript">

// create map
var map = new google.maps.Map(d3.select("#map").node(), {
  zoom: 8,
  center: new google.maps.LatLng(37.76487, -122.41948),
  mapTypeId: google.maps.MapTypeId.TERRAIN
});


var data = [
{ name: 'pt1', lng: -122.28, lat: 38.2 },
{ name: 'pt2', lng: -122.05, lat: 38.0 },
{ name: 'pt3', lng: -122.12, lat: 37.67 },
{ name: 'pt4', lng: -121.82, lat: 37.7 },
{ name: 'pt5', lng: -121.95, lat: 38.38 },
{ name: 'pt6', lng: -121.78, lat: 36.93 },
{ name: 'pt7', lng: -122.25, lat: 37.52 },
{ name: 'pt8', lng: -122.82, lat: 38.5 },
{ name: 'pt9', lng: -121.92, lat: 37.37 },
{ name: 'pt10', lng: -122.37, lat: 37.62 },
{ name: 'pt11', lng: -121.23, lat: 37.9 },
]


// Load the station data. When the data comes back, create an overlay.
var overlay = new google.maps.OverlayView();

// Add the container when the overlay is added to the map.
overlay.onAdd = function() {
  var layer = d3.select(this.getPanes().overlayLayer).append("div")
        .attr("height", "100%")
        .attr("width", "100%")
        .attr("class", "stations")

  // Draw each marker as a separate SVG element.
  // We could use a single SVG, but what size would it have?
  overlay.draw = function() {
    var projection = this.getProjection(),
        padding = 10;

    var marker = layer.selectAll("svg")
        .data( data )
        .each(transform) // update existing markers
      .enter().append("svg:svg")
        .each(transform)
        .attr("class", "marker")

    marker.append("svg:circle")
        .attr("r", 4.5)
        .attr("cx", padding )
        .attr("cy", padding );

    // add a label.
    marker.append("svg:text")
        .attr("x", padding + 7)
        .attr("y", padding)
        .attr("dy", ".31em")
        .text( function(d) { 
          return d.name; }
        );

    var v = d3.geom.voronoi( translate(data) );
    // console.log( v )

    var edges = layer.selectAll("path")
        .data( v )
      .enter().append("svg:svg")
        .attr( "class", "border" )
        .append("svg:path")
        .attr( "d", function(d){
          var e = transform_path(d)
          var p = 'M' + e.join('L') + 'Z'
          console.log( 'PATH: ' + p)
          return p
        })

    function translate(data) {
      var d = []
      for( var i=0; i<data.length; i++){
        var c = [ data[i].lat, data[i].lng ]
        d.push( c )
      }
      return d
    }

    function _projection( lat, lng ) {
      e = new google.maps.LatLng( lat, lng );
      e = projection.fromLatLngToDivPixel(e);
      return [ e.x - padding, e.y - padding]
      // return [ e.x, e.y ]
    }

    function transform(d) {
      e = _projection( d.lat, d.lng )
      console.log("marker " + d.lat +', ' + d.lng + " -> left: " + e[0] +", top: " + e[1] )
      return d3.select(this)
          .style("left", e[0] + "px")
          .style("top", e[1] + "px");
    }

    function transform_path(data) {
      var d = []
      console.log(data)
      for( var i=0; i<data.length; i++) {
        var c = _projection( data[i][0], data[i][2] )
        console.log( ' path point: ' + JSON.stringify(data[i]) + ' -> left: ' + c[0] + ", top: " + c[1])
        d.push( c )
      }
      // console.log(d)
      return d
    }

  };
};

// Bind our overlay to the map…
overlay.setMap(map);

    </script>
  </body>
</html>

However, i can not get any of the path elements showing up. can any one help? i have the above code up on jsfiddle. cheers!

Was it helpful?

Solution

Here you can see the paths showing up. Your problem was not related to D3, but to bad CSS styling : width were set to 0px, styles for the circles were given to the paths, etc.

http://jsfiddle.net/uF9PV/7/

I also noticed design flaws : your dots should not be positioned with CSS through absolute positioning, but rather through SVG positioning (let D3 do the trick for you). My advice would be to separate clearly the overlay and the Google map. The tricky part would be to make sure that they move together (zooms and left-right up-down)

good luck
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top