简体   繁体   English

如何使用 D3.js 将图像添加到 svg 容器

[英]How to add an image to an svg container using D3.js

I've created a sample Asp.Net MVC 4 application where I've used D3.js to append an SVG element and then inside the SVG I've appended a text element (see code below).我创建了一个示例 Asp.Net MVC 4 应用程序,其中我使用 D3.js 附加了一个 SVG 元素,然后在 SVG 内附加了一个文本元素(请参阅下面的代码)。 This all works fine until I try to append an img to the SVG using a local png file.这一切正常,直到我尝试使用本地 png 文件将 img 附加到 SVG。 The img gets appended to the DOM, but the img is not rendered on the page. img 被附加到 DOM,但 img 未呈现在页面上。 Any ideas what I'm doing wrong here, and how to go about fixing it?任何想法我在这里做错了什么,以及如何解决它?

@{
    ViewBag.Title = "Home Page";
}

<script src="~/Scripts/d3.v3.js"></script>
<script type="text/javascript">
    var svg = d3.select("body")
        .append("svg")
        .attr("width", 200)
        .attr("height", 100)
        .style("border", "1px solid black");

    var text = svg.selectAll("text")
        .data([0])
        .enter()
        .append("text")
        .text("Testing")
        .attr("x", "40")
        .attr("y", "60");

    var imgs = svg.selectAll("img").data([0]);
    imgs.enter()
        .append("img")
        .attr("xlink:href", "@Url.Content("~/Content/images/icons/refresh.png")")
        .attr("x", "60")
        .attr("y", "60")
        .attr("width", "20")
        .attr("height", "20");

</script>

@Richard Marr - Below is an attempt to do the same thing in straight HTML, which gives me the same result. @Richard Marr - 下面是尝试在纯 HTML 中做同样的事情,这给了我相同的结果。 I'm not sure about my code to get the refresh.png file from the local drive this way.我不确定我的代码以这种方式从本地驱动器获取 refresh.png 文件。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script src="http://d3js.org/d3.v2.js"></script>

    </head>
    <body>
        <script type="text/javascript">
            var svg = d3.select("body")
                .append("svg")
                .attr("width", 200)
                .attr("height", 100)
                .style("border", "1px solid black");

            var text = svg.selectAll("text")
                .data([0])
                .enter()
                .append("text")
                .text("Testing")
                .attr("x", "40")
                .attr("y", "60");

            var imgs = svg.selectAll("img").data([0]);
                imgs.enter()
                .append("svg:img")
                .attr("xlink:href", "file:///D:/d3js_projects/refresh.png")
                .attr("x", "60")
                .attr("y", "60")
                .attr("width", "20")
                .attr("height", "20");

        </script>
    </body>
</html>
nodeEnter.append("svg:image")
.attr('x', -9)
.attr('y', -12)
.attr('width', 20)
.attr('height', 24)
.attr("xlink:href", "resources/images/check.png")

In SVG (contrasted with HTML), you will want to use <image> instead of <img> for elements.在 SVG 中(与 HTML 相比),您将希望对元素使用<image>而不是<img>

Try changing your last block with:尝试更改您的最后一个块:

var imgs = svg.selectAll("image").data([0]);
            imgs.enter()
            .append("svg:image")
            ...

My team also wanted to add images inside d3-drawn circles, and came up with the following ( fiddle ):我的团队还想在 d3 绘制的圆圈内添加图像,并提出以下(小提琴):

index.html:索引.html:

<!doctype html>
<html>
<head>
  <link rel="stylesheet" type="text/css" href="timeline.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
  <script src="https://code.jquery.com/jquery-2.2.4.js"
    integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
    crossorigin="anonymous"></script>
  <script src="./timeline.js"></script>
</head>
  <body>
    <div class="timeline"></div>
  </body>
</html>

timeline.css:时间线.css:

.axis path,
.axis line,
.tick line,
.line {
  fill: none;
  stroke: #000000;
  stroke-width: 1px;
}

timeline.js:时间线.js:

// container target
var elem = ".timeline";

var props = {
  width: 1000,
  height: 600,
  class: "timeline-point",

  // margins
  marginTop: 100,
  marginRight: 40,
  marginBottom: 100,
  marginLeft: 60,

  // data inputs
  data: [
    {
      x: 10,
      y: 20,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "a"
    },
    {
      x: 20,
      y: 10,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "b"
    },
    {
      x: 60,
      y: 30,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "c"
    },
    {
      x: 40,
      y: 30,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "d"
    },
    {
      x: 50,
      y: 70,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "e"
    },
    {
      x: 30,
      y: 50,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "f"
    },
    {
      x: 50,
      y: 60,
      key: "a",
      image: "https://unsplash.it/300/300",
      id: "g"
    }
  ],

  // y label
  yLabel: "Y label",
  yLabelLength: 50,

  // axis ticks
  xTicks: 10,
  yTicks: 10

}

// component start
var Timeline = {};

/***
*
* Create the svg canvas on which the chart will be rendered
*
***/

Timeline.create = function(elem, props) {

  // build the chart foundation
  var svg = d3.select(elem).append('svg')
      .attr('width', props.width)
      .attr('height', props.height);

  var g = svg.append('g')
      .attr('class', 'point-container')
      .attr("transform",
              "translate(" + props.marginLeft + "," + props.marginTop + ")");

  var g = svg.append('g')
      .attr('class', 'line-container')
      .attr("transform", 
              "translate(" + props.marginLeft + "," + props.marginTop + ")");

  var xAxis = g.append('g')
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (props.height - props.marginTop - props.marginBottom) + ")");

  var yAxis = g.append('g')
    .attr("class", "y axis");

  svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("y", 1)
    .attr("x", 0 - ((props.height - props.yLabelLength)/2) )
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text(props.yLabel);

  // add placeholders for the axes
  this.update(elem, props);
};

/***
*
* Update the svg scales and lines given new data
*
***/

Timeline.update = function(elem, props) {
  var self = this;
  var domain = self.getDomain(props);
  var scales = self.scales(elem, props, domain);

  self.drawPoints(elem, props, scales);
};


/***
*
* Use the range of values in the x,y attributes
* of the incoming data to identify the plot domain
*
***/

Timeline.getDomain = function(props) {
  var domain = {};
  domain.x = props.xDomain || d3.extent(props.data, function(d) { return d.x; });
  domain.y = props.yDomain || d3.extent(props.data, function(d) { return d.y; });
  return domain;
};


/***
*
* Compute the chart scales
*
***/

Timeline.scales = function(elem, props, domain) {

  if (!domain) {
    return null;
  }

  var width = props.width - props.marginRight - props.marginLeft;
  var height = props.height - props.marginTop - props.marginBottom;

  var x = d3.scale.linear()
    .range([0, width])
    .domain(domain.x);

  var y = d3.scale.linear()
    .range([height, 0])
    .domain(domain.y);

  return {x: x, y: y};
};


/***
*
* Create the chart axes
*
***/

Timeline.axes = function(props, scales) {

  var xAxis = d3.svg.axis()
    .scale(scales.x)
    .orient("bottom")
    .ticks(props.xTicks)
    .tickFormat(d3.format("d"));

  var yAxis = d3.svg.axis()
    .scale(scales.y)
    .orient("left")
    .ticks(props.yTicks);

  return {
    xAxis: xAxis,
    yAxis: yAxis
  }
};


/***
*
* Use the general update pattern to draw the points
*
***/

Timeline.drawPoints = function(elem, props, scales, prevScales, dispatcher) {
  var g = d3.select(elem).selectAll('.point-container');
  var color = d3.scale.category10();

  // add images
  var image = g.selectAll('.image')
    .data(props.data)

  image.enter()
    .append("pattern")
    .attr("id", function(d) {return d.id})
    .attr("class", "svg-image")
    .attr("x", "0")
    .attr("y", "0")
    .attr("height", "70px")
    .attr("width", "70px")
    .append("image")
      .attr("x", "0")
      .attr("y", "0")
      .attr("height", "70px")
      .attr("width", "70px")
      .attr("xlink:href", function(d) {return d.image})

  var point = g.selectAll('.point')
    .data(props.data);

  // enter
  point.enter()
    .append("circle")
      .attr("class", "point")
      .on('mouseover', function(d) {
        d3.select(elem).selectAll(".point").classed("active", false);
        d3.select(this).classed("active", true);
        if (props.onMouseover) {
          props.onMouseover(d)
        };
      })
      .on('mouseout', function(d) {
        if (props.onMouseout) {
          props.onMouseout(d)
        };
      })

  // enter and update
  point.transition()
    .duration(1000)
    .attr("cx", function(d) {
      return scales.x(d.x); 
    })
    .attr("cy", function(d) { 
      return scales.y(d.y); 
    })
    .attr("r", 30)
    .style("stroke", function(d) {
      if (props.pointStroke) {
        return d.color = props.pointStroke;
      } else {
        return d.color = color(d.key);
      }
    })
    .style("fill", function(d) {
      if (d.image) {
        return ("url(#" + d.id + ")");
      }

      if (props.pointFill) {
        return d.color = props.pointFill;
      } else {
        return d.color = color(d.key);
      }
    });

  // exit
  point.exit()
    .remove();

  // update the axes
  var axes = this.axes(props, scales);
  d3.select(elem).selectAll('g.x.axis')
    .transition()
    .duration(1000)
    .call(axes.xAxis);

  d3.select(elem).selectAll('g.y.axis')
    .transition()
    .duration(1000)
    .call(axes.yAxis);
};


$(document).ready(function() {
  Timeline.create(elem, props);
})

I do not know why, but the image should not be duplicated, tripled, etc ... should remove the previous one and load it again but with another rotation data.我不知道为什么,但图像不应该被复制,三倍等等......应该删除前一个并再次加载它但使用另一个旋转数据。 This is my code:这是我的代码:

data.csv enter image description here data.csv在此处输入图像描述

d3.csv("data/data.csv").then(function(data){
//console.log(data);
// Clean data
formattedData = data.map(function(id){
id.rot_1 = +id.rot_1;
        id.trans_1 = +id.trans_1;
        return id;
});
// First run of the visualization
update(formattedData[0]);})

$("#play-button")
.on("click", function(){
    var button = $(this);
    if (button.text() == "Play"){
        button.text("Pause");
        interval = setInterval(step, 1000);            
    }
    else {
        button.text("Play");
        clearInterval(interval);
    }})

function step(){
// At the end of our data, loop back
time = (time < 76) ? time+1 : 0
update(formattedData[time]); }

function update(data) {
// Standard transition time for the visualization
var t = d3.transition()
    .duration(1000);

//console.log(d3.selectAll(data));    
//console.log(data)

// original
var imgs1 = g.append("image") // en vez de g es svg
.attr("xlink:href", "img/picturetest.png");

// EXIT old elements not present in new data.
imgs1.exit()
    .attr("class", "exit")
    .selectAll("svg:image")
    .remove();

//console.log(data)

// ENTER new elements present in new data.
imgs1.enter()
    .append("svg:image") // svg:image
    //.attr("xlink:href", "img/picturetest.png")
    .attr("class", "enter")
    .merge(imgs1)
    .transition(t)
        .attr("x", 0) // 150
        .attr("y", 0) // 80
        .attr("width", 200)
        .attr("height", 200)
        .attr("transform", "rotate("+data.rot_1+") translate("+data.trans_1+")" ); }`
 var svg = d3.select("body")
        .append("svg")
        .style("width", 200)
        .style("height", 100)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM