SVG - дублирование изображения по пути - PullRequest
0 голосов
/ 27 мая 2018

Я сейчас пытаюсь создать велосипедную цепь с помощью SVG и javascript.

Результат, который я пытаюсь создать, будет выглядеть примерно так: bicycle chain

Проблема, с которой я столкнулсяэто как повторить одно изображение в виде звена цепи вдоль пути цепочки.Я хочу иметь возможность использовать изображение в виде звена цепи (например: chainlink, а затем повторить это по пути, который я определяю.

Я знаю, что повторять текст по пути через SVG тривиально, ноМожно ли сделать то же самое с изображением? Сложность возникает из-за того, что звено цепи должно появиться в виде одной непрерывной линии.

Вот что я имею до сих пор:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
	</head>
	
	<body>
		<svg width="700" height="500">
			<path id="ChainPath" fill="none" stroke="red" d="M150 100 L400 100 C650 100 650 400 400 400 L150 400" />

			<text>
				<textPath href="#ChainPath" alignment-baseline="middle">
					0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
				</textPath>
			</text>
		</svg>
	</body>
</html>

Любая помощь будет принята с благодарностью.Спасибо

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Я попытался практически реализовать ответ Роберта Монферы и нашел несколько дополнительных проблем.Я начал вычислять точки сидения многоугольника, как он описал, на осях / соединительных штифтах отдельных звеньев цепи, и все с точно одинаковым расстоянием между ними.

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

Посмотрите на картинку в вопросе.Правая передача имеет 15 зубьев.Это означает, что угол между соседними звеньями цепи составляет 24 °, а разница в длине между дугой и шнуром от точки к точке (что является конструктивной длиной звена) составляет прибл.0,8%.Звучит не так много, но для ссылки, которую вы рисуете с размером экрана 50 пикселей, это почти половина пикселя.Это разница, которую можно увидеть.

Следующим предложением было использование <marker> элементов для отдельных звеньев цепи с началом координат в центре между двумя выводами.Так как определенный выше многоугольник имеет свои точки в положении штифтов, для этого необходим второй, который соединяет середины всех сегментов многоугольника.

При реализации этого результирующая цепочка выглядела следующим образом (I 'нарисуйте многоугольник сверху, чтобы проиллюстрировать):

enter image description here

Где «прямая» часть цепочки превращается в «изогнутую», цепочкуссылки серьезно смещены.Причина в том, что ориентация маркера делит пополам входящую и исходящую касательную в вершине.И для прямого участка, и для следования по дуге шестерни, это работает правильно, но там, где оба встречаются, это явно не так.

Чтобы получить правильную ориентацию маркеров, касательные в точкахдолжно соответствовать направлению исходного многоугольника.Роберт предложил провести дугу между точками.Это вероятнее всего сработает, но сложно вычислить правильные радиусы и положения дуги.

Я придумал метод, который дает плавный путь, который выглядит немного кривым, но линия никогда не будет отображаться вконец, и его вычисления действительно просты - я фактически сделал это с листом Excel.

Допустим, у нас есть список точек, отмечающих положения штифтов:

a    b    c    d    e    f    g ...

Есть двавиды ссылок (спереди и сзади), поэтому пометьте каждую другую середину из двух точек:

a    b    c    d    e    f    g ...
  ab        cd        ef

a, ab, c находятся на прямой линии, так же, как c, cd, d и так далее.Теперь, если вы нарисуете путь с помощью следующей команды

<path d="M a L ab C b c cd d e ef f g ..." marker-mid="url(#link1)" />

, точка a не будет содержать маркера, так как его нет в середине.Следующие вершины, которые позиционируют маркеры: ab, cd, ef, ..., в то время как b, c, d, e, ... являются контрольными точками кубической кривой Безье.Это означает, что касательная к вершине в ab - это прямая линия от a до b, в cd от c до d и т. Д.

Здесьэто скриншот из Inkscape для иллюстрации:

enter image description here

Другие ссылки можно описать соответственно как

<path d="M b L bc C c d de e f fg g ..." marker-mid="url(#link2)" />

Если вы хотитеПридумайте, можно даже сократить этот бит с помощью команды S, которая берет контрольную точку перед вершиной и косвенно добавляет свое отражение в качестве следующей контрольной точки после (вычисляются точки e, g, ...):

<path d="M b L bc C c d de S f fg h hj ..." marker-mid="url(#link2)" />

Для финала Гранд, вот готовый рисунок.Просто ради этого я нарисовал зубья шестерни с помощью той же техники маркеров.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800 600" width="600" height="450">
  <defs>
    <marker id="blade1" markerUnits="userSpaceOnUse" orient="auto" overflow="visible">
      <path style="fill:#ececf4" d="M 16.5,-1.556 13.947,-1.78 A 14,14 0 0 1 -13.947,-1.78 L -16.5,-1.556 0,200 Z" />
      <path style="fill:none;stroke:#000" d="M 16.5,-1.556 13.947,-1.78 A 14,14 0 0 1 -13.947,-1.78 L -16.5,-1.556" />
    </marker>
    <marker id="blade2" markerUnits="userSpaceOnUse" orient="auto" overflow="visible">
      <path style="fill:#ececf4" d="M 16.5,0.507 13.694,-0.089 A 14,14 0 0 1 -13.694,-0.089 L -16.5,0.507 0,90 Z" />
      <path style="fill:none;stroke:#000" d="M 16.5,0.507 13.694,-0.089 A 14,14 0 0 1 -13.694,-0.089 L -16.5,0.507" />
    </marker>
    <path id="plate" d="M -9.689,-10.392 C -4.782 -7.56 4.782 -7.56 9.689,-10.392 A 12,12 0 1 1 9.689,10.392 C 4.782 7.56 -4.782 7.56 -9.689,10.392 A 12,12 0 1 1 -9.689,-10.392 Z" />
    <marker id="link1" style="stroke:#000" markerUnits="userSpaceOnUse" orient="auto" overflow="visible">
      <use xlink:href="#plate" style="fill:#ddd" />
      <circle id="pin" style="fill:#888;stroke:#000" cx="15.689" cy="0" r="4" />
      <use xlink:href="#pin" x="-31.378" />
    </marker>
    <marker id="link2" style="stroke:#000" markerUnits="userSpaceOnUse" orient="auto" overflow="visible">
      <use xlink:href="#plate" style="fill:#bbb" />
    </marker>
    <g id="center1">
      <circle r="80" cx="250" cy="300" />
      <g id="cq">
        <circle r="10" cx="345" cy="265.42" />
        <path d="M 252.984,200.049 A 100,100 0 0 1 324.557,233.367 25,25 0 0 0 361.957,200.182 150,150 0 0 0 254.883,150.086 25,25 0 0 0 252.984,200.049 Z" />
      </g>
      <use xlink:href="#cq" transform="rotate(90 250,300)" />
      <use xlink:href="#cq" transform="rotate(180 250,300)" />
      <use xlink:href="#cq" transform="rotate(270 250,300)" />
    </g>
    <mask id="m1">
      <rect fill="white" x="50" y="100" width="400" height="400" />
      <use xlink:href="#center1" fill="black" />
    </mask>
    <path id="center2" d="M 647.75 277.2 L 642.04 279.05 L 643.04 282.13 A 20 20 0 0 0 633.31 292.96 L 630.13 292.28 L 628.88 298.15 L 632.06 298.83 A 20 20 0 0 0 636.55 312.68 L 634.38 315.08 L 638.84 319.1 L 641.01 316.69 A 20 20 0 0 0 655.25 319.73 L 656.25 322.8 L 661.96 320.95 L 660.96 317.87 A 20 20 0 0 0 670.7 307.04 L 673.87 307.72 L 675.12 301.85 L 671.94 301.17 A 20 20 0 0 0 667.45 287.32 L 669.62 284.92 L 665.16 280.9 L 662.99 283.31 A 20 20 0 0 0 648.75 280.27 L 647.75 277.2 z" />
    <mask id="m2">
      <rect fill="white" x="572" y="220" width="160" height="160" />
      <use xlink:href="#center2" fill="black" />
    </mask>
  </defs>
  <g mask="url(#m1)">
    <path style="fill:none;marker-mid:url(#blade1)" d="M 430,300 427.27,331.26 419.14,361.56 405.88,390 387.89,415.7 365.7,437.89 340,455.88 311.56,469.14 281.26,477.27 250,480 218.74,477.27 188.44,469.14 160,455.88 134.3,437.89 112.11,415.7 94.12,390 80.86,361.56 72.73,331.26 70,300 72.73,268.74 80.86,238.44 94.12,210 112.11,184.3 134.3,162.11 160,144.12 188.44,130.86 218.74,122.73 250,120 281.26,122.73 311.56,130.86 340,144.12 365.7,162.11 387.89,184.3 405.88,210 419.14,238.44 427.27,268.74 430,300 427.27,331.26" />
  </g>
  <use xlink:href="#center1" style="fill:none;stroke:#000" />
  <g mask="url(#m2)">
    <path style="fill:none;marker-mid:url(#blade2)" d="M 578.19,315.69 V 284.31 L 590.95,255.65 614.27,234.65 644.11,224.95 675.32,228.23 702.49,243.92 720.94,269.31 727.46,300 720.94,330.69 702.49,356.08 675.32,371.77 644.11,375.05 614.27,365.35 590.95,344.35 578.19,315.69 V 284.31"/>
  </g>
  <use xlink:href="#center2" style="fill:none;stroke:#000" />
  <path style="fill:none;marker-mid:url(#link2)" d="M 281.26 477.27 L 265.63 478.63 C 250 480 218.74 477.27 203.59 473.21 S 160 455.88 147.15 446.89 112.11 415.7 103.11 402.85 80.86 361.56 76.79 346.41 70 300 71.37 284.37 80.86 238.44 87.49 224.22 112.11 184.3 123.21 173.21 160 144.12 174.22 137.49 218.74 122.73 234.37 121.37 281.26 122.73 296.41 126.79 341.88 138.97 357.03 143.03 402.5 155.2 417.66 159.26 463.13 171.43 478.28 175.49 523.75 187.66 538.91 191.72 584.38 203.89 599.54 207.95 645.01 220.12 660.16 224.18 702.49 243.92 711.71 256.61 727.46 300 724.2 315.35 702.49 356.08 688.91 363.92 645.01 379.88 629.85 383.94 584.38 396.11 569.22 400.17 523.75 412.34 508.6 416.4 463.13 428.57 447.97 432.63 402.5 444.8 387.35 448.86 341.88 461.03 326.72 465.09 281.26 477.27 265.63 478.63 L 250 480" />
  <path style="fill:none;marker-mid:url(#link1)" d="M 311.56 469.14 L 296.41 473.21 C 281.26 477.27 250 480 234.37 478.63 S 188.44 469.14 174.22 462.51 134.3 437.89 123.21 426.79 94.12 390 87.49 375.78 72.73 331.26 71.37 315.63 72.73 268.74 76.79 253.59 94.12 210 103.11 197.15 134.3 162.11 147.15 153.11 188.44 130.86 203.59 126.79 250 120 265.63 121.37 311.56 130.86 326.72 134.91 372.19 147.08 387.35 151.14 432.82 163.31 447.97 167.37 493.44 179.54 508.6 183.6 554.07 195.77 569.22 199.83 614.69 212 629.85 216.06 675.32 228.23 688.91 236.08 720.94 269.31 724.2 284.65 720.94 330.69 711.71 343.39 675.32 371.77 660.16 375.82 614.69 388 599.54 392.05 554.07 404.23 538.91 408.28 493.44 420.46 478.28 424.51 432.82 436.69 417.66 440.74 372.19 452.92 357.03 456.97 311.56 469.14 296.41 473.21 L 281.26 477.27" />
</svg>
0 голосов
/ 27 мая 2018

Вот одно из решений: вы можете создать <polyline> или <polygon> с <marker> элементами, если вы готовы выполнять математические расчеты, чтобы гарантировать, что расстояние между точками многоугольника точно совпадает с осью-осевое расстояние вашего элемента цепи (т.е. учитывается не общая длина элемента, а повторное расстояние размещения).Требуется использование a^2 + b^2 = c^2, где c - это расстояние основного тона (константа), а a и b - это горизонтальное и вертикальное расстояния от предыдущей точки соответственно.Другими словами, вам нужно вычислить координаты x, y центров осей цепей (*) (если вы это сделаете, вы можете разместить их по одному, но тогда у вас будет много элементов DOM).

Вам понадобится orient="auto", чтобы выровнять элементы цепочки с многоугольником, а также использовать свойства viewBox, refX, refY, markerWidth, markerHeight, чтобы одиносей элемента цепочки идеально совпадает с точкой многоугольника (и затем, с помощью приведенной выше теоремы Пифагора, центр другого элемента цепочки будет соответствовать следующей точке многоугольника).

Вот несколько примеров для <marker>:

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

  • на заднем плане частично перекрытые элементы цепи
  • на переднем плане, 8-образные, полностью видимые звенья связи

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...