Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Как сделать сектора в пончике со скругленными углами?

#javascript #svg #canvas #chart #chart.js


  

Как это сделать?
Мне нужен мульти-сектор в пончике с закругленными концами и добавить тень самому
пончику.   

Хочу использовать chart.js, но можно и другие варианты без jquery. 
    


Ответы

Ответ 1



Есть вариант сделать с помощью SVG. На последней секции(#part4) в качестве примера заливка градиентом. UPD: Добавил еще вариант без CSS .circle { height: 200px; width: 200px; fill: none; stroke-width: 5; stroke-linecap: round; position: absolute; left:0; top:0; } #part1 { stroke: #172bc3; z-index: 3; transform: rotate(20deg); } #part2 { stroke: #f21d92; z-index: 2; transform: rotate(-70deg); } #part3 { stroke: #9631eb; z-index: 5; transform: rotate(-160deg); } #part4 { stroke: url(#gradient); z-index: 4; transform: rotate(-250deg); } #shadow { stroke: white; z-index:1; stroke-width: 2; }

Ответ 2



Решается вопрос с помощью SVG. Применил circles, вместо paths( почему бы и нет?:D ):

Ответ 3



Вариант SVG без CSS

Ответ 4



Решение с Chart.js начиная от 2.1.0+ Chart.pluginService.register({ afterUpdate: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { items=chart.config.options.elements.arc.roundedCornersFor; items.forEach(function(element) { var arc = chart.getDatasetMeta(0).data[element]; arc.round = { x: (chart.chartArea.left + chart.chartArea.right) / 2, y: (chart.chartArea.top + chart.chartArea.bottom) / 2, radius: (chart.outerRadius + chart.innerRadius) / 2, thickness: (chart.outerRadius - chart.innerRadius) / 2 - 1, backgroundColor: arc._model.backgroundColor } }); } }, afterDraw: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { var ctx = chart.chart.ctx; items=chart.config.options.elements.arc.roundedCornersFor; items.forEach(function(element) { var arc = chart.getDatasetMeta(0).data[element]; var startAngle = Math.PI / 2 - arc._view.startAngle; var endAngle = Math.PI / 2 - arc._view.endAngle; ctx.save(); ctx.translate(arc.round.x, arc.round.y); ctx.fillStyle = arc.round.backgroundColor; ctx.beginPath(); //получаются артефакты //ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); ctx.restore(); }); } }, }); var settings = { type: 'doughnut', data: { labels: [], datasets: [{ data: [25, 25, 25,25], backgroundColor: [ "#363edc", "#48d0f0", "#9a31eb", "#f11e94" ], hoverBackgroundColor: [ "#363edc", "#48d0f0", "#9a31eb", "#f11e94" ] }] }, options: { rotation: 10, cutoutPercentage: 80, legend: { display: false }, tooltips: { enabled: false }, elements: { arc: { roundedCornersFor: [0,1,2,3] } } } }; var ctx = document.getElementById("myTest").getContext("2d"); var myChart = new Chart(ctx, settings);

Ответ 5



D3.js вариация, похожий ответ. Обратите внимание на заморочку, что бы перекрытие было не как в макете дизайнера, а правильно, в одну сторону. Похожие перекрытия в ответе господина @Pavel с решением на Chart.js let overlap = 0.2, duration = 1000, count = 2 + Math.floor(Math.random() * 5), data = Array(count).fill(0).map((d, i) => ({value: 1 + 5*Math.random()})); let svg = d3.select('#donut g'); let pie = d3.pie().sort(null); // let arc = d3.arc().innerRadius(70).outerRadius(85); let d = pie(data.map(d => d.value)); d.forEach(d => d.endAngle += overlap); drawArcs("right"); drawArcs("left"); function drawArcs(className) { let right = className === "right"; svg.selectAll("path." + className).data(d).enter() .append("path").classed(className, true) .attr("fill", (d, i) => `hsl(${i*77},75%,45%)`) .transition().duration(duration).attrTween('d', tween) function tween(d) { let center = (d.startAngle+d.endAngle)/2; let interpolator = d3.interpolate(center, right ? d.endAngle : d.startAngle) return t => { let v = interpolator(t); d.startAngle = right ? center - overlap*t : v; d.endAngle = right ? v : center + overlap*t; return arc.cornerRadius(10*t)(d); } } } UPD: по просьбам трудящихся добавил сделал вариант с анимацией заполнения в одну сторону. let overlap = 0.2, duration = 1000, count = 2 + Math.floor(Math.random() * 5), data = Array(count).fill(0).map((d, i) => ({value: 1 + 5*Math.random()})); let svg = d3.select('#donut g'); let pie = d3.pie().sort(null); // let arc = d3.arc().innerRadius(70).outerRadius(85); let d = pie(data.map(d => d.value)); d.forEach(d => d.endAngle += overlap); drawArcs("right"); drawArcs("left"); function drawArcs(className) { let right = className === "right"; svg.selectAll("path." + className).data(d).enter() .append("path").classed(className, true) .attr("fill", (d, i) => `hsl(${i*77},75%,45%)`) .transition().duration(duration).attrTween('d', tween) function tween(d) { let center = d.startAngle; let interpolator = d3.interpolate(center, right ? d.endAngle : d.startAngle) return t => { let v = interpolator(t); d.startAngle = right ? center : v; d.endAngle = right ? v : center + overlap*t; return arc.cornerRadius(10*t)(d); } } }

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

Отправить комментарий