Движение поезда с помощью SVG

218
23 февраля 2018, 16:30

У меня есть картинка, на которой изображено движение поезда по рельсам.
Для создания анимации движения хочу использовать SVG.
При всём этом у паровоза из дымовой трубы выходит дым.
Как сделать подобную анимацию, используя SVG?

Answer 1

Поэтапно сделаем каждую деталь поезда.
В основном будут использованы такие основные команды: path, rect, circle, line.

  • Изначально создадим паровоз:

.st0 { 
  fill: #A82F2F; 
  stroke: #9F9F9F; 
} 
 
.st1 { 
  opacity: 0.5; 
  fill: #5B5B5B; 
  stroke: #842323; 
} 
 
.st2 { 
  fill: #D34040; 
  stroke: #9F9F9F; 
  stroke-width: 0.5; 
} 
 
.st3 { 
  fill: #932727; 
} 
 
.st4 { 
  fill: #D34040; 
} 
 
.st5 { 
  fill: #5B4343; 
} 
 
.first-tr-str0 { 
  fill: #DDCCCC; 
  stroke: #EAE5E5; 
}
<svg width="250" height="250" viewBox="0 0 350 350" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
<path class="st0" d="M272.8,277.5h-56.2v-72.9c0-9.7,7.9-17.6,17.6-17.6h21c9.7,0,17.6,7.9,17.6,17.6V277.5z" /> 
<line class="st1" x1="258.5" y1="187.5" x2="258.5" y2="275.5" /> 
<line class="st1" x1="231.5" y1="188" x2="231.5" y2="276" /> 
<rect x="200.6" y="275.9" class="st2" width="88" height="66" /> 
<path class="st3" d="M252.5,275.5h-16V196c0-1.6,1.3-3,3-3h10.1c1.6,0,3,1.3,3,3V275.5z" /> 
<circle class="st4" cx="244.5" cy="210.5" r="7.5" /> 
<circle class="st5" cx="244.5" cy="210.5" r="4.5" /> 
<rect width="5" height="20" x="212" y="210" /> 
<rect width="5" height="20" x="212" y="250" /> 
<rect width="5" height="20" x="272" y="210" /> 
<rect width="5" height="20" x="272" y="250" /> 
</svg>

  • Создаём оставшиеся прицепы поезда:

<svg width="400" height="400" viewBox="0 0 600 600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
<g> 
  <rect width="10" height="9" x="240" y="40" /> 
  <rect width="90" height="150" x="200" y="49" fill="gray" rx="5" /> 
</g> 
<g> 
  <rect width="10" height="9" x="240" y="199" /> 
  <rect width="90" height="150" x="200" y="208" fill="gray" rx="5" /> 
</g> 
</svg>

  • Сделаем рельсы от начала до конца ViewBox:

<svg width="400" height="400" viewBox="0 0 600 600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
<defs> 
  <rect id="rect" width="95" height="20" fill="#663300" /> 
</defs> 
<g> 
  <use xlink:href="#rect" x="150" y="10"/> 
  <use xlink:href="#rect" x="150" y="50"/> 
  <use xlink:href="#rect" x="150" y="90"/> 
  <use xlink:href="#rect" x="150" y="130"/> 
  <use xlink:href="#rect" x="150" y="170"/> 
  <use xlink:href="#rect" x="150" y="210"/> 
  <use xlink:href="#rect" x="150" y="250"/> 
  <use xlink:href="#rect" x="150" y="290"/> 
  <use xlink:href="#rect" x="150" y="330"/> 
  <use xlink:href="#rect" x="150" y="370"/> 
</g> 
<g> 
  <line x1="230" y1="400" x2="230" y2="0" stroke="#232b2b" stroke-width="5" /> 
  <line x1="165" y1="400" x2="165" y2="0" stroke="#232b2b" stroke-width="5" /> 
</g> 
</svg>

  • Теперь мы должны сделать анимацию дыма, выходящего из трубы паровоза:

    Будем использовать filter & animateTransform

.st0 { 
  fill: #A82F2F; 
  stroke: #9F9F9F; 
} 
 
.st1 { 
  opacity: 0.5; 
  fill: #5B5B5B; 
  stroke: #842323; 
} 
 
.st2 { 
  fill: #D34040; 
  stroke: #9F9F9F; 
  stroke-width: 0.5; 
} 
 
.st3 { 
  fill: #932727; 
} 
 
.st4 { 
  fill: #D34040; 
} 
 
.st5 { 
  fill: #5B4343; 
} 
 
.first-tr-str0 { 
  fill: #DDCCCC; 
  stroke: #EAE5E5; 
}
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
<defs> 
    <filter id="blur" x="-1" y="-1" width="5" height="5"> 
      <feGaussianBlur in="SourceGraphic" stdDeviation="7" /> 
    </filter> 
</defs> 
<g> 
        <path class="st0" d="M272.8,277.5h-56.2v-72.9c0-9.7,7.9-17.6,17.6-17.6h21c9.7,0,17.6,7.9,17.6,17.6V277.5z" /> 
        <line class="st1" x1="258.5" y1="187.5" x2="258.5" y2="275.5" /> 
        <line class="st1" x1="231.5" y1="188" x2="231.5" y2="276" /> 
        <rect x="200.6" y="275.9" class="st2" width="88" height="66" /> 
        <path class="st3" d="M252.5,275.5h-16V196c0-1.6,1.3-3,3-3h10.1c1.6,0,3,1.3,3,3V275.5z" /> 
        <circle class="st4" cx="244.5" cy="210.5" r="7.5" /> 
        <circle class="st5" cx="244.5" cy="210.5" r="4.5" /> 
        <rect width="5" height="20" x="212" y="210"/> 
        <rect width="5" height="20" x="212" y="250"/> 
        <rect width="5" height="20" x="272" y="210"/> 
        <rect width="5" height="20" x="272" y="250"/> 
        <g> 
          <circle cx="244.5" cy="220.5" r="8.5" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 220.5;90 244.5 220.5" dur="1s" transform="scale(1.1)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="246.5" cy="230.5" r="6" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 246.5 230.5;90 246.5 230.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="238.5" r="7" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 238.5;90 244.5 238.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="245.5" r="4" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 245.5;360 242.5 245.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="250.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 250.5;90 244.5 250.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="246.5" cy="260.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 246.5 260.5;90 246.5 260.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="270.5" r="8" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 270.5;90 246.5 270.5" dur="1s" transform="scale(1.5)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="275.5" r="6" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 275.5;90 242.5 275.5" dur="1s" transform="scale(1.8)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="280.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 280.5;90 242.5 280.5" dur="1s" transform="scale(1.6)" repeatCount="indefinite" 
          /> 
        </g> 
      </g> 
    </svg>

Почти готово, осталось соединить всё в одну конструкцию и сделать анимацию движения поезда по заданной траектории, используя path:

* { 
  margin: 0; 
  padding: 0; 
} 
 
svg { 
  background-color: #ddd; 
} 
 
.st0 { 
  fill: #A82F2F; 
  stroke: #9F9F9F; 
} 
 
.st1 { 
  opacity: 0.5; 
  fill: #5B5B5B; 
  stroke: #842323; 
} 
 
.st2 { 
  fill: #D34040; 
  stroke: #9F9F9F; 
  stroke-width: 0.5; 
} 
 
.st3 { 
  fill: #932727; 
} 
 
.st4 { 
  fill: #D34040; 
} 
 
.st5 { 
  fill: #5B4343; 
} 
 
.first-tr-str0 { 
  fill: #DDCCCC; 
  stroke: #EAE5E5; 
}
<svg width="50%" height="50%" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
<defs>     
    <filter id="blur" x="-1" y="-1" width="5" height="5"> 
      <feGaussianBlur in="SourceGraphic" stdDeviation="8" /> 
    </filter> 
      <rect id="rect" width="95" height="20" fill="#663300" /> 
</defs> 
<g> 
  <use xlink:href="#rect" x="150" y="10"/> 
  <use xlink:href="#rect" x="150" y="50"/> 
  <use xlink:href="#rect" x="150" y="90"/> 
  <use xlink:href="#rect" x="150" y="130"/> 
  <use xlink:href="#rect" x="150" y="170"/> 
  <use xlink:href="#rect" x="150" y="210"/> 
  <use xlink:href="#rect" x="150" y="250"/> 
  <use xlink:href="#rect" x="150" y="290"/> 
  <use xlink:href="#rect" x="150" y="330"/> 
  <use xlink:href="#rect" x="150" y="370"/> 
</g> 
    <g> 
      <line x1="230" y1="400" x2="230" y2="0" stroke="#232b2b" stroke-width="5" /> 
      <line x1="165" y1="400" x2="165" y2="0" stroke="#232b2b" stroke-width="5" /> 
    </g> 
    <g id="train" transform="translate(-350 0)"> 
      <g> 
        <path class="st0" d="M272.8,277.5h-56.2v-72.9c0-9.7,7.9-17.6,17.6-17.6h21c9.7,0,17.6,7.9,17.6,17.6V277.5z" /> 
        <line class="st1" x1="258.5" y1="187.5" x2="258.5" y2="275.5" /> 
        <line class="st1" x1="231.5" y1="188" x2="231.5" y2="276" /> 
        <rect x="200.6" y="275.9" class="st2" width="88" height="66" /> 
        <path class="st3" d="M252.5,275.5h-16V196c0-1.6,1.3-3,3-3h10.1c1.6,0,3,1.3,3,3V275.5z" /> 
        <circle class="st4" cx="244.5" cy="210.5" r="7.5" /> 
        <circle class="st5" cx="244.5" cy="210.5" r="4.5" /> 
        <rect width="5" height="20" x="212" y="210"/> 
        <rect width="5" height="20" x="212" y="250"/> 
        <rect width="5" height="20" x="272" y="210"/> 
        <rect width="5" height="20" x="272" y="250"/> 
        <g> 
          <circle cx="244.5" cy="220.5" r="8.5" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 220.5;360 246.5 220.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="220.5" r="8.5" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 220.5;90 244.5 220.5" dur="1s" transform="scale(1.1)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="246.5" cy="230.5" r="6" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 246.5 230.5;90 246.5 230.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="238.5" r="7" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 238.5;90 244.5 238.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="245.5" r="4" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 245.5;360 242.5 245.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="250.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 250.5;90 244.5 250.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="246.5" cy="260.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 246.5 260.5;90 246.5 260.5" dur="1s" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="244.5" cy="270.5" r="8" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 244.5 270.5;90 246.5 270.5" dur="1s" transform="scale(1.5)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="275.5" r="6" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 275.5;90 242.5 275.5" dur="1s" transform="scale(1.8)" repeatCount="indefinite" 
          /> 
        </g> 
        <g> 
          <circle cx="242.5" cy="280.5" r="9" fill="gray" filter="url(#blur)" /> 
          <animateTransform attributeName="transform" type="rotate" values="0 242.5 280.5;90 242.5 280.5" dur="1s" transform="scale(1.6)" repeatCount="indefinite" 
          /> 
        </g> 
      <g> 
        <rect width="10" height="9" x="240" y="341" /> 
        <rect width="90" height="150" x="200" y="350" fill="gray" rx="5" /> 
      </g> 
      <g> 
        <rect width="10" height="9" x="240" y="500" /> 
        <rect width="90" height="150" x="200" y="509" fill="gray" rx="5" /> 
      </g> 
    </g> 
    <path id="trainPath" style="fill:none;stroke: transparent;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 
      d="m 302.80952,297 c 0,-97.08928571 0,-297.08928571 0,-997.08928571" /> 
    <animateMotion xlink:href="#train" begin="0s" dur="18s" repeatCount="indefinite"> 
      <mpath xlink:href="#trainPath" /> 
    </animateMotion> 
  </svg>

Update: Использовал <use> для оптимизации SVG

Связанный вопрос: Как нарисовать автомобиль с помощью команд SVG

READ ALSO
Карточки товаров одинаковой высоты [требует правки]

Карточки товаров одинаковой высоты [требует правки]

Как сделать что бы при переполнении одной карточки, высота других тоже растягивалась? height: 100%; не желателен

329
Выровнять блок footer внизу под всем

Выровнять блок footer внизу под всем

Не могу выровнять блок footer ниже всего, а выравниваеться по низу блока leftbar

250
Нужны ли сейчас css препроцессоры [требует правки]

Нужны ли сейчас css препроцессоры [требует правки]

Нужны ли сейчас css препроцессоры

193