使用不同颜色(不是渐变)为SVG路径着色的有效方法

时间:2015-05-16 00:26:28

标签: javascript r svg

我想使用不同系列的颜色绘制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, ...)

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

gradient enter image description here

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

编辑:我正在使用d3.svg.line绘制线条。

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

3 个答案:

答案 0 :(得分:2)

如果这些都是您正在绘制的函数(一个x值 - >一个y值),那么从技术上讲,您可以使用过滤器执行此操作,但它可能更值得工作,而canvas是更好的选择。但是如果你真的想留在d3中并且你真的想要一个单行对象出于某种原因,那么你可以通过创建一个与线段对齐并与你的线合成的颜色掩码来到达那里。 (这在Firefox中不起作用 - 你需要在那里使用定位的feFloods做一些不同的事情。你不能在当前的Chrome / IE中使用定位的feFloods - 有太多的bug。)例如:

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

答案 1 :(得分:0)

你必须要么:

  1. 绘制一系列<line>元素。每个数据点一个。只要不存在荒谬的数量,这应该没问题。

  2. 使用<polyline>可以提高效率,并将一种颜色的所有点保持在一起。

答案 2 :(得分:0)

对于像witten这样的要求,canvas可能比SVG更合适。

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