Как найти центр svg

You can use the method getBBox or alternatively getBoundingClientRect. Both methods give you an object with the properties x, y, width, height, which you can use to calculate your center.

Since you tagged your question with svg.js I will also give you a solution with svg.js.

// Vanilla
node = document.getElementById('myEl').getBBox()

// with svg.js
SVG.adopt(document.getElementById('myEl')).bbox()

The second solution gives you back an object which has cx and cy already calculated for you.

This method can be found in the docs

Привет. Постал вопрос анимации вращения элемента SVG вокруг своей оси. Потому как Firefox не работает корректно с процентными значениями от transform-origin, требуется узнать точный центр элемента.

К сожалению гугление не дало четкого и правильного ответа на вопрос.

Вот SVG:

<svg version="1.1" id="logotype-container" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 556.3 146.3" style="enable-background:new 0 0 556.3 146.3;" xml:space="preserve">
<style type="text/css">
	.st0{fill:#F77B00;}
	.st1{fill:#FC4D3C;}
	.st2{fill:#F9B521;}
	.st3{fill:#1D3566;}
</style>
<g id="logotype_1_">
	<g id="gears-group">
		<path id="XMLID_40_" class="st0" d="M239.5,86.5l-7.5,1.8c-0.2,0.1-0.4,0.3-0.4,0.5l0.2,3.8c0,0.2,0.2,0.4,0.4,0.5l7.9,1.3
			c0.5,0.1,0.8,0.4,1,0.8c0.4,0.9,0.8,1.8,1.3,2.6c0.3,0.4,0.3,0.9,0,1.4c-1.1,1.7-3.8,6.2-3.8,6.2c-0.3,0.5-0.3,0.8-0.1,0.9
			l2.8,2.6c0.2,0.2,0.4,0.2,0.6,0l6.4-4.7c0.4-0.3,0.9-0.3,1.3-0.1c0.9,0.4,1.8,0.7,2.7,0.9c0.5,0.1,0.9,0.5,1,0.9
			c0.4,1.8,1.5,6.1,1.8,7.4c0.1,0.2,0.3,0.4,0.5,0.4l3.8-0.2c0.2,0,0.4-0.2,0.5-0.4l1.3-7.8c0.1-0.5,0.4-0.8,0.8-1
			c0.9-0.3,1.8-0.7,2.6-1.2c0.4-0.2,0.9-0.3,1.3,0c1.6,1,5.4,3.3,6.6,4c0.2,0.1,0.4,0.1,0.6-0.1l2.6-2.8c0.2-0.2,0.2-0.4,0-0.6
			l-4.7-6.4c-0.3-0.4-0.3-0.8-0.1-1.3c0.4-0.9,0.7-1.8,0.9-2.7c0.1-0.5,0.5-0.9,0.9-1l7.4-1.8c0.2-0.1,0.4-0.3,0.4-0.5l-0.2-3.8
			c0-0.2-0.2-0.4-0.4-0.5l-7.7-1.3c-0.5-0.1-0.8-0.4-1-0.8c-0.3-0.9-0.7-1.8-1.2-2.6c-0.2-0.4-0.3-0.9,0-1.4l4-6.6
			c0.1-0.2,0.1-0.4-0.1-0.6l-2.8-2.6c-0.2-0.2-0.4-0.2-0.6,0l-6.4,4.6c-0.4,0.3-0.9,0.3-1.3,0.1c-0.9-0.4-1.8-0.7-2.8-1
			c-0.5-0.1-0.8-0.5-1-0.9l-1.7-7.1c-0.2-0.6-0.4-0.8-0.6-0.8l-3.8,0.2c-0.2,0-0.4,0.2-0.5,0.4l-1.3,7.9c-0.1,0.5-0.4,0.8-0.8,1
			c-0.9,0.4-1.8,0.8-2.6,1.3c-0.4,0.3-0.9,0.3-1.4,0l-6.5-4c-0.2-0.1-0.4-0.1-0.6,0.1l-2.6,2.8c-0.2,0.2-0.2,0.4,0,0.6l4.6,6.4
			c0.3,0.4,0.3,0.9,0.1,1.3c-0.4,0.9-0.7,1.8-1,2.8C240.3,86,239.9,86.4,239.5,86.5z M249.3,91.6c-1.1-4.9,2.9-9.2,7.8-8.5
			c2.8,0.4,5,2.5,5.7,5.2c1.1,4.9-2.9,9.2-7.8,8.5C252.2,96.4,249.9,94.3,249.3,91.6z"></path>
		<path id="XMLID_37_" class="st1" d="M222.3,71.8l5.7-10.7c0.2-0.4,0.6-0.7,1.1-0.7c1.7,0,3.3-0.3,4.9-0.7c0.5-0.1,1,0,1.3,0.4
			c1.6,1.9,6.3,7.5,7.6,9c0.2,0.2,0.5,0.3,0.8,0.1l5.1-2.8c0.3-0.1,0.4-0.4,0.3-0.7l-3.6-11.6c-0.1-0.4,0-0.9,0.3-1.3
			c1.1-1.2,2.1-2.5,3-4c0.3-0.4,0.7-0.7,1.2-0.6l11.7,1c0.3,0,0.6-0.2,0.6-0.4l1.6-5.6c0.1-0.3,0-0.6-0.3-0.7l-10.7-5.7
			c-0.4-0.2-0.7-0.6-0.7-1.1c0-1.7-0.3-3.3-0.7-4.9c-0.1-0.5,0-1,0.4-1.3l9-7.6c0.2-0.2,0.3-0.5,0.1-0.8l-2.8-5.1
			c-0.1-0.3-0.4-0.4-0.7-0.3L246,19.5c-0.4,0.1-0.9,0-1.3-0.3c-1.2-1.1-2.5-2.1-4-3c-0.4-0.3-0.7-0.7-0.6-1.2l1-11.7
			c0-0.3-0.2-0.6-0.4-0.6L235.2,1c-0.3-0.1-0.6,0-0.7,0.3L228.8,12c-0.2,0.4-0.6,0.7-1.1,0.7c-1.7,0-3.3,0.3-4.9,0.7
			c-0.5,0.1-1,0-1.3-0.4c-1.6-1.9-6.3-7.5-7.6-9c-0.2-0.2-0.5-0.3-0.8-0.1L208,6.6c-0.3,0.1-0.4,0.4-0.3,0.7l3.6,11.6
			c0.1,0.4,0,0.9-0.3,1.3c-1.1,1.2-2.1,2.5-3,4c-0.3,0.4-0.7,0.7-1.2,0.6l-11.7-1c-0.3,0-0.6,0.2-0.6,0.4l-1.6,5.6
			c-0.1,0.3,0,0.6,0.3,0.7l10.7,5.7c0.4,0.2,0.7,0.6,0.7,1.1c0,1.7,0.3,3.3,0.7,4.9c0.1,0.5,0,1-0.4,1.3l-9,7.6
			c-0.2,0.2-0.3,0.5-0.1,0.8l2.8,5.1c0.1,0.3,0.4,0.4,0.7,0.3l11.6-3.6c0.4-0.1,0.9,0,1.3,0.3c1.2,1.1,2.5,2.1,4,3
			c0.4,0.3,0.7,0.7,0.6,1.2l-1,11.7c0,0.3,0.2,0.6,0.4,0.6l5.6,1.6C221.8,72.2,222.1,72,222.3,71.8z M218.5,33.6
			c1.8-6.1,8.7-9.3,14.7-6.2c3.6,1.9,5.8,5.9,5.4,9.9c-0.6,6.7-7,10.8-13.1,9C220,44.7,216.9,39.1,218.5,33.6z"></path>
		<path id="XMLID_32_" class="st2" d="M224.4,137.3l-2.3-9.3c-0.1-0.5,0-0.9,0.4-1.2c0.9-0.9,1.7-1.8,2.4-2.8
			c0.3-0.4,0.8-0.6,1.2-0.5l9.1,1.4c0.2,0,0.5-0.1,0.5-0.3l1.6-4.4c0.1-0.2,0-0.5-0.2-0.6l-8.2-5c-0.4-0.2-0.6-0.7-0.6-1.1
			c0-1.2-0.1-2.4-0.3-3.7c-0.1-0.5,0.1-1,0.5-1.3l7.4-5.5c0.2-0.1,0.3-0.4,0.2-0.6l-2-4.2c-0.1-0.2-0.3-0.3-0.6-0.3l-9.3,2.3
			c-0.5,0.1-0.9,0-1.2-0.4c-0.9-0.9-1.8-1.7-2.8-2.4c-0.4-0.3-0.6-0.8-0.5-1.2l1.4-9.1c0-0.2-0.1-0.5-0.3-0.5l-4.4-1.6
			c-0.2-0.1-0.5,0-0.6,0.2l-5,8.2c-0.2,0.4-0.7,0.6-1.1,0.6c-1.2,0-2.5,0.1-3.7,0.3c-0.5,0.1-1-0.1-1.2-0.5
			c-1.2-1.7-4.6-6.2-5.5-7.4c-0.1-0.2-0.4-0.2-0.6-0.1l-4.2,2c-0.2,0.1-0.3,0.3-0.3,0.6l2.3,9.3c0.1,0.4,0,0.9-0.4,1.2
			c-0.9,0.9-1.7,1.8-2.4,2.8c-0.3,0.4-0.7,0.6-1.2,0.5l-8.7-1.3c-0.7-0.1-0.9,0-1,0.3l-1.6,4.4c-0.1,0.2,0,0.5,0.2,0.6l8.2,5
			c0.4,0.2,0.6,0.7,0.6,1.1c0,1.2,0.1,2.4,0.3,3.7c0.1,0.5-0.1,1-0.5,1.3l-7.4,5.5c-0.2,0.1-0.3,0.4-0.2,0.6l2,4.2
			c0.1,0.2,0.3,0.3,0.6,0.3l9.3-2.3c0.5-0.1,0.9,0,1.2,0.4c0.9,0.9,1.8,1.7,2.8,2.4c0.4,0.3,0.6,0.8,0.5,1.2l-1.4,9.1
			c0,0.2,0.1,0.5,0.3,0.5l4.4,1.6c0.2,0.1,0.5,0,0.6-0.2l5-8.2c0.2-0.4,0.7-0.6,1.1-0.6c1.2,0,2.4-0.1,3.7-0.3
			c0.5-0.1,1,0.1,1.3,0.5c1.2,1.7,4.6,6.2,5.5,7.4c0.1,0.2,0.4,0.2,0.6,0.1l4.2-2C224.3,137.8,224.4,137.5,224.4,137.3z
			 M202.2,117.1c-2.1-4.6,0.3-10.2,5.5-11.5c3.2-0.8,6.6,0.5,8.5,3.1c3.1,4.3,1.5,10.2-3.1,12.3C209,123,204.2,121.2,202.2,117.1z"></path>
	</g>
	<g id="text-group">
		<path id="t" class="st3" d="M15.9,60.7V22.1H1.2v-9.8h40v9.8H26.5v38.5H15.9z"></path>
		<path id="e_1_" class="st3" d="M47.9,60.7V12.3h36.4v9.5H58.4v9.8h22.8v9.5H58.4v10.1h26.2v9.5H47.9z"></path>
		<path id="x" class="st3" d="M90.3,60.7l16.8-24.6L91,12.3h10.8c1,0,2,0.5,2.5,1.4l9.3,14.3l9.3-14.3c0.6-0.8,1.5-1.4,2.5-1.4h10.5
			L119.7,36l16.8,24.7h-10.8c-1,0-2-0.5-2.5-1.4l-9.9-15.2l-10,15.2c-0.6,0.8-1.5,1.4-2.5,1.4H90.3z"></path>
		<path id="h" class="st3" d="M143.2,60.7V12.3h10.6v19.1h19.6V12.3h10.6v48.3h-10.6V41.3h-19.6v19.4H143.2z"></path>
		<path id="c_1_" class="st3" d="M295.8,61.5c-7.1,0-13-2.4-17.7-7.2c-4.7-4.8-7.1-10.7-7.1-17.8c0-7,2.4-12.9,7.1-17.7
			c4.7-4.8,10.8-7.2,18.1-7.2c4.2,0,7.7,0.7,10.6,2c2.9,1.4,5.6,3.3,8.1,5.8l-4.4,5.1c-1,1.2-2.8,1.4-4.1,0.4
			c-1.3-1-2.5-1.7-3.7-2.3c-1.8-0.9-4-1.3-6.6-1.3c-4,0-7.4,1.5-10,4.4c-2.6,2.9-4,6.5-4,10.8c0,4.2,1.3,7.8,4,10.8
			c2.6,2.9,6,4.4,10,4.4c2.6,0,4.8-0.5,6.7-1.4c1.3-0.6,2.6-1.5,3.9-2.5c1.2-1,3-0.8,4,0.3l4.8,5.2c-2.6,2.8-5.5,4.9-8.5,6.2
			C304,60.8,300.3,61.5,295.8,61.5z"></path>
		<path id="e" class="st3" d="M322.5,60.7V12.3H359v9.5h-25.9v9.8h22.8v9.5h-22.8v10.1h26.2v9.5H322.5z"></path>
		<path id="r" class="st3" d="M368.1,60.7V12.3h19.7c5.7,0,10.2,1.5,13.5,4.6c3.3,3.1,5,7.2,5,12.2c0,5.4-1.8,9.6-5.5,12.5
			c-3.7,3-8.4,4.5-14,4.5h-8.1v14.5H368.1z M378.7,36.7h8.4c2.6,0,4.7-0.7,6.2-2.1c1.5-1.4,2.2-3.2,2.2-5.4c0-2.3-0.8-4.2-2.3-5.4
			c-1.5-1.3-3.6-1.9-6.4-1.9h-8.2V36.7z"></path>
		<path id="v" class="st3" d="M412.9,60.7V12.3h22.4c5.6,0,9.8,1.4,12.6,4.3c2.2,2.2,3.3,5,3.3,8.4c0,4.6-2.1,8-6.4,10.4
			c3,1.2,5.2,2.7,6.8,4.5c1.5,1.9,2.3,4.4,2.3,7.5c0,4.3-1.6,7.6-4.8,9.9c-3.2,2.3-7.6,3.4-13.3,3.4H412.9z M423.3,31.9h9.8
			c5.1,0,7.7-1.7,7.7-5.2c0-1.6-0.6-2.8-1.8-3.7c-1.2-0.9-2.9-1.3-5.2-1.3h-10.5V31.9z M423.3,51.3h12.6c5,0,7.5-1.8,7.5-5.4
			c0-3.5-2.6-5.2-7.9-5.2h-12.3V51.3z"></path>
		<path id="i" class="st3" d="M503.6,12.3v48.3h-10.5V29l-20.2,30.3c-0.6,0.8-1.5,1.3-2.5,1.3h-8.4V12.3h10.5V44l20.4-30.4
			c0.6-0.8,1.5-1.3,2.5-1.3H503.6z"></path>
		<path id="c" class="st3" d="M536.5,61.5c-7.1,0-13-2.4-17.7-7.2c-4.7-4.8-7.1-10.7-7.1-17.8c0-7,2.4-12.9,7.1-17.7
			c4.7-4.8,10.8-7.2,18.1-7.2c4.2,0,7.7,0.7,10.6,2c2.9,1.4,5.6,3.3,8.1,5.8l-4.4,5.1c-1,1.2-2.8,1.4-4.1,0.4
			c-1.3-1-2.5-1.7-3.7-2.3c-1.8-0.9-4-1.3-6.6-1.3c-4,0-7.4,1.5-10,4.4c-2.6,2.9-4,6.5-4,10.8c0,4.2,1.3,7.8,4,10.8
			c2.6,2.9,6,4.4,10,4.4c2.6,0,4.8-0.5,6.7-1.4c1.3-0.6,2.6-1.5,3.9-2.5c1.2-1,3-0.8,4,0.3l4.8,5.2c-2.6,2.8-5.5,4.9-8.5,6.2
			C544.7,60.8,541,61.5,536.5,61.5z"></path>
	</g>
</g>
</svg>

Интересуют: #XMLID_32_; #XMLID_37_; #XMLID_40_

Заранее благодарю.

I did some searching and found this
stack overflow answer

Basically what you do is find the smallest rectangle that can fit around the svg element using the getBBox or getBoundingClientRect command which returns a rectangle element. You can then get the width and height of that element and divide both of those fields by two to get the center of that rect element.

mySVG = someRandomSVGElement;
surroundingRectangle = mySVG.getBoundingClientRect();

centerOfRect_X = surroundingRectangle.width/2;
centerOfRect_Y = surroundingRectangle.height/2;

You then add that to the x and y of the rect element to get the coordinates for the center of your mySVG element.

centerOfmySVG_X = centerOfRect_X + surroundingRectangle.x;
centerOfmySCG_Y = centerOfRect_Y + surroundingRectangle.y;

Addendum (Nov2020): with ES destructure:

        let { x, y, width, height } = svgElement.getBoundingClientRect();
        let cx = width / 2 + x;
        let cy = height / 2 + y;

#javascript #svg

#javascript #svg

Вопрос:

Мне нужно расположить маркеры (круги) в центре комнат на плане этажа SVG. Каждая комната может быть либо отдельной формой, например прямоугольником, либо группой фигур. Круг должен занимать около 1/4 комнаты: радиус = (ширина высота) / 8

svg необходимо изменить в соответствии с его контейнером div.введите описание изображения здесь

После множества проб и ошибок я придумал код, который, кажется, работает, но также выглядит слишком сложным, поскольку я использую getBBox(), getBoundingClientRect() и MatrixTransform():

  • getBBox дает мне правильную ширину и высоту, но x = y = 0 для элементов группы
  • getBoundingClientRect MatrixTransform дает мне правильные координаты cx и cy, но не правильную ширину и высоту комнаты.

Есть ли более простой способ?

 const draw = document.getElementsByTagName("svg")[0];

const NS = draw.getAttribute("xmlns");

// Get titles
const titleElements = draw.getElementsByTagNameNS(NS, "title");

Array.from(titleElements).forEach((titleElement) => {
  let parentElement = titleElement.parentElement;
  let clientRect = parentElement.getBoundingClientRect();
  let bbox = parentElement.getBBox();

  let point = draw.createSVGPoint();
  point.x = clientRect.left   clientRect.width / 2;
  point.y = clientRect.top   clientRect.height / 2;

  // Convert screen coordinates into SVG document coordinates
  const svgP = point.matrixTransform(draw.getScreenCTM().inverse());

  // clientRect doesn't resize with the svg
  // let radius = (clientRect.width   clientRect.height) / 8;
  // bbox resizes with the svg
  let radius = (bbox.width   bbox.height) / 8;

  let circle = document.createElementNS(NS, "circle");

  circle.setAttribute("cx", svgP.x.toString());
  circle.setAttribute("cy", svgP.y.toString());
  circle.setAttribute("r", radius.toString());
  circle.setAttribute("fill", "cyan");

  draw.appendChild(circle);
}); 
 <!DOCTYPE html>
<html>
  <head>
    <title>Floor Plan</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app" style="width:300px;height:300px;">
    <svg
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      viewBox="0 0 792 612"
      xml:space="preserve"
      color-interpolation-filters="sRGB"
      class="st7"
    >
      <g>
        <g id="group1-1" transform="translate(659.691,-186.346) rotate(60)">
          <title>Space.1001</title>
          <g id="shape1-2">
            <rect x="0" y="508.5" width="90" height="90" class="st1" />
          </g>
        </g>
        <g id="group1000-10" transform="translate(482.508,-114.75) rotate(60)">
          <title>Space.1000</title>
          <g id="shape1000-11">
            <rect x="0" y="208.5" width="90" height="90" class="st4" />
          </g>
        </g>
        <g id="group1002-18" transform="translate(659.691,-67.0962) rotate(60)">
          <title>Space.1002</title>
          <g id="shape1002-19">
            <rect x="0" y="508.5" width="90" height="90" class="st5" />
          </g>
        </g>
        <rect x="0" y="208.5" width="90" height="90" class="st6">
          <title>Space.1004</title>
        </rect>
      </g>
    </svg>
    </div>
  </body>
</html> 

Комментарии:

1. Ваш код в основном правильный. Либо используйте getBoundingClientRect() и преобразуйте с getScreenCTM().inverse() помощью , либо используйте getBBox() и преобразуйте с getCTM().inverse() помощью .

2. Проблема в том, что я использую getBoundingClientRect «и»getBBox, а не «или». Вот почему я подозреваю, что должен быть лучший способ. Но если я попробую только одно или другое, это не удастся.

3. ваш код присваивает bbox , но никогда не использует его.

4. Я исправил код и перефразировал свой вопрос. Спасибо @ccprog!

5. а. Я вижу свою ошибку. .getCTM() возвращает преобразование к исходному видовому экрану, а не к исходной системе координат. Тогда лучший способ — действительно переместить круг внутри преобразованной группы, согласно ответу Пола.

Ответ №1:

Вот некоторый код, который немного проще.

 const draw = document.getElementsByTagName("svg")[0];

const NS = draw.namespaceURI;

// Do the rooms that are groups
let rooms = document.querySelectorAll("title   g");
rooms.forEach(room => {
  room.appendChild( makeDot(room.getBBox()) );
});

// Do the rooms where the title is in a rect
let titles = document.querySelectorAll("rect > title");
titles.forEach(title => {
  let rect = title.parentElement;
  rect.insertAdjacentElement('afterend', makeDot(rect.getBBox()) );
});


// Make the circle element
function makeDot(roomBounds)
{
  let radius = (roomBounds.width   roomBounds.height) / 8;
  let circle = document.createElementNS(NS, "circle");
  circle.setAttribute("cx", roomBounds.x   roomBounds.width / 2);
  circle.setAttribute("cy", roomBounds.y   roomBounds.height / 2);
  circle.setAttribute("r", radius);
  circle.setAttribute("fill", "cyan");
  return circle;
} 
     <div id="app" style="width:300px;height:300px;">
    <svg
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      viewBox="0 0 792 612"
      xml:space="preserve"
      color-interpolation-filters="sRGB"
      class="st7"
    >
      <g>
        <g id="group1-1" transform="translate(659.691,-186.346) rotate(60)">
          <title>Space.1001</title>
          <g id="shape1-2">
            <rect x="0" y="508.5" width="90" height="90" class="st1" />
          </g>
        </g>
        <g id="group1000-10" transform="translate(482.508,-114.75) rotate(60)">
          <title>Space.1000</title>
          <g id="shape1000-11">
            <rect x="0" y="208.5" width="90" height="90" class="st4" />
          </g>
        </g>
        <g id="group1002-18" transform="translate(659.691,-67.0962) rotate(60)">
          <title>Space.1002</title>
          <g id="shape1002-19">
            <rect x="0" y="508.5" width="90" height="90" class="st5" />
          </g>
        </g>
        <rect x="0" y="208.5" width="90" height="90" class="st6">
          <title>Space.1004</title>
        </rect>
      </g>
    </svg>
    </div> 

Комментарии:

1. Спасибо! Имеет смысл иметь специальный код для групп. Будет ли код для rect работать с любой формой? Как упоминалось в моем вопросе, прямоугольник — это всего лишь пример. У меня могут быть полигоны, пути и т. Д.

2. ДА. Но обратите внимание, что при этом точка будет помещена в центр ограничивающей рамки фигур, а не в центр фигуры. Если контур или многоугольник имеет контур странной формы, то точка может оказаться за пределами фигуры. Поиск оптического центра контура произвольной формы — гораздо более сложная задача.

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

4. Тогда это может стать проблемой. Причина, по которой я вставляю их туда, где они есть, заключается в том, что на них влияют любые transform s, которые могут быть в элементах-предках. Если вам нужно вставить их на совершенно отдельный слой в другом месте SVG, тогда вам нужно каким-то образом применить сопоставимое преобразование к кругу.

5. Верно, именно это я и делал в своем исходном коде. Основной вывод из вашего кода для меня — отделить группы от фигур.

Перевод книги Pocket Guide to Writing SVG, c разрешения автора — Джони Трайтел.

Pocket Guide to Writing SVG

  • Введение
  • Глава 1. Организация документа
  • Глава 2. Базовые фигуры и контуры
  • Глава 3. Рабочая область
  • Глава 4. Заливки и обводки
  • Глава 5. Элемент <text>
  • Глава 6. Продвинутые функции: градиенты, паттерны, контуры обрезки
  • Заключение

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

Базовые фигуры

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

Прямоугольник

Элемент <rect> определяет прямоугольник

<svg>
    <rect width="200" height="100" fill="#BBC42A" />
</svg>

basicrect

Увидеть демо можно здесь.

Атрибуты width и height устанавливают размер прямоугольника, в то время как fill — внутренний цвет фигуры. Если не указаны единицы измерения, то по умолчанию это будут пиксели, а если не указать fill , по умолчанию цвет будет чёрным.

Другие атрибуты, которые могут быть добавлены – координаты x и y . Эти значения передвинут фигуру вдоль соответствующей оси согласно размерам, установленным элементом <svg> .

Также есть возможность создать закруглённые углы, указав значения в атрибутах rx и ry. К примеру, rx="5" ry="10" сгенерирует горизонтальные стороны углов с радиусом 5px, а вертикальные в 10px.

Круг

Элемент <circle> строится, основываясь на центральной точке и внешнем радиусе.

<svg>
    <circle cx="75" cy="75" r="75" fill="#ED6E46" />
</svg>

basiccircle

Увидеть демо можно здесь.

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

Атрибут r устанавливает размер внешнего радиуса.

Эллипс

Элемент <ellipse> описывает эллипс, который строится по центральной точке и двум радиусам.

<svg>
    <ellipse cx="100" cy="100" rx="100" ry="50" fill="#7AA20D" />
</svg>

basicellipse

Увидеть демо можно здесь.

В то время как значения атрибутов cx и cy помещают центральную точку на указанном расстоянии в пикселях от начала SVG-координат, значения rx и ry определяют радиус сторон фигуры.

Линия

Данный элемент определяет прямую линию с начальной и конечной точкой.

<svg>
    <line x1="5" y1="5" x2="100" y2="100" stroke="#765373" stroke-width="8"/> 
</svg>

basicline

Увидеть демо можно здесь.

Значения атрибутов x1 и y1 устанавливают координаты начала линии, а значения x2 и y2 — определяют конец линии.

Ломаная линия

<polyline> определяет набор соединённых отрезков прямой линии, что в результате даёт, как правило, незамкнутую фигуру (начало и конец точек которой не связаны).

<svg>
    <polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" fill="white" stroke="#BBC42A" stroke-width="6" />
</svg>

basicpolyline

Увидеть демо можно здесь.

Значения в points определяют положение фигуры по осям x и y от начала до конца фигуры и разбиты по парам x,y во всём списке значений.

Нечётное число точек является ошибкой.

Многоугольник

Элемент <polygon> определяет замкнутую фигуру состоящую из связанных линий.

<svg>
    <polygon points="50,5 100,5 125,30 125,80 100,105 50,105 25,80 25,30" fill="#ED6E46" />
</svg>

basicpolygon

Увидеть демо можно здесь.

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

Также, в зависимости от числа определяемых точек, этот элемент может создавать и другие замкнутые фигуры.

Элемент path

SVG-элемент path представляет собой контур фигуры. Эта фигура может быть заполнена, обведена, использована как направляющая для текста и/или как контур обрезки.

В зависимости от фигуры, эти контуры могут быть очень сложными, особенно когда в них содержится множество кривых. Но если разобраться в их работе и соответствующем синтаксисе, то и такие контуры станут гораздо более управляемыми.

Данные path

Данные path содержатся в атрибуте d внутри элемента <path>, определяя форму фигуры: <path d="<конкретные данные path>" />.

Данные, включённые в атрибут d, описывают команды для path: moveto, line, curve, arc и closepath.

Детали <path> ниже определяют особенности контура для рисунка лайма:

<svg width="258px" height="184px">
    <path fill="#7AA20D" stroke="#7AA20D" stroke-width="9" stroke-linejoin="round" d="M248.761,92c0,9.801-7.93,17.731-17.71,17.731c-0.319,0-0.617,0-0.935-0.021c-10.035,37.291-51.174,65.206-100.414,65.206 c-49.261,0-90.443-27.979-100.435-65.334c-0.765,0.106-1.531,0.149-2.317,0.149c-9.78,0-17.71-7.93-17.71-17.731 c0-9.78,7.93-17.71,17.71-17.71c0.787,0,1.552,0.042,2.317,0.149C39.238,37.084,80.419,9.083,129.702,9.083    c49.24,0,90.379,27.937,100.414,65.228h0.021c0.298-0.021,0.617-0.021,0.914-0.021C240.831,74.29,248.761,82.22,248.761,92z" />
</svg>

pathlime

moveto

Команды moveto (М или м) устанавливают новые точки, как будто мы поднимаем ручку и начинаем рисовать в новом месте на листе бумаги. Строка кода, составляющего данные path, должна начинаться с команды moveto, как показано выше в примере с лаймом.

Команды moveto, которые следуют за исходной, представляют собой начало нового фрагмента контура, создавая составной контур. Заглавная М указывает, что после нее идут абсолютные координаты, тогда как строчная m указывает на относительные координаты.

closepath

Closepath (Z и z) заканчивает текущий фрагмент контура приводит к рисованию прямой линии от текущей точки до начальной.

Если команда moveto следует непосредственно за closepath, то координаты moveto представляют собой начало следующего фрагмента контура. Если за closepath следует любая команда кроме moveto, то следующий фрагмент контура начинается в той же самой точке, где и текущий фрагмент контура.

И заглавная и строчная буква z здесь имеют одинаковые результаты.

lineto

Команды lineto рисуют прямые линии от текущей точки до новой.

L, l

Команды L и l рисуют линию от текущей точки до следующих предоставленных координат точки. Эта новая точка затем становится текущей точкой и так далее.

Заглавная L означает, что после неё идёт абсолютное позиционирование, в то время как после l — относительное.

H, h

Команды H и h рисуют горизонтальную линию от текущей точки.

Заглавная H означает, что после неё идёт абсолютное позиционирование, в то время как после h — относительное.

V, v

Команды V и v рисуют вертикальную линию от текущей точки.

Заглавная V означает, что после неё идёт абсолютное позиционирование, в то время как после v — относительное.

Команды для создания кривых

Для рисования кривых есть три группы команд: кубическая кривая Безье (C, c, S, s), квадратичная кривая Безье (Q, q, T, t), и дуга эллипса (A, a)..

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

Кубическая кривая Безье

Команды C и c рисуют кубическую кривую Безье от текущей точки, используя параметры (х1, y1) в качестве управляющей точки в начале кривой и (x2, y2) в качестве управляющей точки в конце, определяющих особенности формы кривой.

Команды S и s также рисуют кубическую кривую Безье, но в данном случае предполагается, что первая управляющая точка является отражением второй (имеется в виду вторая управляющая точка предыдущей команды, см. более подробное описание ниже — прим. перев.).

кубическая-кривая-безье

Следующий код рисует базовую кубическую кривую Безье:

<svg>
    <path fill="none" stroke="#333333" stroke-width="3" d="M10,55 C15,5 100,5 100,55" />
</svg>

Увидеть демо можно здесь.

Управление первыми и последними наборами значения для этой кривой повлияет на положение ее начала и конца, в то время как управление двумя центральными значениями повлияет на форму и ориентацию самой кривой в начале и конце.

Команды S и s также рисуют кубическую кривую Безье, но в данном случае предполагается, что первая управляющая точка является отражением последней для предшествующей команды C. Отражение производится относительно начальной точки команды S.

отражение-команды-S

Заглавная C сигнализирует, что за ней следует абсолютное позиционирование, в то время как после строчной c — относительное. Та же самая логика применяется к S и s.

Квадратичная кривая Безье

Квадратичные кривые Безье (Q, q, T, t) похожи на кубические, но имеют всего одну управляющую точку.

квадратичная-кривая-Безье

Следующий код рисует базовую квадратичную кривую Безье.

<svg>
    <path fill="none" stroke="#333333" stroke-width="3" d="M20,50 Q40,5 100,50" />
</svg>

Увидеть демо можно здесь.

Управление первыми и последними наборами значений, M20,50 и 100,50 будет влиять на позиционирование начала и конца точек кривой. Центральный набор значений Q40,5 задаёт управляющую точку для кривой, определяя ее форму.

Q и q рисуют кривую от начальной точки до конечной, используя (x1,y1) в качестве управляющей точки. T и t рисуют кривую от начальной точки до конечной, предполагая, что управляющая точка является отражением управляющей точки предыдущей команды относительно начальной точки новой команды T или t.

управляющая-точка-команды-Т

Заглавная Q сигнализирует, что за ней следует абсолютное позиционирование, в то время как после строчной q относительное. Та же самая логика применяется к T и t.

Дуга эллипса

Дуга эллипса (A, a) определяет часть эллипса. Эти части создаются с помощью команд A или a, которые создают дугу путем указания начальной и конечной точки, радиусов x и y, вращение и направление.

Взгляните на код для базовой дуги эллипса:

<svg>
    <path fill="none" stroke="#333333" stroke-width="3" d="M65,10 a50,25 0 1,0 50,25" />
</svg>

Первые и последние наборы значений внутри этого контура, M65,10 и 50,25 представляют начальные и конечные координаты, а вторые наборы значений определяют два радиуса. Значения 1, 0 (large-arc-flag и sweep-flag) определяют то, как будет отрисована дуга, поскольку для этого есть четыре различных возможных варианта.

Следующая диаграмма показывает четыре варианта выбора дуги и то, как влияют значения large-arc-flag и sweep-flag на конечное отображение отрезка дуги.

дуга-эллипса

Увидеть демо можно здесь.

Копирование из векторных редакторов

Программы для векторной графики позволяют генерировать более сложные фигуры и контуры, в то же время производя SVG-код, который может быть взят, использован и обработан где-то ещё.

После того, как графика готова, сгенерированный XML-код, который может быть достаточно длинным в зависимости от сложности, может быть скопирован и встроен в HTML. Разбивка каждого раздела SVG и наличие правильных организационных элементов может значительно помочь в навигации и понимании этих, казалось бы, сложных и многословных документов.

Здесь представлен SVG-код для изображения нескольких вишенок с добавлением классов для расширенной навигации:

<svg width="215px" height="274px" viewBox="0 0 215 274">
    <g>
        <path class="stems" fill="none" stroke="#7AA20D" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" d="M54.817,169.848c0,0,77.943-73.477,82.528-104.043c4.585-30.566,46.364,91.186,27.512,121.498" />
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M134.747,62.926c-1.342-6.078,0.404-12.924,5.762-19.681c11.179-14.098,23.582-17.539,40.795-17.846 c0.007,0,22.115-0.396,26.714-20.031c-2.859,12.205-5.58,24.168-9.774,36.045c-6.817,19.301-22.399,48.527-47.631,38.028 C141.823,75.784,136.277,69.855,134.747,62.926z" />
    </g>
    <g>
        <path class="r-cherry" fill="#ED6E46" stroke="#ED6E46" stroke-width="12" d="M164.836,193.136 c1.754-0.12,3.609-0.485,5.649-1.148c8.512-2.768,21.185-6.985,28.181,3.152c15.076,21.845,5.764,55.876-18.387,66.523 c-27.61,12.172-58.962-16.947-56.383-45.005c1.266-13.779,8.163-35.95,26.136-27.478   C155.46,191.738,159.715,193.485,164.836,193.136z" />
        <path class="l-cherry" fill="#ED6E46" stroke="#ED6E46" stroke-width="12" d="M55.99,176.859 c1.736,0.273,3.626,0.328,5.763,0.135c8.914-0.809,22.207-2.108,26.778,9.329c9.851,24.647-6.784,55.761-32.696,60.78 c-29.623,5.739-53.728-29.614-44.985-56.399c4.294-13.154,15.94-33.241,31.584-20.99C47.158,173.415,50.919,176.062,55.99,176.859z" />
    </g>
</svg>

embedcherry

Атрибуты в элементе svg определяют рабочую область или «холст» для графики. Листочек и черешки находятся в одном элементе <g> (группе), а вишенки в другом. Строка числовых значений определяет контур графики, а атрибуты fill и stroke устанавливают цвет для фона и границ.

Прежде чем поместить этот код в HTML, его можно скопировать и пропустить через SVG-оптимизатор, который в свою очередь поможет устранить лишний код, пробелы и значительно сократить размер файла. SVG-оптимизатор Питера Коллингриджа или SVGO — очень полезные в этом плане инструменты.

Публикуется под лицензией Attribution-NonCommercial-ShareAlike 4.0

P.S. Это тоже может быть интересно:

Добавить комментарий