如何使用javascript和CANVAS创建圆角六边形 [英] How to create a rounded hexagon with javascript andCANVAS

查看:85
本文介绍了如何使用javascript和CANVAS创建圆角六边形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了

我使用Max Lawrence的超棒开源Hexagon Progress jQuery插件生成了一个带有进度条的六边形头像.

他还帮助我改善了自己的代码,但我不想再打扰他.

也许有人可以帮我把这个六角形的角弄圆.

我希望它看起来像这样(来自真棒的Vikinger HTML模板),但需要开源,因为我的软件都是开源的.我不能使用维京人代码.

到目前为止,我读到我必须在行尾之前停止行,并在下一条行开始处添加二次曲线,但是我无法做到这一点.

他的代码在505行中执行以下操作:

 <代码> ctx.moveTo(this.coordBack [0] .x +偏移量,this.coordBack [0] .y +偏移量);for(var i = 0; i< this.coordBack.length; i ++){ctx.lineTo(this.coordBack [i] .x +偏移量,this.coordBack [i] .y +偏移量);} 

不幸的是,我的JavaScript或数学能力都不强.

解决方案

两种方法可以做到这一点.简单的方法,以及漫长而漫长的数学方法.

简单的圆角

要创建简单的圆形多边形,可以使用 ctx.arcTo .它将完成所有角的数学运算.

要创建多边形,以下函数将创建一个点和一个路径(点的数组)

  const Point =(x,y)=>({x,y});函数多边形(边,弧度,腐烂= 0){var i = 0,step = Math.PI * 2/边,path = [];而(i<双方){path.push(Point(Math.cos(i * step + rot)* rad,Math.sin((i ++)* step + rot)* rad));}返回路径;} 

创建一个六边形.请注意,多边形以其本地原点0,0为中心

  const六边形=多边形(6,100); 

要渲染圆角多边形,您需要从线段中心进行操作.以下功能将用圆角描边路径.

  function strokeRoundedPath(cx,cy,path,radius,style,width){ctx.setTransform(1,0,0,1,cx,cy);var i = 0;const len = path.lengthvar p1 = path [i ++],p2 = path [i];ctx.lineWidth =宽度;ctx.lineCap ="round";ctx.strokeStyle =样式;ctx.beginPath();ctx.lineTo((p1.x + p2.x)/2,(p1.y + p2.y)/2);而(i< = len){p1 = p2;p2 = path [(++ i)%len];ctx.arcTo(p1.x,p1.y,(p1.x + p2.x)/2,(p1.y + p2.y)/2,半径);}ctx.closePath();ctx.stroke();ctx.setTransform(1,0,0,1,0,0);}strokeRoundedPath(200、200,六角形,20,#000",18); 

进度栏

创建进度条并不像起点不能位于圆角上那样简单,并且在圆角上移动将需要大量数学运算才能获得正确的坐标.这将否定使用简单的 arcTo 的意义,并且需要我们用JS编写等效内容(今天要放松一下)

使用破折号取得进展

但是,有一种黑客使用破折号来创建您可能满意的效果.该片段演示了这一点

  const barWidth = 10;const cornerRadius = barWidth * 2 + 8;const polyRadius = 100;const inset = 1;const barRadius = polyRadius-barWidth * inset;var progress = 0.0;constroxLineLen = barRadius * Math.PI * 2;const hexBar =多边形(6,barRadius);const hexPoly =多边形(6,polyRadius);const hexPolyInner =多边形(6,polyRadius-barWidth * 2 * inset);const ctx = canvas.getContext("2d");ctx.setLineDash([approxLineLen]);环形()功能点(x,y){返回{x,y}}函数多边形(边,半径,腐烂= 0){var i = 0;const step = Math.PI * 2/边,路径= [];一会儿(我<双方){path.push(point(Math.cos(i * step + rot)*半径,Math.sin((i ++)* step + rot)*半径));}返回路径;}函数roundedPath(path,radius){var i = 0,p1 =路径[i ++],p2 =路径[i];const len = path.lengthctx.moveTo((p1.x + p2.x)/2,(p1.y + p2.y)/2);而(i< = len){p1 = p2;p2 = path [(++ i)%len];ctx.arcTo(p1.x,p1.y,(p1.x + p2.x)/2,(p1.y + p2.y)/2,半径);}}函数strokeRoundedPath(cx,cy,路径,半径,样式,宽度){ctx.setTransform(1,0,0,1,cx,cy);ctx.lineWidth =宽度;ctx.lineCap =圆形";ctx.strokeStyle =样式;ctx.beginPath();roundedPath(路径,半径);ctx.closePath();ctx.stroke();}函数fillRoundedPath(cx,cy,路径,半径,样式){ctx.setTransform(1,0,0,1,cx,cy);ctx.fillStyle =样式;ctx.beginPath();roundedPath(路径,半径);ctx.fill();}函数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 =大约直线长度-(进度%1)*大约直线长度;strokeRoundedPath(polyRadius,polyRadius,hexBar,cornerRadius-barWidth * inset,#09C",barWidth);进度+ = 0.005;requestAnimationFrame(loop);}  

 <画布id ="canvas" width ="210" height ="210"></canvas> 

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 arcToand 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>

这篇关于如何使用javascript和CANVAS创建圆角六边形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆