d3 svg 阴影差异

Posted

技术标签:

【中文标题】d3 svg 阴影差异【英文标题】:d3 svg shadow difference 【发布时间】:2021-12-14 11:52:33 【问题描述】:

我制作了一个加密气泡的副本,我希望硬币像气泡一样漂浮,现在我遇到了一个正方形完全填充的问题,有些不是因为阴影吗?我该如何解决?

import React,  Component  from "react";
import "../styles/style.css";
import $ from "jquery";
import * as d3 from "d3";

const crypto = require("../data/cryptoData.json");
const coins = [];
var data = [];

for (let i = 0; i < crypto.length; i++) 
  var coin = crypto[i];
  var minplus = String(coin.market_data.price_change_percentage_24h);
  if (minplus.includes("-")) 
    coin["color"] = "red";
   else 
    coin["color"] = "green";
  
  coins.push(coin);


coins.forEach((coin) => 
  var text = coin.symbol;
  var r = coin.market_data.market_cap.usd / 3500000000;
  if (r < 5) 
    r = 20;
  
  data.push(
    text: text,
    category: coin.market_data.price_change_percentage_24h + "%",
    image: coin.image.large,
    color: coin.color,
    r: r,
    r_change_1: coin.market_data.market_cap.USD / 3500000000,
    r_change_2: coin.market_data.market_cap.USD / 3500000000,
  );
);

function collide(alpha) 
  var quadtree = d3.geom.quadtree(data);
  return function (d) 
    var r = d.r + 10,
      nx1 = d.x - r,
      nx2 = d.x + r,
      ny1 = d.y - r,
      ny2 = d.y + r;
    quadtree.visit(function (quad, x1, y1, x2, y2) 
      if (quad.point && quad.point !== d) 
        var x = d.x - quad.point.x,
          y = d.y - quad.point.y,
          l = Math.sqrt(x * x + y * y),
          r = d.r + quad.point.r;
        if (l < r) 
          l = ((l - r) / l) * (1 + alpha);
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x += x;
          quad.point.y += y;
        
      
      return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
    );
  ;


const bubbleCloud = (element) => 
  var container = d3.select(".bubble-cloud");
  var $container = $(".bubble-cloud");
  var containerWidth = $container.width();
  var containerHeight = $container.height();
  var svgContainer = container
    .append("svg")
    .attr("width", containerWidth)
    .attr("height", containerHeight)
    .call(
      d3.behavior.zoom().on("zoom", function () 
        node.attr(
          "transform",
          "translate(" +
            d3.event.translate +
            ")" +
            " scale(" +
            d3.event.scale +
            ")"
        );
      )
    );

  // prepare layout
  var force = d3.layout
    .force()
    .size([containerWidth, containerHeight])
    .gravity(0)
    .charge(0)
    .friction(1);
  // load data
  force.nodes(data).start();

  // create item groups
  var node = svgContainer
    .selectAll(".node")
    .data(data)
    .enter()
    .append("g")
    .attr("class", "node")
    .call(force.drag);

  // create circles
  var defs = node.append("defs");

  function makeFiter(id, color) 
    //make a filter if filter id not present
    if (defs.selectAll("#" + id).empty()) 
      var filter = defs.append("filter").attr("id", id).attr("height", "130%");

      filter
        .append("feGaussianBlur")
        .attr("in", "SourceAlpha")
        .attr("stdDeviation", 20)
        .attr("result", "blur");

      filter
        .append("feOffset", 0)
        .attr("in", "blur")
        .attr("result", "offsetBlur");

      filter
        .append("feFlood")
        .attr("in", "offsetBlur")
        .attr("flood-color", color)
        .attr("flood-opacity", "1")

        .attr("result", "offsetColor");

      filter
        .append("feComposite")
        .attr("in", "offsetColor")
        .attr("in2", "offsetBlur")
        .attr("operator", "in")
        .attr("result", "offsetBlur");

      var feMerge = filter.append("feMerge");

      feMerge.append("feMergeNode").attr("in", "offsetBlur");
      feMerge.append("feMergeNode").attr("in", "SourceGraphic");
    
    return "url(#" + id + ")"; //return the filter id
  

  function getFilter(d) 
    if (d.color === "red") 
      return makeFiter("fill-text-red", "red");
     else if (d.color === "green") 
      return makeFiter("fill-text-green", "green");
    
  

  defs
    .selectAll(null)
    .data(data)
    .enter()
    .append("pattern")
    .attr("id", function (d) 
      return d.image;
    )
    .attr("height", "100%")
    .attr("width", "100%")
    .attr("patternContentUnits", "objectBoundingBox")
    .append("image")
    .attr("height", 1)
    .attr("width", 1)
    .attr("preserveAspectRatio", "none")
    .attr("xlink:href", function (d) 
      return d.image;
    );

  node
    .append("circle")
    .attr("r", 1e-6)
    .style("fill", function (d) 
      return "url(#" + d.image + ")";
    )
    .attr("filter", function (d) 
      return getFilter(d);
    );

  // create labels
  node
    .append("text")
    .text(function (d) 
      return d.text;
    )
    .classed("text", true)
    .style(
      fill: "#ffffff",
      "text-anchor": "middle",
      "font-size": "1vw",
      "font-weight": "bold",
      "text-transform": "uppercase",
      "font-family": "Tahoma, Arial, sans-serif",
    )
    .attr("stroke", "black")
    .attr("stroke-width", "1px");

  node
    .append("text")
    .text(function (d) 
      return d.category;
    )
    .classed("category", true)
    .style(
      fill: "#ffffff",
      "text-anchor": "middle",
      "font-size": "12px",
      "font-weight": "bold",
      "text-transform": "uppercase",
      "font-family": "Tahoma, Arial, sans-serif",
    )
    .attr("stroke", "black")
    .attr("stroke-width", "1px");

  node
    //.append("line")
    //.classed("line", true)
    //.attr(
    //  x1: 0,
    //  y1: 0,
    //  x2: 0,
    //  y2: 0,
    //)
    .attr("stroke-width", 1)
    .attr("stroke", function (d) 
      return d.stroke;
    );

  // put circle into movement
  force.on("tick", function (e) 
    d3.selectAll("circle")
      .each(collide(0.1))
      .attr("r", function (d) 
        return d.r;
      )
      .attr("cx", function (d) 
        // boundaries
        if (d.x <= d.r) 
          d.x = d.r + 1;
        
        if (d.x >= containerWidth - d.r) 
          d.x = containerWidth - d.r - 1;
        
        return d.x;
      )
      .attr("cy", function (d) 
        // boundaries
        if (d.y <= d.r) 
          d.y = d.r + 1;
        
        if (d.y >= containerHeight - d.r) 
          d.y = containerHeight - d.r - 1;
        
        return d.y;
      );

    d3.selectAll("line").attr(
      x1: function (d) 
        return d.x - d.r + 10;
      ,
      y1: function (d) 
        return d.y;
      ,
      x2: function (d) 
        return d.x + d.r - 10;
      ,
      y2: function (d) 
        return d.y;
      ,
    );

    d3.selectAll(".text")
      .attr("x", function (d) 
        return d.x;
      )
      .attr("y", function (d) 
        return d.y - 10;
      );

    d3.selectAll(".category")
      .attr("x", function (d) 
        return d.x;
      )
      .attr("y", function (d) 
        return d.y + 20;
      );
    force.alpha(0.1);
  );
;

class Bubbles extends Component 
  render() 
    return <div className="bubble-cloud" ref=bubbleCloud></div>;
  

export default Bubbles;

我希望它看起来像以太坊图像,但不知道我必须改变什么......

需要更改哪些属性?

【问题讨论】:

【参考方案1】:

使用较小的 stdDeviation 或扩大您的过滤区域。这样的事情可能会起作用:

var filter = defs.append("filter").attr("id", id)
    .attr("height", "300%")
    .attr("width", "300%")
    .attr("x", "-100%")
    .attr("y", "-100%");

另一种方法是将阴影表示为框大小的百分比,而不是绝对单位。像这样的:

var filter = defs.append("filter").attr("id", id)
    .attr("primitiveUnits", "objectBoundingBox");

  filter
    .append("feGaussianBlur")
    .attr("in", "SourceAlpha")
    .attr("stdDeviation", "0.1")
    .attr("result", "blur");

【讨论】:

正是我想要的!谢谢!

以上是关于d3 svg 阴影差异的主要内容,如果未能解决你的问题,请参考以下文章

svg 到 png 不工作,怀疑 svg 元素差异

SVG 属性和样式之间是不是存在性能差异?

为啥过滤器(阴影)导致我的 SVG 在 Safari 中消失?

如何根据文本宽度动态调整 SVG 矩形的大小?

ts 与 C#的 一个差异的地方

为什么稳压二极管动态电阻测量出现差异?