【问题标题】:Efficient way to color an SVG path with differing colors (not a gradient)用不同颜色(不是渐变)为 SVG 路径着色的有效方法
【发布时间】:2021-10-09 15:43:32
【问题描述】:

我想使用一系列不同的颜色绘制svg 路径。颜色列表是有限的,但它不是渐变,它是从路径/线外部的值派生的。在R 我是这样做的,作为一系列段和一个相关的颜色向量。有很多数据点(数千个),所以即使每个段的颜色可能会突然变化,但效果是平滑的:

# Color scale for each level
# blue/low -> red/high, anchored at zero (index 5, a shade of green)
# max and min will come from the data (i.e., red will be at max of V)
cscale <- c(rev(rainbow(4, start = 0.45, end = 0.66)),
  rev(rainbow(5, start = 0.0, end = 0.25)))
# view with:
# pie(rep(1, 9), col = cscale)

refscale <- seq(-1, 1, length.out = 9)  
myc <- cscale[findInterval(C[row,], refscale)] # C is a correlation matrix, values -1 ... 1

np <- length(spectra$freq)
ind1 <- 1:(np-1)
ind2 <- 2:np

plot(spectra$freq, V[row,], type = "n") # V is a covariance matrix, values -Inf ... Inf
segments(spectra$freq[ind1], V[row, ind1], spectra$freq[ind2], V[row, ind2],  col = myc, ...)

它给出了这样的图(编辑:添加了详细视图):

我想在JavaScript 中执行此操作。我看到有几种方法可以将渐变应用于笔画,但这不是我需要的。就我而言,每个线段都需要自己的颜色。关于如何在js 中有效地完成此任务的任何建议?我可以单独循环各个部分,并一次绘制一个,每个部分都有自己的颜色,但这听起来很慢(我没有尝试过,也许它比我想象的要快)。我正在使用js 代码以黑色或其他方式绘制线条。我希望我可以将颜色向量传递给 stroke 属性,但这不是js 方式。有没有我错过的技巧来做到这一点?

编辑:我正在使用d3.svg.line 画线。

EDIT2:经过进一步研究,我受到了question 的启发,这让我从this 提出了一些不同的观点。那里有两个很好的完整答案。

【问题讨论】:

    标签: javascript r svg


    【解决方案1】:

    如果这些都是您要绘制图表的函数(一个 x 值 -> 一个 y 值),那么从技术上讲,您可以使用过滤器来执行此操作,但它可能需要更多的工作,而画布是一个更好的选择。但是,如果您真的想留在 d3 中并且出于某种原因确实想要一个单线对象,那么您可以通过创建一个与线段对齐的颜色蒙版并将其与您的线合成来实现。 (这在 Firefox 中不起作用 - 您需要将颜色掩码内联为 feImage 中的数据 URI 以便获得跨浏览器)。示例:

    <svg width="800px" height="600px" color-interpolation-filters="sRGB">
      <defs>
        
        <g id="colormask">
          <rect  x="0" y="0" height="600" width="50" fill="red"   stroke="none" />
          <rect  x="50" y="0" height="600" width="20" fill="blue"  stroke="none"   />
          <rect  x="70" y="0" height="600" width="50" fill="green"    stroke="none" />
          <rect  x="120" y="0" height="600" width="30" fill="grey"  stroke="none"   />
          <rect  x="150" y="0" height="600" width="15" fill="black" stroke="none"   />
          <rect  x="165" y="0" height="600" width="50" fill="blue"   stroke="none"  />
          <rect  x="215" y="0" height="600" width="20" fill="cyan"  stroke="none"   />
          <rect  x="235" y="0" height="600" width="50" fill="red"   stroke="none"  />
          <rect  x="285" y="0" height="600" width="30" fill="pink"  stroke="none"   /> 
          <rect  x="315" y="0" height="600" width="15" fill="magenta" stroke="none" />
          <rect  x="330" y="0" height="600" width="50" fill="yellow"   stroke="none"/>
          <rect  x="380" y="0" height="600" width="20" fill="purple"   stroke="none"/>
          <rect  x="400" y="0" height="600" width="50" fill="red"   stroke="none"  />
          <rect  x="450" y="0" height="600" width="30" fill="blue"  stroke="none"  /> 
          <rect  x="480" y="0" height="600" width="50" fill="pink"   stroke="none" />
          <rect  x="530" y="0" height="600" width="15" fill="grey" stroke="none"  />
        </g>
          
        <filter id="colorline" x="0" y="0" width="800" height="600" filterUnits="userSpaceOnUse">
         <feImage xlink:href="#colormask" result="mask1"/>
          <feComposite in2="SourceGraphic" in="mask1" operator="in" />
        </filter>
      </defs>
      
      <path filter="url(#colorline)" d="M0 50 l50,30 20,-15 50,-40 30,20 15,40 50,30 20,-15 50,-40 30,20 15,40 50,30 20,-15 50,-40 30,20 15,40 50,30 20,-15 50,-40 30,20 15,40 50,30 20,-15 50,-40 30,20 15,40 " fill="none " stroke="black" stroke-width="3"/>
    </svg>

    【讨论】:

    • 你的例子有问题。您有两个 id 为“colormask”的元素。这将是不可靠的。它在 Chrome 中似乎可以正常工作,但在 FF 中可以。
    • 感谢 Paul - 修复了 ID - 并针对 Chrome 提交了定位洪水的错误 - 这是最近的回归
    【解决方案2】:

    对于 Witten 的要求,canvas 可能比 SVG 更适合。

    如果您确实想继续使用 SVG,请绘制一个包含单一颜色的所有段的 &lt;path&gt; 元素。路径中的M or m 命令可用于创建不连续的段,L or l 可以创建行。

    【讨论】:

    • 我是如何在数千个数据点上做到这一点的。
    【解决方案3】:

    您只需要:

    1. 绘制一系列&lt;line&gt; 元素。每个数据点一个。只要数量不多,应该没问题。

    2. 您可以通过使用&lt;polyline&gt; 来提高效率,并将一种颜色的所有点保持在一起。

    【讨论】:

    • 需要&lt;path&gt; 而不是&lt;polyline&gt;,因为一种颜色的点不会是连续的吗?
    • 很难从这么小的图像中分辨出来,但是如果放大,它看起来确实像折线图而不是条形图。至少我是这么认为的。接近尾声时,一个序列中至少有 5 或 6 条红线。
    • 我添加了更详细的图像。我目前正在与d3.svg.line 划清界限。我想两个答案都建议的一个选择是按颜色排序,然后分块绘制。这比遍历每个段要快。感谢您的关注!
    • @RobertLongson 从任何一张图片中都不能完全清楚(抱歉),但 x 维度是均匀分布的并且非常靠近(请参阅详细图片中的深蓝色)。所以,有一些相同颜色的连续元素,但不是很多。从一个情节到另一个情节,不能保证颜色的任何模式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    相关资源
    最近更新 更多