#javascript #html #css #svg
Товарищи, подскажите! Куда копать, возможно ли это вообще - как реализовать такой круг в html, чтобы при клике на конкретное меню - оно вращалось и выбранное меню становилось на верх (как колесо фортуны, но не рандом). Интересует так же, как это изобразить в коде? Достаточно только css или нужно что-то еще? Есть какие то примеры, наводки? Update: Заново прошу помощи! Есть вот такой круг (спасибо MaximLensky): codepen.io/topicstarter/pen/dExqLr Как сделать из него семиугольник (здесь пятиугольник). А так же добавить сверху такие меню, как на картинке? Как его анимировать, чтобы при нажатии на элемент - круг вращался и наверх по центру становился выбранный элемент, изменялся цвет? Дополнительные меню сверху - просто ссылки, такого же цвета, как и основной элемент. Важно, чтобы текст и цвета можно было изменить. Так же прикрепляю примерно что-то похожее (вращение): codepen.io/AndersFly666/pen/GZxVYO
Ответы
Ответ 1
Что касается верстки всяких разных кругов, тут ваши лучшие друзья это Math.sin Math.cos и Math.PI Вот пример с использованием d3.js, но могло быть и без него PS: длинный текст надо тоже вписать в круг и его вращать Самая актуальная версия тут https://codepen.io/strangerintheq/pen/wbVRGL let data = Array(5).fill(0).map(object) let a = Math.PI*2/data.length, start = -Math.PI/2 let r1 = 30, r2 = 35, r3 = 37, r4 = 95; let basePts = []; basePts.push(pt(0, r1)) basePts.push(pt(a, r2)) basePts.push(pt(a*2-0.15, r3)) basePts.push(pt(a*1.5-0.1, r4)) let arc = `A ${r4} ${r4} 0 0 1 ${pt(a/2, r4)}` ; append('path', 'line') .attr('stroke', d => d.color) .attr('fill', 'none') .attr('d', 'M' + basePts.join('L') + arc) .attr('transform', (d, i) => `rotate(${-i*360/data.length})`) append('text', 'icon') .attr('fill', d => d.color) .html(d => d.icon) .attr('x', (e, i) => pt(a*i+a*0.7,80)[0]) .attr('y', (e, i) => pt(a*i+a*0.7,80)[1]) append('text', 'number') .attr('fill', d => d.color) .html((d, i) => i+1) .attr('x', (e, i) => pt(a*i+a*1.5,44)[0]) .attr('y', (e, i) => pt(a*i+a*1.5,44)[1]) basePts.shift(); append('path', 'active') .attr('d', 'M' + basePts.join('L') + arc) .attr('transform', (d, i) => `rotate(${-i*360/data.length})`) .on('click', (d,i) => { let angle = (i + 1)*360 / data.length d3.select('g').attr('transform', `rotate(${angle})`) d3.selectAll('text').attr('transform', function(){ let x = d3.select(this).attr('x') let y = d3.select(this).attr('y') return `rotate(${-angle},${x},${y})`; }) }) function append(node, clazz) { return d3.select('g') .selectAll(node + '.' + clazz) .data(data) .enter() .append(node) .classed(clazz, true) } function pt (a, r) { a = - a - Math.PI/2 return [Math.cos(a)*r, Math.sin(a)*r]; } function object(){ return { color: `hsl(${Math.random()*360},55%,55%)`, icon: `ð${Math.floor(Math.random()*100)};` } } text { stroke: transparent; dominant-baseline: middle; text-anchor: middle; } .icon { font-family: FontAwesome; font-size: 20px; transition: 1s; } .number { font-family: arial, sans-serif; font-size: 15px; transition: 1s; } path.active{ fill: transparent; cursor: pointer; } g { transition: 1s; } UPD: Классика жанра, в макете 5 углов, но надо 7, как хорошо что я не умею делать это в inkscape, я просто поменяю пару цифр в своем коде let data = Array(7).fill(0).map(object) let a = Math.PI*2/data.length, start = -Math.PI/2 let r1=30, r2=35, r3=37, r4=95, rotation=0; let pts = []; pts.push(pt(0, r1)) pts.push(pt(a, r2)) pts.push(pt(a*2-0.15, r3)) pts.push(pt(a*1.5-0.45, r4)) let arc = (radius, angle) => `A ${radius} ${radius} 0 0 1 ${pt(angle, radius)}` ; append('path', 'line') .attr('stroke', d => d.color) .attr('d', 'M' + pts.join('L') + arc(r4, a-0.7)) .attr('transform', (d, i) => `rotate(${-i*360/data.length})`) append('text', 'icon rotate') .attr('fill', d => d.color) .html(d => d.icon) .attr('x', (e, i) => pt(a*i+a*0.35,80)[0]) .attr('y', (e, i) => pt(a*i+a*0.35,80)[1]) append('path', 'text-wrap-path') .attr('id', (d, i) => `text-wrap-path_${i}`) .attr('x', (e, i) => pt(a*i+a*0.77,67)[0]) .attr('y', (e, i) => pt(a*i+a*0.77,67)[1]) .attr('d', (e, i) => { let c = pt(a*i+a*0.77,67); return Array(5).fill(0).map((e,i) => line(Math.acos(1-2/5*i))) function line(a) { let p1 = pt(a, 21), p2 = pt(-a, 21); return 'M' + (c[0]+p1[0]) + ',' + (c[1]+p1[1]) + 'L' + (c[0]+p2[0]) + ',' + (c[1]+p2[1]) } }) append('text', 'text') .append('textPath') .attr('href', (e,i) => `#text-wrap-path_${i}`) .text(d => d.text) .attr('fill', d => d.color) .attr('startOffset', 40) append('text', 'number rotate') .attr('fill', d => d.color) .html((d, i) => i + 1) .attr('x', (e, i) => pt(a*i+a*1.2,44)[0]) .attr('y', (e, i) => pt(a*i+a*1.2,44)[1]) pts.shift(); append('path', 'active') .attr('fill', 'transparent') .attr('d', 'M' + pts.join('L') + arc(r4, a-0.7)) .attr('transform', (d, i) => `rotate(${-i*360/data.length})`) .on('click', click) lineAndText(r4+15, 0) lineAndText(r4+30, 1) lineAndText(r4+45, 2) function lineAndText(r,n){ append('path', 'line1 l' + n) .attr('id', (d, i) => `line1_l${n}_${i}`) .attr('stroke', d => d.color) .attr('d', 'M' + pt(a-0.05*(n+1), r) + arc(r, 0.2-0.05*(n+1))) .attr('transform', (d, i) => `rotate(${-i*360/data.length})`) append('text', 'menu l' + n) .append('textPath') .attr('href', (e,i) => `#line1_l${n}_${i}`) .text(d => d.menu[n]) .attr('fill', d => d.color) .attr('startOffset', 40) } function click(d,i) { let angle = (i+1)*360/data.length-30 let from = rotation; rotation = angle; d3.selectAll('.line1').style('opacity', 0) d3.selectAll('.line1.index_'+i).style('opacity', 1) d3.selectAll('.menu').style('opacity', 0) d3.selectAll('.menu.index_'+i).style('opacity', 1) d3.select('g').transition().duration(1000) .attrTween('transform', () => t => `rotate(${from+(angle-from)*t})`) d3.selectAll('.text-wrap-path').transition().duration(1000) .attrTween('transform', function() { let x = d3.select(this).attr('x') let y = d3.select(this).attr('y') return t => `rotate(-${from+(angle-from)*t}, ${x}, ${y})` }) d3.selectAll('text.rotate').transition().duration(1000) .attrTween('transform', function() { let x = d3.select(this).attr('x') let y = d3.select(this).attr('y') return t => `rotate(-${from+(angle-from)*t}, ${x}, ${y})` }) } function append(node, clazz) { return d3.select('g') .selectAll(node + '.' + clazz) .data(data) .enter() .append(node) .attr('fill', 'none') .attr('class', (d, i) => `${clazz} index_${i}`) } function pt (a, r) { a = - a - Math.PI/2 return [Math.cos(a)*r, Math.sin(a)*r]; } function object(){ return { color: `hsl(${Math.random()*360},55%,55%)`, icon: `ð${Math.floor(Math.random()*100)};`, menu: [`menu 1`, `menu 2`, `menu 3`], text: 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur'.split(' ').filter(() => Math.random() > 0.5).join(' ') } } text { stroke: transparent; dominant-baseline: middle; text-anchor: middle; } .icon { font-family: FontAwesome; font-size: 18px; } .number { font-family: arial, sans-serif; font-size: 15px; } path.active{ cursor: pointer; } .line1, .menu { opacity: 0; transition: 1s; } text.menu{ dominant-baseline: text-before-edge; font-size:13px; cursor:pointer; } textPath { transition: 500ms; } text.menu:hover textPath { fill: red; } text.text { font-size: 8px; }Ответ 2
Накидал макет на Svg в редакторе векторной графики Inkscape Для этого я вырезал в Gimp нужный фрагмент, и загрузил в inkscape, преимущественно пользовался инструментом path без закрутия пути Символы добавил с font-awesome что потребовало подключения самого шрифта с cdn и обычное копирование и вставка самой иконки
Комментариев нет:
Отправить комментарий