数据使用自定义键加入无法正常工作 [英] Data Join with Custom Key does not work as expected

查看:140
本文介绍了数据使用自定义键加入无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用d3绘制一些点。我想根据一些条件改变所有点的形状。连接看起来有点像这样:

  var data = [{x:10,y:10},{x:20 ,y:30}]; 
var shape =rect;
...
var point = svg.selectAll(。point)
.data(data,function(d,idx){returnrow_+ idx +_shape_+ shape;})
;

d3 enter()和exit()选择似乎不反映由shape 改变。



小提琴在这里: http:// jsfiddle.net/schmoo2k/jcpctbty/

解决方案

您需要注意的是,键功能是在选择 this 作为SVG元素,然后选择数据数组为 this



我想也许这是你想要做的事情。



  var data = [{x:10,y:10},{x:20,y:30}]; var svg = d3.select(body)append(svg).attr(width 500).attr(height,500); function update(data,shape){var point = svg.selectAll(。point).data(data,function(d,idx){var key =row_ + idx +_shape_+(Array.isArray(this)?Data:+ shape:d3.select(this).attr(shape)); alert(key); return key;}); alert(enter selection size:+ point.enter()。size()); point.enter()。append(shape).attr(class,point).style(fill,red).attr(shape,shape)开关(形状){caserect:point.attr(x,function(d){return dx;}).attr(y,function(d){return dy;}).attr ,5).attr(height,5);打破; casecircle:point.attr(cx,function(d){return d.x;}).attr(cy,function(d){return d.y;}).attr(r,5)打破; } point.exit()。remove();} update(data,rect); setTimeout(function(){update(data,circle);},5000);  pre> 

  text {font:bold 48px monospace;}输入{fill:green;}。 :#333;}  

 < script src = ://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js>< / script>  

div>






抽象版本



只是为了整理这里是一个更可读和惯用的版本(包括修复的文本元素的问题)...



  var data = [{x:10 ,y:10,},{x:20,y:30,}]; var svg = d3.select(body)。append(svg).attr(width,500).attr高度,500),marker = Marker(); function update(data,shape){var point = svg.selectAll(。point).data(data,key(shape,shape)),enter = point .enter()。append(g).attr(class,point).attr(transform,function(d){returntranslate(+ dx +,+ dy +) }).attr(shape,shape); enter.append(shape).style(fill,red).attr(marker.width [shape],5).attr(marker.height [shape],5); enter.append(text).attr({class:title,dx:10,text-anchor:start})。 point.exit()。remove();} update(data,rect); setTimeout(function(){update(data,circle);},2000); function Marker rect:width,circle:r},height:{rect:height,circle:r},shape:function(d){return d.shape},};} value){//连接数据和元素,其中attr的值是value function _phase(that){return Array.isArray(that)? data:element; } function _Type(that){return {data:value,get element(){return d3.select(that).attr(attr)}}} return function(d,i,j){var _value = return i +_+ _value [_phase(this)]; };}  

 < script src =https: /cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js\"></script>






广义的数据驱动方法



div class =snippetdata-lang =jsdata-hide =false>

  var data = [{x:10,y:10,},{x:20,y:30,}]; var svg = d3.select(body)append(svg) .attr(width,500).attr(height,500),marker = Marker(); function update(data,shape){//数据驱动的方法data.forEach d.shape = shape [i]}); var log = [],point = svg.selectAll(。point).data(data,key({shape:marker.shape,transform:marker.transform},log)),// UPDATE update = point.classed (update,true),updateSize = update.size(); update.selectAll(text)。transition()。duration(1000).style(fill,#ccc); update.selectAll(。shape)。transition()。duration(1000).style(fill,#ccc)// ENTER var enter = point.enter()。append(g).classed (point enter,true).attr(transform,marker.dock).attr(shape,marker.shape),// UPDATE + ENTER // ...此时不需要updateAndEnter = classed(update-enter,true); // EXIT var exit = point.exit()。classed(exit,true); exit.selectAll(text)。transition()。duration(1000).style(fill,red); exit.selectAll(。shape)。transition()。duration(1000).style(fill,red); exit.transition()。delay(1000。)。duration(1000).attr(transform,marker.dock).remove(); // ADJUSTMENTS enter.each(function(d){//为每个数据元素添加指定的形状//在每个数据元素中添加,以便attr可以是数据的函数d3.select(this).append(marker.shape d)).style(fill,green).classed(shape,true).attr(marker.width [marker.shape(d)],5).attr(marker.height [marker.shape (d)],5)}); enter.append(text).attr({class:title,dx:10,text-anchor:start}).text(marker.shape).style(fill绿色).style(opacity,1); enter.transition()。delay(1000).duration(2000).attr(transform,marker.transform);} data = generateData(40,10)update(data,data.map {return [rect,circle] [Math.round(Math.random())]})); setInterval(function rect,circle] [Math.round(Math.random())]}));},5000); function generateData(n,p){var values = []; for(var i = 0; i  

  text {font:bold 12px monospace; fill:black;}  

 < script src =https ://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js>  


I am plotting some points using d3. I want to change the shape off all the points based on some condition. The join looks a bit like this:

var data=[{x:10,y:10}, {x:20, y:30}];
var shape = "rect";
...
var point = svg.selectAll(".point")
  .data(data, function(d, idx) { return "row_" + idx + "_shape_" + shape;})
;

The d3 enter() and exit() selections do not seem to reflect any changes caused by "shape" changing.

Fiddle is here: http://jsfiddle.net/schmoo2k/jcpctbty/

解决方案

You need to be aware that the key function is calculated on the selection with this as the SVG element and then on the data with the data array as this.

I think maybe this is what you are trying to do...

var data = [{
  x: 10,
  y: 10
}, {
  x: 20,
  y: 30
}];

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

function update(data, shape) {
  var point = svg.selectAll(".point")
    .data(data, function(d, idx) {
      var key = "row_" + idx + "_shape_" + (Array.isArray(this) ? "Data: " + shape :
        d3.select(this).attr("shape"));
      alert(key);
      return key;
    });

  alert("enter selection size: " + point.enter().size());

  point.enter().append(shape)
    .attr("class", "point")
    .style("fill", "red")
    .attr("shape", shape);
  switch (shape) {
    case "rect":
      point.attr("x", function(d) {
          return d.x;
        })
        .attr("y", function(d) {
          return d.y;
        })
        .attr("width", 5)
        .attr("height", 5);
      break;
    case "circle":
      point.attr("cx", function(d) {
          return d.x;
        })
        .attr("cy", function(d) {
          return d.y;
        })
        .attr("r", 5);
      break;
  }
  point.exit().remove();
}

update(data, "rect");

setTimeout(function() {
  update(data, "circle");
}, 5000);

text {
  font: bold 48px monospace;
}
.enter {
  fill: green;
}
.update {
  fill: #333;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>


Abstracted version

Just to tidy things up here is a more readable and idiomatic version (including fixing a problem with the text element)...

var data = [{
  x: 10,
  y: 10,
}, {
  x: 20,
  y: 30,
}];

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

function update(data, shape) {
  var point = svg.selectAll(".point")
    .data(data, key("shape", shape)),

    enter = point.enter().append("g")
    .attr("class", "point")
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")"
    })
    .attr("shape", shape);

  enter.append(shape)
    .style("fill", "red")
    .attr(marker.width[shape], 5)
    .attr(marker.height[shape], 5);

  enter.append("text")
    .attr({
      "class": "title",
      dx: 10,
      "text-anchor": "start"
    })
    .text(shape);

  point.exit().remove();
}

update(data, "rect");

setTimeout(function() {
  update(data, "circle");
}, 2000);

function Marker() {
  return {
    width: {
      rect: "width",
      circle: "r"
    },
    height: {
      rect: "height",
      circle: "r"
    },
    shape: function(d) {
      return d.shape
    },
  };
}

function key(attr, value) {
  //join data and elements where value of attr is value
  function _phase(that) {
    return Array.isArray(that) ? "data" : "element";
  }

  function _Type(that) {
    return {
      data: value,
      get element() {
        return d3.select(that).attr(attr)
      }
    }
  }
  return function(d, i, j) {
    var _value = _Type(this)
    return i + "_" + _value[_phase(this)];
  };
}

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


Generalised, data-driven approach

var data = [{
  x: 10,
  y: 10,
}, {
  x: 20,
  y: 30,
}];

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

function update(data, shape) {
  //data-driven approach
  data.forEach(function(d, i) {
    d.shape = shape[i]
  });

  var log = [],
    point = svg.selectAll(".point")
    .data(data, key({
      shape: marker.shape,
      transform: marker.transform
    }, log)),

    //UPDATE
    update = point.classed("update", true),
    updateSize = update.size();
  update.selectAll("text").transition().duration(1000).style("fill", "#ccc");
  update.selectAll(".shape").transition().duration(1000).style("fill", "#ccc")

  //ENTER
  var enter = point.enter().append("g")
    .classed("point enter", true)
    .attr("transform", marker.dock)
    .attr("shape", marker.shape),

    //UPDATE+ENTER
    // ... not required on this occasion

    updateAndEnter = point.classed("update-enter", true);

  //EXIT
  var exit = point.exit().classed("exit", true);
  exit.selectAll("text").transition().duration(1000).style("fill", "red");
  exit.selectAll(".shape").transition().duration(1000).style("fill", "red");
  exit.transition().delay(1000.).duration(1000)
    .attr("transform", marker.dock)
    .remove();

  //ADJUSTMENTS
  enter.each(function(d) {
    //append the specified shape for each data element
    //wrap in each so that attr can be a function of the data
    d3.select(this).append(marker.shape(d))
      .style("fill", "green")
      .classed("shape", true)
      .attr(marker.width[marker.shape(d)], 5)
      .attr(marker.height[marker.shape(d)], 5)
  });

  enter.append("text")
    .attr({
      "class": "title",
      dx: 10,
      "text-anchor": "start"
    })
    .text(marker.shape)
    .style("fill", "green")
    .style("opacity", 1);

  enter.transition().delay(1000).duration(2000)
    .attr("transform", marker.transform);
}
data = generateData(40, 10)
update(data, data.map(function(d, i) {
  return ["rect", "circle"][Math.round(Math.random())]
}));

setInterval(function() {
  update(data, data.map(function(d, i) {
    return ["rect", "circle"][Math.round(Math.random())]
  }));
}, 5000);

function generateData(n, p) {
  var values = [];

  for (var i = 0; i < n; i++) {
    values.push({
      x: (i + 1) * p,
      y: (i + 1) * p
    })
  }
  return values;
};

function Marker() {
  return {
    x: {
      rect: "x",
      circle: "cx"
    },
    y: {
      rect: "y",
      circle: "cy"
    },
    width: {
      rect: "width",
      circle: "r"
    },
    height: {
      rect: "height",
      circle: "r"
    },
    shape: function(d) {
      return d.shape
    },
    transform: function(d) {
      return "translate(" + f(d.x) + "," + f(d.y) + ")"
    },
    dock: function(d) {
      return "translate(" + (d.x + 800) + "," + (d.y + 100) + ")"
    }
  };

  function f(x) {
    return d3.format(".0f")(x)
  }
}

function key(attr, value, log) {
  //join data and elements where value of attr is value
  function _phase(that) {
    return Array.isArray(that) ? "data" : "element";
  }

  function _Key(that) {
    if (plural) {
      return {
        data: function(d, i, j) {
          var a, key = "";
          for (a in attr) {
            key += (typeof attr[a] === "function" ? attr[a](d, i, j) : attr[a]);
          }
          return key;
        },
        element: function() {
          var a, key = "";
          for (a in attr) {
            key += d3.select(that).attr(a);
          }
          return key;
        }
      }
    } else {
      return {
        data: function(d, i, j) {
          return typeof value === "function" ? value(d, i, j) : value;
        },
        element: function() {
          return d3.select(that).attr(attr)
        }
      }
    }
  }

  var plural = typeof attr === "object";
  if (plural && arguments.length === 2) log = value;

  return function(d, i, j) {
    var key = _Key(this)[_phase(this)](d, i, j);
    if (log) log.push(i + "_" + _phase(this) + "_" + key);
    return key;
  };
}

text {
  font: bold 12px monospace;
  fill: black;
}

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

这篇关于数据使用自定义键加入无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆