Я работаю над визуализацией миграции из города в город, и у меня возникла проблема ... Я хочу отобразить свою карту поверх базовой карты листовки. Проблема состоит в том, что карта листовки увеличивается и уменьшается, но созданный SVG является статичным. Я пытался реализовать много примеров, но я застрял ... Вот мой код:
var map = L.map('map', {
center: [52.52, 13.5],
zoom: 11,
zoomControl: true
});
mapLink = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a>contributors'
}).addTo(map);
// Add an SVG element to Leaflet’s overlay pane
var w = 950;
var h = 600;
var centered;
var formatC = d3.format(",.0f");
var formatD = d3.format("+,.0f");
var immin, immax, exmin, exmax;
var colors = ["#EDF8FB", "#41083E"];
var immdomain = [24431, 537148];
var emmdomain = [20056, 566986];
var circleSize = d3.scale.linear().range([0, 25000]).domain([0, 137175]);
var lineSize = d3.scale.linear().range([2, 25]).domain([0, 35000]);
var fillcolor = d3.scale.linear().range(colors).domain(immdomain);
//Define path generator
var path = d3.geo.path()
//Create SVG element
var svg = d3.select(map.getPanes().overlayPane)
.append("svg")
.attr("width", w)
.attr("height", h)
.style("class", "background");
var fp = d3.format(".1f");
var g = svg.append("g").attr("class", "leaflet-zoom-hide");
// This is the function that transforms D3 svg output to the correct leaflet projection
function projectPoint(x, y) {
var point = map.latLngToLayerPoint(new L.LatLng(y, x));
this.stream.point(point.x, point.y);
}
//initialize html tooltip
var tooltip = d3.select("#maincontainer")
.append("div")
.attr("id", "tt")
.style("z-index", "10")
.style("position", "absolute")
.style("visibility", "hidden");
var tooltip2 = d3.select("#maincontainer")
.append("div")
.attr("id", "tt2")
.style("z-index", "10")
.style("position", "absolute")
.style("visibility", "hidden");
var coming, going;
d3.csv("coming.csv", function(data) {
coming = data;
});
d3.csv("going.csv", function(data) {
going = data;
d3.json("test.json", function(json) {
var bounds = d3.geo.bounds(json)
bottomLeft = bounds[0],
topRight = bounds[1],
rotLong = -(topRight[0]+bottomLeft[0])/2;
center = [(topRight[0]+bottomLeft[0])/2+rotLong, (topRight[1]+bottomLeft[1])/2],
//default scale projection
projection = d3.geo.albers()
.parallels([bottomLeft[1],topRight[1]])
.rotate([rotLong,0,0])
.translate([w/2,h/2])
.center(center),
bottomLeftPx = projection(bottomLeft),
topRightPx = projection(topRight),
scaleFactor = 1.00*Math.min(w/(topRightPx[0]-bottomLeftPx[0]), h/(-topRightPx[1]+bottomLeftPx[1])),
projection = d3.geo.albers()
.parallels([bottomLeft[1],topRight[1]])
.rotate([rotLong,0,0])
.translate([w/2,h/2])
.scale(scaleFactor*0.975*1000)
.center(center);
path = d3.geo.path()
.projection(projection);
for (var i = 0; i < data.length; i++) {
var dataName = data[i].state;
var tempObj = {};
for (var propt in data[i]) {
var valz = parseFloat(data[i][propt]);
tempObj[propt] = valz;
}
//Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.name;
if (dataName == jsonState) {
matched = true;
json.features[j].properties.state = dataName;
json.features[j].id = dataName;
json.features[j].abbrev = data[i].abbrev;
json.features[j].ind = i;
for (var propt in tempObj) {
if (!isNaN(tempObj[propt])) {
json.features[j].properties[propt] = tempObj[propt];
}
}
break;
}
}
}
//Bind data and create one path per GeoJSON feature
g.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("class", "state")
.attr("id", function(d) {
return d.properties.state;
})
.attr("d", path)
.attr("stroke-width", 0.5)
.style("stroke", "#666")
.style("fill", "#fff");
g.selectAll("circle")
.data(json.features)
.enter().append("circle")
.attr("cx", function(d) {
var centname = d.properties.name;
var ctroid;
ctroid = path.centroid(d)[0];
return ctroid;
})
.attr("cy", function(d) {
var centname = d.properties.name;
var ctroid;
ctroid = path.centroid(d)[1];
return ctroid;
})
.attr("r", function(d) {
var diff = d.properties.total_imm - d.properties.total_emm;
return circleSize(Math.sqrt(Math.abs(diff) / Math.PI));
})
.attr("class", "circ")
.attr("id", function(d) {
return d.abbrev;
})
.attr("fill", function(d) {
var diff = d.properties.total_imm - d.properties.total_emm;
if (diff > 0) {
return "#65a89d";
}
else {
return "#a96a46";
}
})
.attr("fill-opacity", "0.5")
.attr("stroke", "#fff")
.attr("stroke-weight", "0.5")
.on("mouseover", function(d) {
return toolOver(d, this);
})
.on("mousemove", function(d) {
var m = d3.mouse(this);
mx = m[0];
my = m[1];
return toolMove(mx, my, d);
})
.on("mouseout", function(d) {
return toolOut(d, this);
})
.on("click", function(d) {
clicked(d)
});
});
});
function toolOver(v, thepath) {
d3.select(thepath).style({
"fill-opacity": "0.7",
"cursor": "pointer"
});
return tooltip.style("visibility", "visible");
};
function toolOut(m, thepath) {
d3.select(thepath).style({
"fill-opacity": "0.5",
"cursor": ""
});
return tooltip.style("visibility", "hidden");
};
function toolMove(mx, my, data) {
if (mx < 120) {
mx = 120
};
if (my < 40) {
my = 40
};
return tooltip.style("top", my + -140 + "px").style("left", mx - 120 + "px").html("<div id='tipContainer'><div id='tipLocation'><b>" + data.id + "</b></div><div id='tipKey'>Migration in: <b>" + formatC(data.properties.total_imm) + "</b><br>Migration out: <b>" + formatC(data.properties.total_emm) + "</b><br>Net migration: <b>" + formatC((data.properties.total_imm - data.properties.total_emm)) + "</b></div><div class='tipClear'></div> </div>");
};
function toolOver2(v, thepath) {
d3.select(thepath).style({
"opacity": "1",
"cursor": "pointer"
});
return tooltip2.style("visibility", "visible");
};
function toolOut2(m, thepath) {
d3.select(thepath).style({
"opacity": "0.5",
"cursor": ""
});
return tooltip2.style("visibility", "hidden");
};
function toolMove2(mx, my, home, end, v1, v2) {
var diff = v1 - v2;
if (mx < 120) {
mx = 120
};
if (my < 40) {
my = 40
};
return tooltip2.style("top", my + -140 + "px").style("left", mx - 120 + "px").html("<div id='tipContainer2'><div id='tipLocation'><b>" + home + "/" + end + "</b></div><div id='tipKey2'>Migration, " + home + " to " + end + ": <b>" + formatC(v2) + "</b><br>Migration, " + end + " to " + home + ": <b>" + formatC(v1) + "</b><br>Net change, " + home + ": <b>" + formatD(v1 - v2) + "</b></div><div class='tipClear'></div> </div>");
};
function clicked(selected) {
var selname = selected.id;
var homex = path.centroid(selected)[0];
var homey = path.centroid(selected)[1];
g.selectAll(".goingline")
.attr("stroke-dasharray", 0)
.remove()
g.selectAll(".goingline")
.data(going)
.enter().append("path")
.attr("class", "goingline")
.attr("d", function(d, i) {
var abb = d.abbrev;
var finalval = coming[i][selname] - going[i][selname];
var theState = d3.select("#" + abb);
if (!isNaN(finalval)) {
var startx = path.centroid(theState[0][0].__data__)[0];
var starty = path.centroid(theState[0][0].__data__)[1];
if (finalval > 0) {
return "M" + startx + "," + starty + " Q" + (startx + homex) / 2 + " " + (starty + homey) / 1.5 + " " + homex + " " + homey;
}
else {
return "M" + homex + "," + homey + " Q" + (startx + homex) / 2 + " " + (starty + homey) / 2.5 + " " + startx + " " + starty;
}
}
})
.call(transition)
.attr("stroke-width", function(d, i) {
var finalval = coming[i][selname] - going[i][selname];
return lineSize(parseFloat(Math.abs(finalval)));
})
.attr("stroke", function(d, i) {
var finalval = coming[i][selname] - going[i][selname];
if (finalval > 0) {
return "#65a89d";
}
else {
return "#a96a46";
}
})
.attr("fill", "none")
.attr("opacity", 0.5)
.attr("stroke-linecap", "round")
.on("mouseover", function(d){
return toolOver2(d, this);
})
.on("mousemove", function(d, i){
var m = d3.mouse(this);
mx = m[0];
my = m[1];
return toolMove2(mx, my, selname, d.state, coming[i][selname], going[i][selname]);
})
.on("mouseout", function(d) {
return toolOut2(d, this);
});
}
function transition(path) {
path.transition()
.duration(1500)
.attrTween("stroke-dasharray", tweenDash);
}
function tweenDash() {
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l);
return function(t) {
return i(t);
};
}
Я все еще очень плохо знаком с d3 js. Я уверен, что моя проблема не большая, но мне действительно нужна помощь в этом.