d3:应用scale()变换时元素移动

时间:2016-03-17 05:53:43

标签: javascript css d3.js

我希望SVG元素在鼠标悬停时显得更大。应用CSS变换似乎是一种方便的方法,但它也可以翻译对象。如何使下面示例中的圆圈保持原始中心点?我尝试使用position: absolute;无效。



var dataset = [0, 2345786000, 10000000000];

var svg = d3.select("body").append("svg");
var w = 500, h = 200;
var padding = 50;
svg.attr("width", w)
   .attr("height", h);

// Background pattern 
var patternSize = 5;
svg.append("defs")
            .append("pattern")
            .attr("id", "dotPattern")
            .attr("patternUnits", "userSpaceOnUse")
            .attr("width", patternSize)
            .attr("height", patternSize)
            .append("circle")
            .attr("cx", patternSize / 2)
            .attr("cy", patternSize / 2)
            .attr("r", 2)
            .style("stroke", "none")
            .style("fill", "lightgrey")
            .style("opacity", 0.5);
   
var xScale = d3.time.scale()
    .domain([0, 10000000000])
    .range([padding, w-padding]);
var xAxis = d3.svg.axis()
    .scale(xScale)
    .ticks(5);
svg.append("g")
		.attr("class","axis")
    .attr("transform", "translate(0," + (h-padding) + ")")
    .call(xAxis);
    
var zoom = d3.behavior.zoom()
            .on("zoom", build)
            .scaleExtent([1, 20]);           
zoom.x(xScale);

var clipPath = svg.append("clipPath")
        .attr("id", "clip")
        .append("rect")
        .attr("x", padding)
        .attr("y", 0)
        .attr("width",w-2*padding)
        .attr("height", h-padding);
var zoomArea = svg.append("g")
         .attr("class", "zoomArea")
         .style("cursor","move")
         .attr("clip-path", "url(#clip)");
var zoomRect = zoomArea.append("rect")
     .attr("x", padding)
     .attr("y", 0)
     .attr("width", w-2*padding)
     .attr("height", h-padding)
     .style("fill", "url(#dotPattern)")
     .style("pointer-events", "all")
     .style("cursor","move")
     .call(zoom);

zoomArea.selectAll("circles")          
	.data(dataset)
  .enter()
  .append("circle")
  .attr("cx", function(d){
  	return xScale(d);
  })
  .attr("cy", h/2)
  .attr("r",10)
  .attr("fill","grey")
  .on("mouseover", function(){
  	d3.select(this)
    	.attr("transform", "scale(1.4)")
  })
  .on("mouseout", function(){
  	d3.select(this)
    	.attr("transform", "scale(1)")
  });

function build(){
					svg.select("g.axis").call(xAxis);
          d3.selectAll("circle")
          	  .attr("cx", function(d){
  							return xScale(d);
  						});
};    

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:3)

有两种方法可以解决这个问题。

1。要缩放圆圈而不更改其位置,请执行以下操作。

  

translate(-centerX *(factor-1), - centerY *(factor-1))scale(factor)

工作小提琴1:

&#13;
&#13;
var dataset = [0, 2345786000, 10000000000];

var svg = d3.select("body").append("svg");
var w = 500,
  h = 200;
var padding = 50;
svg.attr("width", w)
  .attr("height", h);

// Background pattern 
var patternSize = 5;
svg.append("defs")
  .append("pattern")
  .attr("id", "dotPattern")
  .attr("patternUnits", "userSpaceOnUse")
  .attr("width", patternSize)
  .attr("height", patternSize)
  .append("circle")
  .attr("cx", patternSize / 2)
  .attr("cy", patternSize / 2)
  .attr("r", 2)
  .style("stroke", "none")
  .style("fill", "lightgrey")
  .style("opacity", 0.5);

var xScale = d3.time.scale()
  .domain([0, 10000000000])
  .range([padding, w - padding]);

var xAxis = d3.svg.axis()
  .scale(xScale)
  .ticks(5);
svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(0," + (h - padding) + ")")
  .call(xAxis);

var zoom = d3.behavior.zoom()
  .on("zoom", build)
  .scaleExtent([1, 20]);
zoom.x(xScale);

var clipPath = svg.append("clipPath")
  .attr("id", "clip")
  .append("rect")
  .attr("x", padding)
  .attr("y", 0)
  .attr("width", w - 2 * padding)
  .attr("height", h - padding);
var zoomArea = svg.append("g")
  .attr("class", "zoomArea")
  .style("cursor", "move")
  .attr("clip-path", "url(#clip)");
var zoomRect = zoomArea.append("rect")
  .attr("x", padding)
  .attr("y", 0)
  .attr("width", w - 2 * padding)
  .attr("height", h - padding)
  .style("fill", "url(#dotPattern)")
  .style("pointer-events", "all")
  .style("cursor", "move")
  .call(zoom);

zoomArea.selectAll("circles")
  .data(dataset)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return xScale(d);
  })
  .attr("cy", h / 2)
  .attr("r", 10)
  .attr("fill", "grey")
  .on("mouseover", function(d) {
    var x = xScale(d),
      y = h / 2,
      factor = 2;
    var tx = -x * (factor - 1),
      ty = -y * (factor - 1);
    d3.select(this).transition().duration(50)
      .attr("transform", "translate(" + tx + "," + ty + ") scale(" + factor + ")");
  })
  .on("mouseleave", function(d) {
    var x = xScale(d),
      y = h / 2,
      factor = 1;
    var tx = -x * (factor - 1),
      ty = -y * (factor - 1);
    d3.select(this).transition().duration(50)
      .attr("transform", "translate(" + tx + "," + ty + ") scale(" + factor + ")");
  });

function build() {
  svg.select("g.axis").call(xAxis);
  d3.selectAll("circle")
    .attr("cx", function(d) {
      return xScale(d);
    });
};
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

2。由于您使用的是圆形,因此您可以轻松地增加圆的半径以缩放它们。

工作小提琴2:

&#13;
&#13;
var dataset = [0, 2345786000, 10000000000];

var svg = d3.select("body").append("svg");
var w = 500,
  h = 200;
var padding = 50;
svg.attr("width", w)
  .attr("height", h);

// Background pattern 
var patternSize = 5;
svg.append("defs")
  .append("pattern")
  .attr("id", "dotPattern")
  .attr("patternUnits", "userSpaceOnUse")
  .attr("width", patternSize)
  .attr("height", patternSize)
  .append("circle")
  .attr("cx", patternSize / 2)
  .attr("cy", patternSize / 2)
  .attr("r", 2)
  .style("stroke", "none")
  .style("fill", "lightgrey")
  .style("opacity", 0.5);

var xScale = d3.time.scale()
  .domain([0, 10000000000])
  .range([padding, w - padding]);
var xAxis = d3.svg.axis()
  .scale(xScale)
  .ticks(5);
svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(0," + (h - padding) + ")")
  .call(xAxis);

var zoom = d3.behavior.zoom()
  .on("zoom", build)
  .scaleExtent([1, 20]);
zoom.x(xScale);

var clipPath = svg.append("clipPath")
  .attr("id", "clip")
  .append("rect")
  .attr("x", padding)
  .attr("y", 0)
  .attr("width", w - 2 * padding)
  .attr("height", h - padding);
var zoomArea = svg.append("g")
  .attr("class", "zoomArea")
  .style("cursor", "move")
  .attr("clip-path", "url(#clip)");
var zoomRect = zoomArea.append("rect")
  .attr("x", padding)
  .attr("y", 0)
  .attr("width", w - 2 * padding)
  .attr("height", h - padding)
  .style("fill", "url(#dotPattern)")
  .style("pointer-events", "all")
  .style("cursor", "move")
  .call(zoom);

zoomArea.selectAll("circles")
  .data(dataset)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return xScale(d);
  })
  .attr("cy", h / 2)
  .attr("r", 10)
  .attr("fill", "grey")
  .on("mouseover", function() {
    d3.select(this).transition().duration(50).attr("r", 20);
  })
  .on("mouseleave", function() {
    d3.select(this).transition().duration(50).attr("r", 10);
  });

function build() {
  svg.select("g.axis").call(xAxis);
  d3.selectAll("circle")
    .attr("cx", function(d) {
      return xScale(d);
    });
};
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;