Блок стрелка с использованием SVG

111
25 октября 2021, 18:50

Мне нужно нарисовать красивую заштрихованную стрелку блока, используя SVG из одной точки (x0, y0) в другую (x1, y1), как показано на рисунке.

Единственный способ, который я могу себе представить, - это использовать линию (две линии в основном для имитации обводки и заливки) с маркером, но она выглядит некрасиво из-за перекрывающихся штрихов.

В идеале и линия, и маркер должны быть заполнены одинаковым цветом и иметь одинаковый цвет обводки, а общая ширина стрелки может быть фиксированной (но если бы я мог создать линию с помощью JS,изменяя параметры, это было бы круто).

По сути, он должен выглядеть так же, как на картинке. Это вообще возможно?

Answer 1

Я написал функцию для генерации пути правильной формы.

Вам просто нужно указать координаты «от» и «до», ширину линии, ширину стрелки и длину стрелки.

var from = {x: 50, y: 250}; 
var to = {x: 250, y: 100}; 
 
var lineWidth = 30; 
var arrowheadWidth = 60; 
var arrowheadLength = 50; 
 
var svg = document.getElementById("test"); 
 
drawArrow(svg, from, to, lineWidth, arrowheadWidth, arrowheadLength); 
 
 
function drawArrow(svg, from, to, lineWidth, arrowheadWidth, arrowheadLength) 
{ 
  var dx = to.x - from.x; 
  var dy = to.y - from.y; 
  // Calculate the length of the line 
  var len = Math.sqrt(dx * dx + dy * dy); 
  if (len < arrowheadLength) return; 
 
  // Разница между шириной линии и шириной стрелки 
  var dW = arrowheadWidth - lineWidth; 
  // Угол наклона линии 
  var angle = Math.atan2(dy, dx) * 180 / Math.PI; 
 //Создайте путь, описывающий стрелку. Для простоты мы определяем это как 
  //горизонтальная линия  длиной вправо, начиная с 0,0. Тогда мы поворачиваем 
  // и перемещаем его на место с атрибутом преобразования. 
  var d = ['M', 0, -lineWidth/2, 
           'h', len - arrowheadLength, 
           'v', -dW / 2, 
           'L', len, 0, 
           'L', len - arrowheadLength, arrowheadWidth / 2, 
           'v', -dW / 2, 
           'H', 0, 
           'Z' ]; 
  var path = document.createElementNS("http://www.w3.org/2000/svg", "path"); 
  path.setAttribute("d", d.join(' ')); 
  path.setAttribute("transform", "translate("+from.x+","+from.y+") rotate("+angle+")"); 
  path.setAttribute("class", "arrow-line"); 
  svg.appendChild(path); 
}
.arrow-line { 
  fill: gold; 
  stroke: black; 
  stroke-width: 6; 
}
<svg id="test" width="300" height="300"> 
</svg>

Источник: @Paul LeBeau

Answer 2

Создана нормализованная стрелка в теге SVG defs. Затем масштабируем стрелку после предоставленных координат. (Добавлена статическая высота XD)

document.addEventListener("DOMContentLoaded", function(event) { 
  var svgDoc = document.getElementById("arrowSvg"); 
  var useArrow = svgDoc.getElementById("customArrow"); 
  var extraData = useArrow.getAttribute("extra:data"); 
  extraData = extraData.split(" "); 
  var x1 = parseInt(extraData[0]); 
  var x2 = parseInt(extraData[1]); 
  var y1 = parseInt(extraData[2]); 
  var y2 = parseInt(extraData[3]); 
  var arrowHeight = 15; 
  //Calculate the rotation needed 
  var deltaY = y1 - y2; 
  var deltaX = x2 - x1; 
  var angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI); 
  //Distance between the two points. 
  var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); 
  useArrow.setAttribute("transform",  
                        "translate("+(x1+(deltaX/2))+" "+(y1-(deltaY/2))+") "+ 
                        "rotate(" + -1*angle +") " + 
                        "matrix("+distance+", 0, 0, "+arrowHeight+", "+(0.5-distance*0.5)+","+(0.5-arrowHeight* 0.5)+")"); 
 
});
svg { 
  width: 50%; 
  border: 1px solid black; 
} 
.arrow { 
  stroke: black; 
  stroke-width: 0.05; 
  fill: yellow; 
}
<svg id="arrowSvg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:extra="ExtraNameSpace">> 
  <defs> 
    <path id="idArrow" class="arrow" d="M0,0.25 0.60,0.25  
                         0.60,0 1,0.5 0.60,1 
                         0.60,0.75 0,0.75z" /> 
  </defs> 
  <!--- Extra Data Param: x1 x2 y1 y2---> 
  <use id="customArrow" xlink:href="#idArrow" extra:data="10 90 90 5" /> 
 
</svg>

Источник @Persijn

READ ALSO
Как получить все блоки?

Как получить все блоки?

Есть разметка вида:

209
Задержка при переборе каждого блока

Задержка при переборе каждого блока

На странице есть несколько блоков, я прохожусь по каждому с помощью кода:

110
Проблема с билдом

Проблема с билдом

Удалил из Package Manager Xiaomi SDK, после этого выдает 100 ошибок во время билда, установил заново, но ошибки выдает те-же, кто может помочь?

222
Event и delegate: в чем отличие?

Event и delegate: в чем отличие?

Для того чтобы лучше понять хотел знать чем отличается event от delegate и ещё применение операторов += и -= для методов в C#

277