Интерактивное SVG колесо

213
03 апреля 2021, 10:20

Есть вот такое колесо:

Т.е. нужно сделать 3 сплошных circle, поместить друг в друга и второй разделить на 6 частей.

Цвет элемента будет меняться по нажатию, т.е. плавно из серого переходить в градиент и добавляться верхний border.

Подскажите, как лучше такое реализовать, на SVG или же Canvas? Вот эти иконки будут интерактивно меняться в зависимости от выбранной части, также текст в центре.

Answer 1

Решение SVG + CSS

Окружность можно разделить на 6 отдельных секторов с помощью команды Elliptical Arc для path подробнее здесь

  • Рисуем один сектор

svg { 
  height: 440px; 
  width: 440px; 
} 
.sector { 
  fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
}  
:hover.sector { 
 fill:#9F45E2; 
 stroke-width:6; 
 stroke:#9F45E2; 
 transition: fill 0.5s, stroke-width 0.5s; 
  
}
<svg viewBox='0 0 110 110'> 
 
  <path class="sector " d='M55,55 L30,11.69 A50,50 0 0,1 80,11.69z' /> 
</svg>

  • Добавляем ещё 5 секторов

svg { 
  height: 440px; 
  width: 440px; 
} 
.sector { 
  fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
}  
:hover.sector { 
 fill:#9F45E2; 
 stroke-width:6; 
 stroke:#9F45E2; 
 transition: fill 0.5s, stroke-width 0.5s;
<svg viewBox='0 0 110 110'> 
   
  <!-- Блок секторов -->  
  <path class="sector " d='M55,55 L105,55 A50,50 0 0,1 80,98.30z' /> 
  <path class="sector" d='M55,55 L80,98.30 A50,50 0 0,1 30,98.30z' /> 
  <path class="sector" d='M55,55 L30,98.30 A50,50 0 0,1 5,55z' /> 
  <path class="sector" d='M55,55 L5,55 A50,50 0 0,1 30,11.69z' /> 
  <path class="sector " d='M55,55 L30,11.69 A50,50 0 0,1 80,11.69z' /> 
  <path class="sector" d='M55,55 L80,11.69 A50,50 0 0,1 105,55z' /> 
   
</svg>

Добавляем окружности для создания центральной части, добавляем текст и иконки.

Иконки брал здесь

Для придания нужного размера иконкам используем scale(0.7)

Для позиционирования икон используется команда translate(X Y)

Ниже полный код:

svg { 
  height: 440px; 
  width: 440px; 
} 
.sector { 
  fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
}  
:hover.sector { 
 fill:#9F45E2; 
 stroke-width:6; 
 stroke:#9F45E2; 
 transition: fill 0.5s, stroke-width 0.5s; 
  
} 
#F { 
  fill: #5F5E5F; 
  stroke: #BFBFBF; 
}  
#S { 
  fill: none; 
  stroke: #BFBFBF; 
   stroke-width:5; 
} 
#T { 
  fill: #707070; 
  stroke: #FFFFFF; 
  stroke-width:3; 
} 
.icon { 
fill:none; 
stroke:#CCCACD; 
transition: fill 0.5s; 
} 
:hover.icon { 
fill:#9F45E2; 
} 
</style>
<svg viewBox='0 0 110 110'> 
   
  <!-- Блок секторов -->  
  <path class="sector " d='M55,55 L105,55 A50,50 0 0,1 80,98.30z' /> 
  <path class="sector" d='M55,55 L80,98.30 A50,50 0 0,1 30,98.30z' /> 
  <path class="sector" d='M55,55 L30,98.30 A50,50 0 0,1 5,55z' /> 
  <path class="sector" d='M55,55 L5,55 A50,50 0 0,1 30,11.69z' /> 
  <path class="sector " d='M55,55 L30,11.69 A50,50 0 0,1 80,11.69z' /> 
  <path class="sector" d='M55,55 L80,11.69 A50,50 0 0,1 105,55z' /> 
   
 <circle id="F" cx='55' cy='55' r='25' />  
  <circle id="S" cx='55' cy='55' r='23'  />  
   <circle id="T" cx='55' cy='55' r='22'  />  
    <circle id="Big" cx='55' cy='55' r='50' fill="none" stroke="#BFBFBF" stroke-width="2" />  
   
   
  <text x="55" y="55" font-size="5" fill="white" font-weight="bold"  text-anchor="middle"  > Текст в круге </text>  
   
  <!-- Блок иконок -->  
 <path class="icon" transform="translate(47 10) scale(0.7)" d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm7-7H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-1.75 9c0 .23-.02.46-.05.68l1.48 1.16c.13.11.17.3.08.45l-1.4 2.42c-.09.15-.27.21-.43.15l-1.74-.7c-.36.28-.76.51-1.18.69l-.26 1.85c-.03.17-.18.3-.35.3h-2.8c-.17 0-.32-.13-.35-.29l-.26-1.85c-.43-.18-.82-.41-1.18-.69l-1.74.7c-.16.06-.34 0-.43-.15l-1.4-2.42c-.09-.15-.05-.34.08-.45l1.48-1.16c-.03-.23-.05-.46-.05-.69 0-.23.02-.46.05-.68l-1.48-1.16c-.13-.11-.17-.3-.08-.45l1.4-2.42c.09-.15.27-.21.43-.15l1.74.7c.36-.28.76-.51 1.18-.69l.26-1.85c.03-.17.18-.3.35-.3h2.8c.17 0 .32.13.35.29l.26 1.85c.43.18.82.41 1.18.69l1.74-.7c.16-.06.34 0 .43.15l1.4 2.42c.09.15.05.34-.08.45l-1.48 1.16c.03.23.05.46.05.69z"/> 
   
    
  <path class="icon" transform="translate(80 27) scale(0.7)" d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/> 
   
   <path class="icon" transform="translate(80 66) scale(0.7)" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm4.24 16L12 15.45 7.77 18l1.12-4.81-3.73-3.23 4.92-.42L12 5l1.92 4.53 4.92.42-3.73 3.23L16.23 18z"/>  
  
</svg>

JS

Разбить круг на любое количество секторов можно с помощью javascript, который реализует формулу Elliptical Arc для path

  • Задаются переменные fromAngle, toAngle начального и конечного угла сектора
  • Задаются переменные для расчета начальных и конечных координат сектора fromCoordX, fromCoordY, toCoordX, toCoordY
  • Вызов функции для рисования 6 секторов - createSector(55, 55, 50, 6);, где
    55 координаты центра окружности
    50 - радиус окружности
    6 - количество секторов

var fromAngle, toAngle, fromCoordX, fromCoordY, toCoordX, toCoordY, path, d; 
 
function createSector(cx, cy, r, part) { 
  for (var i = 0; i < part; i++) { 
    path = document.createElementNS("http://www.w3.org/2000/svg", "path"); 
    fromAngle = i * 360 / part; 
    toAngle = (i + 1) * 360 / part; 
    fromCoordX = cx + (r * Math.cos(fromAngle * Math.PI / 180)); 
    fromCoordY = cy + (r * Math.sin(fromAngle * Math.PI / 180)); 
    toCoordX = cx + (r * Math.cos(toAngle * Math.PI / 180)); 
    toCoordY = cy + (r * Math.sin(toAngle * Math.PI / 180)); 
    d = 'M' + cx + ',' + cy + ' L' + fromCoordX + ',' + fromCoordY + ' A' + r + ',' + r + ' 0 0,1 ' + toCoordX + ',' + toCoordY + 'z'; 
    path.setAttributeNS(null, "d", d); 
    document.getElementById('pie').appendChild(path); 
  } 
} 
 
createSector(55, 55, 50, 6);
svg { 
  height: 220px; 
  width: 220px; 
} 
path { 
   fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
} 
<svg viewBox="0 0 110 110" id="pie"></svg>

8 секторов

var fromAngle, toAngle, fromCoordX, fromCoordY, toCoordX, toCoordY, path, d; 
 
function createSector(cx, cy, r, part) { 
  for (var i = 0; i < part; i++) { 
    path = document.createElementNS("http://www.w3.org/2000/svg", "path"); 
    fromAngle = i * 360 / part; 
    toAngle = (i + 1) * 360 / part; 
    fromCoordX = cx + (r * Math.cos(fromAngle * Math.PI / 180)); 
    fromCoordY = cy + (r * Math.sin(fromAngle * Math.PI / 180)); 
    toCoordX = cx + (r * Math.cos(toAngle * Math.PI / 180)); 
    toCoordY = cy + (r * Math.sin(toAngle * Math.PI / 180)); 
    d = 'M' + cx + ',' + cy + ' L' + fromCoordX + ',' + fromCoordY + ' A' + r + ',' + r + ' 0 0,1 ' + toCoordX + ',' + toCoordY + 'z'; 
    path.setAttributeNS(null, "d", d); 
    document.getElementById('pie').appendChild(path); 
  } 
} 
 
createSector(55, 55, 50, 8);
svg { 
  height: 220px; 
  width: 220px; 
} 
path { 
  fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
}
<svg viewBox="0 0 110 110" id="pie"></svg>

12 секторов

var fromAngle, toAngle, fromCoordX, fromCoordY, toCoordX, toCoordY, path, d; 
 
function createSector(cx, cy, r, part) { 
  for (var i = 0; i < part; i++) { 
    path = document.createElementNS("http://www.w3.org/2000/svg", "path"); 
    fromAngle = i * 360 / part; 
    toAngle = (i + 1) * 360 / part; 
    fromCoordX = cx + (r * Math.cos(fromAngle * Math.PI / 180)); 
    fromCoordY = cy + (r * Math.sin(fromAngle * Math.PI / 180)); 
    toCoordX = cx + (r * Math.cos(toAngle * Math.PI / 180)); 
    toCoordY = cy + (r * Math.sin(toAngle * Math.PI / 180)); 
    d = 'M' + cx + ',' + cy + ' L' + fromCoordX + ',' + fromCoordY + ' A' + r + ',' + r + ' 0 0,1 ' + toCoordX + ',' + toCoordY + 'z'; 
    path.setAttributeNS(null, "d", d); 
    document.getElementById('pie').appendChild(path); 
  } 
} 
 
createSector(55, 55, 50, 12);
svg { 
  height: 220px; 
  width: 220px; 
} 
path { 
 fill: #5F5E5F; 
  stroke: #BFBFBF; 
  stroke-width:2; 
}
<svg viewBox="0 0 110 110" id="pie"></svg>

Answer 2

Сверстал что-то подобное, при помощи синусов да косинусов. чтобы получить прямо точь в точь что и в макете надо еще с этим посидеть. пока так, для понимания я думаю хватит.

let items = ['        
    
Answer 3

В общем я только с градиентной заливкой на hover завис ..а так все хотелки выполнены

Если что то не ясно спрашивайте, не применял алгоритмов и само изготовление не сложное

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css"> 
 
<svg width="400" height="400" viewbox="0 0 4 4"> 
 
 	   <defs> 
 	   	<style> 
 	   		.hover{ 
 	   			stroke-opacity: 0; 
 	   		} 
 	   		g:hover .hover{ 
 	   			stroke-opacity: 1; 
 	   		} 
 	   		g:hover text{ 
 	   			fill: red; 
 	   		} 
 	   	</style> 
 	   </defs> 
 
      <circle cx="2" cy="2" r="1.05"  
       fill="none" 
       stroke="lightgreen" 
       stroke-width="1.06"/> 
 
       <circle cx="2" cy="2" r="0.45"  
       fill="lightgreen"/> 
       <text font-size="0.1" 
       x="1.66"  
       y="2.05" 
       font-family="sans-serif"> текст в центре </text> 
 
<g> 	   
 	  <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="-0.01"/> 
 	  <text x="2.7" y="2.7" 
 	  font-family="FontAwesome" 
 	  font-size="0.5px"  
 	  fill="lightgreen"></text><!--android--> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-0.01" class="hover"/> 
</g> 
<g> 
      <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="-1.05"/> 
 	  <text x="1.7" y="3.2" 
      font-family="FontAwesome" 
      fill="lightgreen" 
 	  font-size="0.5px"  
 	  ></text> <!--руки--> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-1.6" class="hover"/> 
</g> 
<g> 
 
 	  <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="-2.1"/> 
 	  <text x="0.85" y="2.6" 
      font-family="FontAwesome" 
      fill="lightgreen" 
 	  font-size="0.5px"  
 	  ></text> <!--замок--> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-3.17" class="hover"/> 
</g> 
<g> 
 
	  <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="3.86"/> 
 	  <text x="0.85" y="1.7" 
      font-family="FontAwesome" 
      fill="lightgreen" 
 	  font-size="0.5px"  
 	  ></text> <!--душ--> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-4.71" class="hover"/> 
</g> 
<g> 
 
 	  <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="2.8"/> 
 	  <text x="1.75" y="1.2" 
      font-family="FontAwesome" 
      fill="lightgreen" 
 	  font-size="0.5px"  
 	  ></text> <!--бинокль--> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-6.3"  class="hover"/> 
</g> 
<g> 
 
  	  <circle cx="2" cy="2" r="1"  
 	  fill="none"  
 	  stroke="lightblue" 
 	  stroke-width="1"  
 	  stroke-dasharray="1 6"  
 	  stroke-dashoffset="1.75"/> 
	  <text x="2.5" y="1.7" 
      font-family="FontAwesome" 
      fill="lightgreen" 
 	  font-size="0.5px"  
 	  ></text> <!--велосипед --> 
 	  <circle cx="2" cy="2" r="1.5" 
 	  fill="none" 
 	  stroke="red" 
 	  stroke-width="0.1"  
 	  stroke-dasharray="1.49 9" 
 	  stroke-dashoffset="-7.9" class="hover"/> 
</g>  
 
 </svg>

READ ALSO
Ошибка ASP.Net Core

Ошибка ASP.Net Core

Всем привет, возникла ошибкаНа сколько я понимаю возникает исключение при попытке доступа к члену типа, значение которого равно null

163
WInForms. Назначить функцию onClick форме

WInForms. Назначить функцию onClick форме

Если вы напишите itemKey

164
Поиск через group by

Поиск через group by

Пытаюсь реализовать поиск в DataGrid используя оператор group by, но не получается реализовать вывод содержимого в DataGridВод код: Событие поиска:

132
Как перенести элемент на задний план WPF C#

Как перенести элемент на задний план WPF C#

Установил библиотеку MediaPlayerWpf и возникла проблема при наложении на передний план других объектовXaml такого вида

134