简体   繁体   中英

How to create a rounded hexagon with javascript andCANVAS

I created this codepen to show what I got.

在此处输入图像描述

I managed to generate a hexagon avatar with progressbar around it using the awesome open source Hexagon Progress jQuery Plugin from Max Lawrence.

He also helped me to improve his own code a little but I don't want to bother him again.

Maybe someone here can help me to round the corners of this hexagon.

I want it to looks something like this (from the awesome Vikinger Html template) but need to be open source because my software is all open source. I can't use the Vikinger code.

在此处输入图像描述

So far I read that I have to stop the line before the end and add a quadratic curve to the next line start but I could not managed to do that.

His code do something like this on line 505:

ctx.moveTo(this.coordBack[0].x + offset, this.coordBack[0].y + offset);
for(var i = 0; i < this.coordBack.length; i++) {
    ctx.lineTo(this.coordBack[i].x + offset, this.coordBack[i].y + offset);
}

Unfortunatelly, I am not that good in javascript or math.

Two ways to do this. The easy way, and the long winded, lots of math way.

Easy rounded corners

To create simple rounded polygons you can use ctx.arcTo . It will do all the math for the corners.

To create the polygon the following functions create a point and a path (array of points)

const Point = (x,y) => ({x, y});
function polygon(sides, rad, rot = 0) {
    var i = 0, step = Math.PI * 2 / sides, path = [];
    while (i < sides) {
        path.push(Point(Math.cos(i * step + rot) * rad, Math.sin((i++) * step + rot) * rad));
    }
    return path;
}

To create a hexagon. Note that the polygon is centered over its local origin 0,0

const hexagon = polygon(6, 100);

To render the rounded polygon you need to work from the line segment centers. The following function will stroke the path with the rounded corners.

function strokeRoundedPath(cx, cy, path, radius, style, width) {
    ctx.setTransform(1,0,0,1,cx,cy);
    var i = 0;
    const len = path.length
    var p1 = path[i++], p2 = path[i];
    ctx.lineWidth = width;
    ctx.lineCap = "round";
    ctx.strokeStyle = style;
    
    ctx.beginPath();
    
    ctx.lineTo((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
    while (i <= len) {
        p1 = p2;
        p2 = path[(++i) % len];
        ctx.arcTo(p1.x, p1.y, (p1.x + p2.x) / 2, (p1.y + p2.y) / 2, radius);
    }
    ctx.closePath();
    ctx.stroke();
    ctx.setTransform(1,0,0,1,0,0);
}

strokeRoundedPath(200, 200, hexagon, 20, "#000", 18);

Progress bar

Creating a progress bar is not as simple as the starting point can not be on a rounded corner, and moving over the rounded corners will need a lot of math to get the correct coordinates. This will negate the point of using easy arcTo and need us to write the equivalent in JS (Way to slack for that today)

Using line dash for progress

There is however a hack that uses the line dash to create the effect you may be happy with. The snippet demonstrates this

 const barWidth = 10; const cornerRadius = barWidth * 2 + 8; const polyRadius = 100; const inset = 1; const barRadius = polyRadius - barWidth * inset; var progress = 0.0; const approxLineLen = barRadius * Math.PI * 2; const hexBar = polygon(6, barRadius); const hexPoly = polygon(6, polyRadius); const hexPolyInner = polygon(6, polyRadius - barWidth * 2 * inset); const ctx = canvas.getContext("2d"); ctx.setLineDash([approxLineLen]); loop() function point(x,y) { return {x, y} } function polygon(sides, radius, rot = 0) { var i = 0; const step = Math.PI * 2 / sides, path = []; while (i < sides) { path.push(point(Math.cos(i * step + rot) * radius, Math.sin((i++) * step + rot) * radius)); } return path; } function roundedPath(path, radius) { var i = 0, p1 = path[i++], p2 = path[i]; const len = path.length ctx.moveTo((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); while (i <= len) { p1 = p2; p2 = path[(++i) % len]; ctx.arcTo(p1.x, p1.y, (p1.x + p2.x) / 2, (p1.y + p2.y) / 2, radius); } } function strokeRoundedPath(cx, cy, path, radius, style, width) { ctx.setTransform(1,0,0,1,cx,cy); ctx.lineWidth = width; ctx.lineCap = "round"; ctx.strokeStyle = style; ctx.beginPath(); roundedPath(path, radius); ctx.closePath(); ctx.stroke(); } function fillRoundedPath(cx, cy, path, radius, style) { ctx.setTransform(1,0,0,1,cx,cy); ctx.fillStyle = style; ctx.beginPath(); roundedPath(path, radius); ctx.fill(); } function loop() { ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0,0,canvas.width,canvas.height); fillRoundedPath(polyRadius, polyRadius, hexPoly, cornerRadius, "#000"); fillRoundedPath(polyRadius, polyRadius, hexPolyInner, cornerRadius - barWidth * inset * 2, "#F80"); ctx.lineDashOffset = approxLineLen - (progress % 1) * approxLineLen; strokeRoundedPath(polyRadius, polyRadius, hexBar, cornerRadius - barWidth * inset, "#09C", barWidth); progress += 0.005; requestAnimationFrame(loop); }
 <canvas id="canvas" width = "210" height="210"></canvas>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM