我正在用d3.js做一些关于缩放的测试。目前,我已经在测试中成功实现了几何缩放,但它有一个缺点:缩放的g
下的元素正在缩放。据我所知,这可以通过使用semantic zooming来解决。
问题是我在测试中需要scale
,因为我正在将它与jQuery.UI滑块value
同步。
另一方面,我希望调整text
个元素以在缩放操作后保持其大小。
我有一个当前尝试的例子here。
我无法更改代码以适应此目的。任何人都可以分享一些见解/想法吗?
答案 0 :(得分:6)
对于您的解决方案,我合并了两个示例:
代码段:
function zoom() {
text.attr("transform", transform);
var scale = zoombehavior.scale();
//to make the scale rounded to 2 decimal digits
scale = Math.round(scale * 100) / 100;
//setting the slider to the new value
$("#slider").slider( "option", "value", scale );
//setting the slider text to the new value
$("#scale").val(scale);
}
//note here we are not handling the scale as its Semantic Zoom
function transform(d) {
//translate string
return "translate(" + x(d[0]) + "," + y(d[1]) + ")";
}
function interpolateZoom(translate, scale) {
zoombehavior
.scale(scale)//we are setting this zoom only for detecting the scale for slider..we are not zoooming using scale.
.translate(translate);
zoom();
}
var slider = $(function() {
$("#slider").slider({
value: zoombehavior.scaleExtent()[0],//setting the value
min: zoombehavior.scaleExtent()[0],//setting the min value
max: zoombehavior.scaleExtent()[1],//settinng the ax value
step: 0.01,
slide: function(event, ui) {
var newValue = ui.value;
var center = [centerX, centerY],
extent = zoombehavior.scaleExtent(),
translate = zoombehavior.translate(),
l = [],
view = {
x: translate[0],
y: translate[1],
k: zoombehavior.scale()
};
//translate w.r.t the center
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = newValue;//the scale as per the slider
//the translate after the scale(so we are multiplying the translate)
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
interpolateZoom([view.x, view.y], view.k);
}
});
});
我正在缩放w.r.t. 250,250这是剪辑圈的中心。
工作代码here(已添加必要的评论)
希望这有帮助!
答案 1 :(得分:2)
要做你想做的事,你需要先重构一下代码。对于d3,最好使用data()
将项添加到选择中,而不是使用for循环。
所以这个:
for(i=0; i<7; i++){
pointsGroup.append("text")
.attr("x", function(){
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randx = Math.random();
return Math.floor(plusOrMinus*randx*75)+centerx;
})
.attr("y", function(){
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randy = Math.random();
return Math.floor(plusOrMinus*randy*75)+centery;
})
.html("star")
.attr("class", "point material-icons")
.on("click", function(){console.log("click!");});
}
&#13;
成为这个
var arr = [];
for(i=0; i<7; i++){
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randx = Math.random();
var x = Math.floor(plusOrMinus*randx*75)+centerx;
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randy = Math.random();
var y = Math.floor(plusOrMinus*randy*75)+centery;
arr.push({"x":x,"y":y});
}
pointsGroup.selectAll("text")
.data(arr)
.enter()
.append("text")
.attr("x", function(d,i){
return d.x;// This corresponds to arr[i].x
})
.attr("y", function(d,i){
return d.y;// This corresponds to arr[i].y
})
.html("star")
.attr("class", "point material-icons")
.on("click", function(){console.log("click!");});
&#13;
这样,您可以使用例如.attr("x",function(d,i){ //d.x is equal to arr.x, i is item index in the selection});
然后,为了实现您的目标,您应该使用线性比例来更改每个星形位置,而不是更改项目的比例。
首先,将线性比例添加到小提琴并将其应用于缩放:
var scalex = d3.scale.linear();
var scaley = d3.scale.linear();
var zoom = d3.behavior.zoom().x(scalex).y(scaley).scaleExtent([1, 5]).on('zoom', onZoom);
&#13;
最后在缩放事件中,将比例应用于每个明星x
和y
function onZoom(){
d3.selectAll("text")
.attr("x",function(d,i){
return scalex(d.x);
})
.attr("y",function(d,i){
return scaley(d.y);
});
}
&#13;
此时,缩放将在没有滑块的情况下工作。要添加滑块,只需在onSlide事件期间手动更改缩放行为比例值,然后调用onZoom。
function onSlide(scale){
var sc = $("#slider").slider("value");
zoom.scale(sc);
onZoom();
}
&#13;
注意:我使用此配置作为滑块:
var slider = $(function() {
$( "#slider" ).slider({
value: 1,
min: 1,
max: 5,
step: 0.1,
slide: function(event, ui){
onSlide(5/ui.value);
}
});
});
&#13;
请注意,此时此时ui的变焦是相对于(0,0)执行的,而不是你的&#34;圈&#34;窗口中心。为了解决这个问题,我从程序化示例中简化了以下函数,该函数计算有效的translate和scale以提供缩放行为。
// To handle center zooming
var width = 500;
var height = 600;
function zoomClick(sliderValue) {
var center = [width / 2, height / 2],
extent = zoom.scaleExtent(),
translate = zoom.translate();
var view = {
x: zoom.translate()[0],
y: zoom.translate()[1],
k: zoom.scale()
};
var target_zoom = sliderValue;
if (target_zoom < extent[0] || target_zoom > extent[1]) {
return false;
}
var translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
var l = [];
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
// [view.x view.y] is valid translate
// view.k is valid scale
// Then, simply feed them to the zoom behavior
zoom
.scale(view.k)
.translate([view.x, view.y]);
// and call onZoom to update points position
onZoom();
}
&#13;
然后只需更改onSlide
以在每次滑块移动时使用此新功能
function onSlide(scale){
var sc = $("#slider").slider("value");
zoomClick(sc);
}
&#13;
完整摘要
function onZoom(){
d3.selectAll("text")
.attr("x",function(d,i){
return scalex(d.x);
})
.attr("y",function(d,i){
return scaley(d.y);
});
}
function onSlide(scale){
var sc = $("#slider").slider("value");
zoomClick(sc);
}
var scalex = d3.scale.linear();
var scaley = d3.scale.linear();
var zoom = d3.behavior.zoom().x(scalex).y(scaley).scaleExtent([1, 5]).on('zoom', onZoom);
var svg = d3.select("body").append("svg")
.attr("height", "500px")
.attr("width", "500px")
.call(zoom)
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);
var centerx = 250,
centery = 250;
var circleGroup = svg.append("g")
.attr("id", "circleGroup");
var circle = circleGroup.append("circle")
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", 150)
.attr("class", "circle");
var pointsParent = svg.append("g").attr("clip-path", "url(#clip)").attr("id", "pointsParent");
var pointsGroup = pointsParent.append("g")
.attr("id", "pointsGroup");
var arr = [];
for(i=0; i<7; i++){
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randx = Math.random();
var x = Math.floor(plusOrMinus*randx*75)+centerx;
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
var randy = Math.random();
var y = Math.floor(plusOrMinus*randy*75)+centery;
arr.push({"x":x,"y":y});
}
pointsGroup.selectAll("text")
.data(arr)
.enter()
.append("text")
.attr("x", function(d,i){
return d.x;// This corresponds to arr[i].x
})
.attr("y", function(d,i){
return d.y;// This corresponds to arr[i].y
})
.html("star")
.attr("class", "point material-icons")
.on("click", function(){console.log("click!");});
zoom(pointsGroup);
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:circle")
.attr("id", "clip-circ")
.attr("cx", centerx)
.attr("cy", centery)
.attr("r", 149);
var slider = $(function() {
$( "#slider" ).slider({
value: 1,
min: 1,
max: 5,
step: 0.1,
slide: function(event, ui){
onSlide(5/ui.value);
}
});
});
// To handle center zooming
var width = 500;
var height = 600;
function zoomClick(sliderValue) {
var target_zoom = 1,
center = [width / 2, height / 2],
extent = zoom.scaleExtent(),
translate = zoom.translate();
var view = {x: zoom.translate()[0], y: zoom.translate()[1], k: zoom.scale()};
target_zoom = sliderValue;
if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }
var translate0 = [];
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
var l = [];
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
zoom
.scale(view.k)
.translate([view.x, view.y]);
onZoom();
}
&#13;
body {
font: 10px sans-serif;
}
text {
font: 10px sans-serif;
}
.circle{
stroke: black;
stroke-width: 2px;
fill: white;
}
.point{
fill: goldenrod;
cursor: pointer;
}
.blip{
fill: black;
}
#slider{
width: 200px;
margin: auto;
}
&#13;
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<meta charset=utf-8 />
<title>d3.JS slider zoom</title>
</head>
<body>
<div id="slider"></div>
</body>
</html>
&#13;