如何在d3.js中的多个svg圈上重用相同的模式

时间:2017-05-09 16:25:37

标签: d3.js

我有一个项目,我们通过他们的纬度/长度将圆圈固定在世界地图上。每个圆圈应该是/ has / include / show a image:hasTheThing.png或doesNotHaveTheThing.png。随着应用中的条件发生变化,哪些圈子会改变哪些图像并需要动态更新。

现在我的代码如下。

  var defs = pointClustersG.append("defs");
  defs.append('pattern')
    .attr("id", "hasTheThing")
    .attr("patternUnits", "userSpaceOnUse")
    .attr("width", "10px")
    .attr("height", "10px")
    .append("svg:image")
      .attr("xlink:href", "images/hasTheThing.png")
      .attr("width", "10px")
      .attr("height", "10px")
      .attr("x", 0)
      .attr("y", 0);
  defs.append('pattern')
    .attr("id", "doesNotHaveTheThing")
    .attr("patternUnits", "userSpaceOnUse")
    .attr("width", "10px")
    .attr("height", "10px")
    .append("svg:image")
      .attr("xlink:href", "images/doesNotHaveTheThing.png")
      .attr("width", "10px")
      .attr("height", "10px")
      .attr("x", 0)
      .attr("y", 0);

  var point = pointClustersG.selectAll("circle")
    .data(allPointClusters)
    .enter()
    .append("circle")
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; })
    .attr("id", function(d) { return d.id; })
    .attr("class", "pointCluster")
    .attr("r", "5px")
    .attr("fill", function(d) { if(d.hasTheThing) { return "url(#hasTheThing)"} else { return "url(#doesNotHaveTheThing)"}});

无论我对x,y,高度,宽度和r值做什么,图案都会在圆圈内重复出现。但它在每个圆圈中重复的方式不同,这使我相信这不仅仅是不能正确地确定位置和尺寸。想知道我的代码是否错误,或者它是否是我的整体方法。如果它是选项2,那么任何人都有关于如何更好地做到这一点的建议吗?

2 个答案:

答案 0 :(得分:1)

经验表明,找到解决问题的最佳方法是:

  1. 与它斗争6小时
  2. 发布到SO
  3. 等待5分钟,然后自己神奇地弄明白
  4. 不确定这对任何不是我的人有多大用处,但以防它可以提供帮助:

    var points = pointClustersG.selectAll("image")
        .data(allPointClusters)
        .enter()
        .append("svg:image")
          .attr("xlink:href", "images/doesNotHaveTheThing.png")
          .attr("width", "10px")
          .attr("height", "10px")
          .attr("x",  function(d) { return d.x; })
          .attr("y",  function(d) { return d.y; })
          .attr("id", function(d) { return d.id; })
          .attr("class", "pointMarker");
    

    创建以下HTML:

    <image href="images/doesNotHaveTheThing.png" width="10px" height="10px" x="695.1694728311688" y="625.5607912558139" id="3480" class="pointMarker"></image>
    

    由于我使用js / jquery和朋友来决定哪个点需要什么图像,我只是同时更改href值。

答案 1 :(得分:1)

我看到你给自己写了一个答案,这很好,你有权利。但是,只是为了解释一下,你的问题......

  

......图案在圆圈内重复。

...可以通过将<pattern>的宽度和高度设置为1并删除userSpaceOnUse来修复:

defs.append('pattern')
    .attr("id", "hasTheThing")
    .attr("width", 1)
    .attr("height", 1)
    //etc...

根据Docs

  

与上面使用的gradientUnits属性一样,模式也有一个属性patternUnits,它指定这些属性将采用的单位。默认为“objectBoundingBox”,如上所述,因此值为1 会缩放到您应用该模式的对象的宽度/高度。 (强调我的)

使用部分代码检查此演示:

var svg = d3.select("svg");

var defs = svg.append("defs");

defs.append('pattern')
  .attr("id", "hasTheThing")
  .attr("width", 1)
  .attr("height", 1)
  .append("svg:image")
  .attr("xlink:href", "http://www.pressunion.org/wp-content/uploads/2016/11/1-2.jpg")
  .attr("width", 140)
  .attr("height", 140)
  .attr("y", -30)
  .attr("x", -20);

defs.append('pattern')
  .attr("id", "doesNotHaveTheThing")
  .attr("width", 1)
  .attr("height", 1)
  .append("svg:image")
  .attr("xlink:href", "https://s-media-cache-ak0.pinimg.com/736x/92/9d/3d/929d3d9f76f406b5ac6020323d2d32dc.jpg")
  .attr("width", 120)
  .attr("height", 120)
  .attr("x", -20)
  .attr("y", -10);

var circles = svg.selectAll("foo")
  .data(d3.range(5))
  .enter()
  .append("circle");

circles.attr("cy", 60)
  .attr("cx", function(d) {
    return 50 + 90 * d
  })
  .attr("r", 40)
  .attr("stroke", "#222")
  .attr("stroke-width", 3)
  .attr("fill", function(d) {
    return d % 2 === 0 ? "url(#hasTheThing)" : "url(#doesNotHaveTheThing)"
  });
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500"></svg>