我有一个与GeoJSON并排的SVG图像。两个图像中都有相应的对象。我使用d3添加了它们。我目前能够分别放大和平移它们。我还可以在缩放或平移两个图像中的任何一个时获得比例和x,y。现在我想同步两个图像的缩放/平移,这样如果在一个图像上完成缩放/平移,则在另一个图像上完成相同数量的缩放/平移。如果我调用zoom.translateBy
和zoom.scaleBy
函数但我不知道如何应用它,我想这可以完成。这是代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Sketch-To-Metric Map Alignment by Qualitative Spatial Constraint Matching</title>
<!-- the data of the map -->
<script src="img/sketchmap_ids.json"></script>
<!--Add support for earlier versions of Internet Explorer -->
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
<filter id="offset" x="-20%" y="-10%" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="5"/>
<feOffset dx="5" dy="5" result="B"/>
<feMerge>
<feMergeNode in="B"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<filter id="dropshadow_2" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/> <!-- stdDeviation is how much to blur -->
<feOffset dx="2" dy="2" result="offsetblur"/> <!-- how much to offset -->
<feMerge>
<feMergeNode/> <!-- this contains the offset blurred image -->
<feMergeNode in="SourceGraphic"/> <!-- this contains the element that the filter is applied to -->
</feMerge>
</filter>
<!-- circle r="10" style="filter:url(#dropshadow)"/ -->
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="2" dy="2" result="offsetblur"/>
<feComponentTransfer>
<feFuncA type="linear" slope="0.2"/>
</feComponentTransfer>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<style>
.shadow {
-webkit-filter: drop-shadow( 5px 5px 5px 10px);
filter: drop-shadow( 5px 5px 2px); /* Same syntax as box-shadow */
}
.reveal section img { background:none; border:none; box-shadow:none; }
.service {
stroke-width: 4;
stroke: #999999;
fill: none;
}
.residential-line {
stroke-width: 8;
stroke: #b3b3b3;
fill: none;
}
.fence,.footway,.cycleway,.track,.path,.pedestrian,.steps {
stroke-width: 2;
stroke: #2b1100;
stroke-dasharray: 3,2,3;
fill: none;
}
.primary {
stroke-width: 18;
stroke: #b3b3b3;
fill: none;
}
.tertiary {
stroke-width: 12;
stroke: #b3b3b3;
fill: none;
}
.bridge {
stroke-width: 12;
stroke: #cd853f;
fill: none;
}
.graveyard {
stroke-width: 2;
stroke: #444444;
stroke-dasharray: 3,2,3;
fill: #668000;
}
.waterway-line,.river-line,.weir {
stroke-width: 5;
stroke: #2A7FFF;
fill: none;
}
.water {
stroke-width: 1;
stroke: #0066FF;
fill: #2A7FFF;;
}
.scrub,.forest {
stroke-width: 1;
stroke: #008033;
fill: #008033;
}
.grass,.village_green,.greenhouse {
stroke-width: 1;
stroke: #5FD35F;
fill: #5FD35F;
}
.residential,.commercial {
stroke-width: 1;
stroke: #FFF6D5;
fill: #FFF6D5;
}
.parking,.bicycle_parking {
stroke-width: 1;
stroke: #FFE680;
fill: #FFE680;
}
.university,.civic,.yes,.house,.school {
stroke-width: 0;
fill: #916F6F;
}
.map-panel {
width: 100%;
border: 1px solid #444444;
}
#sketch3,#sketch4,#sketch5,#sketch6,#sketch10,#sketchgraph11,#sketchgraph12 {
width: 45%;
float: left;
padding-bottom:0px;
}
#metric3,#metric4,#metric5,#metric6,#metric10,#metricgraph11,#metricgraph12 {
width: 45%;
float: right;
padding-bottom:0px;
}
.text-pane-left {
width: 45%;
float: right;
padding-bottom:0px;
}
.text-pane-right {
width: 45%;
float: right;
padding-bottom:0px;
}
#mynetwork {
width: 854px;
height: 480px;
position: relative;
border: 1px solid #444444;
background-color: #dddddd;
}
#othernetwork {
width: 800px;
height: 600px;
position: relative;
border: 1px solid #444444;
background-color: #dddddd;
}
#visualization {
width: 800px;
height: 600px;
position: relative;
border: 1px solid #444444;
background-color: #dddddd;
}
body {
color: #d3d3d3;
font: 12pt arial;
background-color: #ffffff;
}
</style>
</head>
<body>
<div class="map-panel" id="panel">
<div class="map-pane-left" id="sketch4"></div>
<div class="map-pane-right" id="metric4"></div>
</div>
<script src="d3/d3.min.js"></script>
<script src="d3/topojson.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
//https://datascience.blog.wzb.eu/2016/08/29/bringing-svg-to-life-with-d3-js/
//load sketch map
d3.xml("img/sketch_all_in_components_web.svg").mimeType("image/svg+xml").get(function(error, xml) {
if (error) throw error;
function sketchMapZoomed() {
svg.selectAll("*").attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
var currentScale = d3.event.scale;
var currentTranslate = d3.event.translate;
console.log(currentScale, currentTranslate);
}
//var copy = xml.documentElement.cloneNode(true);
document.getElementById('sketch4').appendChild(xml.documentElement);
d3.select('#sketch4').selectAll('g, path').on('mouseenter',animateMapTargets).on('mouseleave',removeFilter);
var svg = d3.select("svg")
.call(d3.behavior.zoom().on("zoom", sketchMapZoomed ))
});
//load metric map
var width = document.getElementById("sketch4").clientWidth;
height = (width * 0.71053942806206943134954217685331);
function metricMapZoomed () {
svg.attr("transform", d3.event.transform)
var transformMetric = d3.zoomTransform(this)
console.log(transformMetric);
//.call(d3.zoom.translateBy("sketch#4", transformMetric.x, transformMetric.y))
//var t = d3.select("#sketch4").attr("transform", "translate(" + transformMetric.x + "," + transformMetric.y + ") scale(" + transformMetric.k + ")");
}
var svg = d3.select("#metric4").append("svg")
.attr("width", width)
.attr("height", height)
.attr("id", "metricmap")
.call(d3.zoom().on("zoom", metricMapZoomed ))
.append("g");
//create a place holder rectangle to keep floats inline
var svgContainer = d3.select("body").append("svg")
.attr("width", width)
.attr("height", width)
.attr("id", "placeholder");
d3.json("img/defense_data.json", function(error, map) {
if (error) return console.error(error);
var projection = d3.geo.mercator()
.center([7.612337603149424, 51.96211781909236])
.scale(3000000);
//.translate(0,0);
var path = d3.geo.path()
.projection(projection);
svg.selectAll(".city_block_landmarks")
.data(topojson.feature(map, map.objects.city_block_landmarks).features)
.enter().append("path")
.attr("class", function(d){
//console.log(d.properties.class)
return d.properties.classfeature;
})
.attr("id", function(d){
//console.log(d.id)
return d.id;
})
.attr("d", path);
svg.selectAll(".hidden_landmarks")
.data(topojson.feature(map, map.objects.hidden_landmarks).features)
.enter().append("path")
.attr("class", function(d){
//console.log(d.properties.class)
return d.properties.classfeature;
})
.attr("id", function(d){
//console.log(d.id)
return d.id;
})
.attr("d", path);
svg.selectAll(".botanica_mid_polygons")
.data(topojson.feature(map, map.objects.botanica_mid_polygons).features)
.enter().append("path")
.attr("class", function(d){
//console.log(d.properties.class)
return d.properties.classfeature;
})
.attr("id", function(d){
//console.log(d.id)
return d.id;
})
.attr("d", path);
svg.selectAll(".streets_linear_features")
.data(topojson.feature(map, map.objects.streets_linear_features).features)
.enter().append("path")
.attr("class", function(d){
//console.log(d.properties.class)
return d.properties.classfeature;
})
.attr("id", function(d){
//console.log(d.id)
return d.id;
})
.attr("d", path);
});
//animate objects on mouse on and remove animation on mouse off
function animateMapTargets() {
if (this.id)
if (targets[this.id])
targets[this.id].forEach(animateTargetNode);
};
function animateTargetNode(obj, i) {
//console.log(d3.select('#'+obj)./*node().*/style('filter','url(#offset)'));
//d3.select('#'+obj).style('filter','url(#offset)');
//console.log(d3.select('#'+obj).classed("shadow", true));//
d3.select('#'+obj).classed("shadow", true);
//.attr() style="filter:url(#dropshadow)"
//.attr();
}
function removeFilter() {
if (this.id)
if (targets[this.id])
targets[this.id].forEach(function animateTargetNode(obj, i) {
//d3.select('#'+obj).style('filter','none');
d3.select('#'+obj).classed("shadow", false);
});
};
</script>
</body>
</html>
答案 0 :(得分:0)
我想如果我拨打
,就可以完成zoom.translateBy
和zoom.scaleBy
这两个都是相对的,即它们被添加到当前变换/乘以当前变换,它们不设置它。因此,如果当前比例为0.5并且您使用值为1.0的scaleBy
,则仍然会得到0.5的比例(因为0.5 * 1.0 == 0.5)。
要在两个缩放之间“同步”绝对值,您将分别使用zoom.translateTo
和zoom.scaleTo
。
更直接的方法是设置整个变换,而不是设置缩放变换的各个组件。为此,您将在源节点上使用zoomTransform
(或使用缩放事件的event.transform
)来获取当前变换,然后使用zoom.transform
在目标上设置该变换。