Расширить элемент SVG, если он перекрывает другой элемент - PullRequest
1 голос
/ 27 марта 2020

У меня есть диаграмма данных, которую я создал с помощью D3, где я рисую круг для каждой точки данных.

Когда круги перекрываются, я хочу сделать их немного больше, чтобы вы могли видеть разницу, когда несколько точек данных накапливаются в одной и той же позиции.

Я обнаружил, что могу применить фильтр feMorphology с dilate, но мне нужно как-то масштабировать расширение в зависимости от количества кругов в одной и той же позиции.

Вот демонстрация SVG:

<svg width="400" height="120" xmlns="http://www.w3.org/2000/svg">
 <filter id="dilateIfOverlapping">
  <feMorphology operator="dilate" radius="4">
 </filter>
 <g filter="url(#dilateIfOverlapping)">
   <circle cx="60" cy="60" r="30" fill="green" />
   <circle cx="60" cy="60" r="30" fill="green" />
   <circle cx="170" cy="60" r="30" fill="green" />
 </g>
</svg>

Это делает два круга одинакового размера. Я хочу, чтобы первый был больше, так как два круга располагаются друг над другом.

Есть идеи, как этого добиться без программной установки другого радиуса круга?

1 Ответ

1 голос
/ 02 апреля 2020

Вы можете делать такие вещи с feComponentTransfer / feFuncA. Но он работает только с полностью перекрывающимися точками, а не с частичным перекрытием.

Работает так, что сначала рендерит круги с низкой непрозрачностью. Таким образом, чем больше кругов отображается в одной точке, тем выше их непрозрачность. Затем фильтр разбивает изображение на разные слои с разными диапазонами непрозрачности. Затем он применяет размытие разного размера к каждому из слоев, а затем устанавливает непрозрачность на размытом круге и добавляет немного искусственного сглаживания с дополнительным размытием.

Хитрость здесь заключается в получении значения непрозрачности. кругов как раз вправо, поэтому он совпадает с диапазонами непрозрачности feFuncA tableValues. Вы должны заранее знать, какое максимальное количество точек перекрытия будет, чтобы вы могли правильно откалибровать это. (Например, tableValues="0 1 0 0 0" создает 5 диапазонов непрозрачности: 0-20%, 20-40%, 40-60%, 60-80% и 80-100%.)

<svg width="800px" height="600px">
  <defs>
  <filter id="embiggen" x="-50%" y="-50%" width="200%" height="200%">
    <feComponentTransfer in="SourceGraphic" result="layer1">
      <feFuncA type="discrete" tableValues="0 1 0 0 0" />
      </feComponentTransfer>
      
         <feComponentTransfer in="SourceGraphic" >
      <feFuncA type="discrete" tableValues="0 0 1 0 0"  />
      </feComponentTransfer>
    <feGaussianBlur stdDeviation= "2"/>
    <feComponentTransfer >
      <feFuncA type="discrete" tableValues="0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1"/>
      </feComponentTransfer>
      <feGaussianBlur stdDeviation= "0.5" result="layer2"/>
    
    <feComponentTransfer in="SourceGraphic" >
      <feFuncA type="discrete" tableValues="0 0 0 1 0" />
      </feComponentTransfer>
    <feGaussianBlur stdDeviation= "4"/>
    <feComponentTransfer>
    <feFuncA type="discrete" tableValues="0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1"/>
      </feComponentTransfer>
          <feGaussianBlur stdDeviation= "0.5" result="layer3"/>
                  
    <feComponentTransfer in="SourceGraphic">
      <feFuncA type="discrete" tableValues="0 0 0 0 1" />
    </feComponentTransfer>
    <feGaussianBlur stdDeviation= "8"/>
    <feComponentTransfer >
     <feFuncA type="discrete" tableValues="0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1" />                   
    </feComponentTransfer>
     <feGaussianBlur stdDeviation= "0.5" result="layer4"/>
      
    <feMerge>
      <feMergeNode in="layer1"/>      
      <feMergeNode in="layer2"/>
      <feMergeNode in="layer3"/>
      <feMergeNode in="layer4"/>
    </feMerge>
    </defs>
  </filter>
  
  <g filter="url(#embiggen)" shape-rendering="crispEdges">

    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>  
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="50" cy="50" fill-opacity="0.21" r="10" fill="red"/>  
    
    <circle cx="120" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="120" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="120" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="120" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    
    <circle cx="180" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="180" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    <circle cx="180" cy="50" fill-opacity="0.21" r="10" fill="red"/>
    
    <circle cx="240" cy="50" fill-opacity="0.21" r="10" fill="red"/>

  </g>
  
</svg>
...