Maddy Chavda
Maddy Chavda

Reputation: 591

how to zoom only map and smiley could stay at same place and size

I having problem of zoom over map. The actual problem is when i zoom map, the location showing on map using smiley could also zoom but i don't want to zoom smiley. It could stay at same size and place. Sometime smiley get overlap so to avoid this i am trying to solve the above problem but i don't have idea how to transform attribute contains many things like images and text on map of d3.js. Please have a look at jsfiddle link and you can see that at japan 3 smiley get overlap and keep overlapped even after zooming map.

My JSfiddle link

my code is following:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
  stroke: white;
  stroke-width: 0.25px;
  fill: grey;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
var width = 960,
    height = 500;

var data = [
  {
    "code":"TYO",
    "city":"TOKYO",
    "country":"JAPAN",
    "lat":"35.68",
    "lon":"139.76"
  },
  {
    "code":"OSK",
    "city":"Osaka",
    "country":"JAPAN",
    "lat":" 34.40",
    "lon":"135.37"
  },
  {
    "code":"HISH",
    "city":"Hiroshima",
    "country":"JAPAN",
    "lat":"34.3853",
    "lon":"132.4553"
  },
  {
    "code":"BKK",
    "city":"BANGKOK",
    "country":"THAILAND",
    "lat":"13.75",
    "lon":"100.48"
  },
  {
    "code":"DEL",
    "city":"DELHI",
    "country":"INDIA",
    "lat":"29.01",
    "lon":"77.38"
  },
  {
    "code":"SEA",
    "city":"SEATTLE",
    "country":"USA",
    "lat":"38.680632",
    "lon":"-96.5001"
  }
];

var projection = d3.geo.mercator()
    .center([0, 5 ])
    .scale(200)
    .rotate([-180,0]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var path = d3.geo.path()
    .projection(projection);

var g = svg.append("g");

// load and display the World
d3.json("world-110m2.json", function(error, topology) {

// load and display the cities

function drawMap(data){

    var circle = g.selectAll("circle")
        .data(data)
        .enter()
        .append("g")

    circle.append("circle")
       .attr("cx", function(d) {
               return projection([d.lon, d.lat])[0];
       })
       .attr("cy", function(d) {
               return projection([d.lon, d.lat])[1];
       })
       .attr("r", 5)
       .style("fill", "red");

    circle.append("image")
            .attr("xlink:href", "http://fc08.deviantart.net/fs71/f/2013/354/8/7/blinking_smiley__animated__by_mondspeer-d6ylwn3.gif")//http://t2.gstatic.//com/images?q=tbn:ANd9GcT6fN48PEP2-z-JbutdhqfypsYdciYTAZEziHpBJZLAfM6rxqYX";})
            .attr("class", "node")
            .attr("x", function(d) {
                return (projection([d.lon, d.lat])[0]) - 8;
            })
            .attr("y", function(d) {
                return (projection([d.lon, d.lat])[1])-8;
            })
            .attr("width",20)
            .attr("height",20)
//});
}


g.selectAll("path")
      .data(topojson.object(topology, topology.objects.countries)
          .geometries)
    .enter()
      .append("path")
      .attr("d", path)

      drawMap(data);

});

// zoom and pan
var zoom = d3.behavior.zoom()
    .on("zoom",function() {
        g.attr("transform","translate("+ 
            d3.event.translate.join(",")+")scale("+d3.event.scale+")");
        g.selectAll("circle")
            .attr("d", path.projection(projection));
        g.selectAll("path")  
            .attr("d", path.projection(projection)); 

  });

svg.call(zoom)

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

Any body help me to zoom only map image not smiley

Upvotes: 0

Views: 890

Answers (1)

AJ_91
AJ_91

Reputation: 581

Implement semantic zooming :)

Try use this example to change your code :) :

Semantic zoom on map with circle showing capital

JSFIDDLE : http://jsfiddle.net/xf7222dg/2/

The code below shrinks the 'circles' depending on scale

var zoom = d3.behavior.zoom()
  .on("zoom",function() {
     g.attr("transform","translate("+ 
        d3.event.translate.join(",")+")scale("+d3.event.scale+")");
     g.selectAll("circle")
      .attr("r", function(){
        var self = d3.select(this);
        var r = 8 / d3.event.scale;  // set radius according to scale
        self.style("stroke-width", r < 4 ? (r < 2 ? 0.5 : 1) : 2);  // scale stroke-width
        return r;
    });
});

Here is it working with your smileys: http://jsfiddle.net/dmn0d11f/7/

You have to change the 'width' of the nodes (images) not the radius like with the circles. So select the nodes and instead of changing 'r' change 'width' :

g.selectAll(".node")
      .attr("width", function(){
        var self = d3.select(this);
        var r = 28 / d3.event.scale;  // set radius according to scale
        self.style("stroke-width", r < 4 ? (r < 2 ? 0.5 : 1) : 2);  // scale stroke-width
        return r;
    });

Upvotes: 1

Related Questions