【问题标题】:How to add an image to an svg container using D3.js如何使用 D3.js 将图像添加到 svg 容器
【发布时间】:2013-01-12 03:10:34
【问题描述】:

我创建了一个示例 Asp.Net MVC 4 应用程序,其中我使用 D3.js 附加了一个 SVG 元素,然后在 SVG 内部附加了一个文本元素(请参见下面的代码)。在我尝试使用本地 png 文件将 img 附加到 SVG 之前,这一切都很好。 img 被附加到 DOM,但 img 不会呈现在页面上。任何想法我在这里做错了什么,以及如何解决它?

@{
    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 - 下面是尝试在纯 HTML 中做同样的事情,这给了我相同的结果。我不确定我的代码是否可以通过这种方式从本地驱动器获取 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>

【问题讨论】:

  • 您能否通过在常规 HTML 中演示该问题来排除此问题的 ASP.NET 方面?
  • 在 SVG 中,我相信你想要“image”而不是“img”作为元素。或许可以试试。
  • @cmonkey - 效果很好,如果您将此作为答案发布,我会将其标记为正确答案。
  • 如果您将多个图像推进到多个 SVG 元素中,请建立一个模式,如此处所示。 stackoverflow.com/questions/19202450/…

标签: javascript asp.net-mvc-4 svg d3.js


【解决方案1】:

在 SVG(与 HTML 对比)中,您需要使用 &lt;image&gt; 而不是 &lt;img&gt; 来表示元素。

尝试更改您的最后一个块:

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

【讨论】:

  • 如果您显示 xlink:href 标签会更好,用户需要使用您的解决方案。此外,不需要数据。
  • 请同时添加xlink-href,width,height 部分
【解决方案2】:
nodeEnter.append("svg:image")
.attr('x', -9)
.attr('y', -12)
.attr('width', 20)
.attr('height', 24)
.attr("xlink:href", "resources/images/check.png")

【讨论】:

    【解决方案3】:
     var svg = d3.select("body")
            .append("svg")
            .style("width", 200)
            .style("height", 100)
    

    【讨论】:

      【解决方案4】:

      我的团队还想在 d3 绘制的圆圈内添加图像,并提出以下 (fiddle):

      index.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>
      

      时间线.css:

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

      timeline.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);
      })
      

      【讨论】:

        【解决方案5】:

        我不知道为什么,但图像不应该被复制、三倍等......应该删除前一个并再次加载它,但使用另一个旋转数据。这是我的代码:

        数据.csv enter image description here

        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+")" ); }`
        

        【讨论】:

          猜你喜欢
          • 2016-03-14
          • 2021-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-07
          • 2017-06-29
          • 2020-02-13
          • 2017-12-18
          相关资源
          最近更新 更多