Canvas绘制六边形网格

使用Canvas绘制六边形网格。
主要思路是先画给定中心点的六边形,然后二重循环遍历所有中心点,画所有的六边形。

<!DOCTYPE HTML>
<html>
<body>

<canvas id="myCanvas" width="300" height="150">
    <p>你的浏览器不支持Canvas</p>
</canvas>
<br>
<p id='p1'></p>
<script type="text/javascript">
"use strict";
var canvas=document.getElementById('myCanvas');
if (canvas.getContext) {
    var k=3;
    var d=30;
    var w=Math.sqrt(3)*d;
    var h=3/2*d;
    canvas.width=2*k*w;
    canvas.height=2*k*h+h/2;
    var o=[canvas.width/2,canvas.height/2];
    document.getElementById('p1').innerHTML='画布宽'+canvas.width+',高'+canvas.height;
    var ctx=canvas.getContext('2d');
    ctx.fillStyle='AntiqueWhite';
    ctx.fillRect(0,0,canvas.width,canvas.height);
    ctx.strokeStyle='blue';
    ctx.beginPath();
    var vs=[[0,d],[-w/2,d/2],[-w/2,-d/2],
            [0,-d],[w/2,-d/2],[w/2,d/2]];
    function one(xo,yo){
        ctx.moveTo(xo+vs[5][0],yo+vs[5][1]);
        for(var i=0;i<vs.length;i++){
            ctx.lineTo(xo+vs[i][0],yo+vs[i][1]);
        }
    }
    for(var i=-k+1;i<k;i++){
        for(var j=0;j<2*k-1-Math.abs(i);j++){
            one(o[0]+(-k+1+Math.abs(i)/2+j)*w,o[1]+h*i);
        }
    }
    ctx.stroke();
}
else{
    console.log('你的浏览器不支持Canvas');
}
</script>

</body>
</html>

效果如下:
在这里插入图片描述
更新:增加了一些选项,边长和颜色可以设置。网页的图标也用六边形画出。

<!DOCTYPE HTML>
<html>
<head>
<title>六边形网格</title>
<link id="link" rel="shortcut icon" type="image/x-icon">
<style>
#bc1,#bc2{width:25px;}
#bj,#xt,#tc{width:20px;}
</style>
</head>
<body>
<p>设置大六边形边长: <input id='bc1' value="3" onchange="generate()"> 小六边形<br>
设置小六边形边长: <input id='bc2' value="24" onchange="generate()"> 像素(px)<br>
设置背景色 <input type="color" id="bj" value="#c8ffff" onchange="generate()"/>
设置线条色 <input type="color" id="xt" value="#0000ff" onchange="generate()"/>
设置填充色 <input type="color" id="tc" value="#faebd7" onchange="generate()"/></p>
<p id='p1'></p>
<canvas id="myCanvas" width="300" height="150">
<p>你的浏览器不支持Canvas</p>
</canvas>
<script type="text/javascript">
"use strict";
document.getElementById('bc1').value=2;
generate();
link.href=myCanvas.toDataURL({format:'image/png', quality:1});
document.getElementById('bc1').value=3;
generate();
function generate(){
    var bc1=document.getElementById('bc1').value;
    var bc2=document.getElementById('bc2').value;
    var k=Number(bc1);
    var d=Number(bc2);
    var bj=document.getElementById('bj').value;
    var xt=document.getElementById('xt').value;
    var tc=document.getElementById('tc').value;
    var canvas=document.getElementById('myCanvas');
    if(bc1>200){
        var c=confirm('六边形个数过多时网页会卡,是否继续?');
        if(!c){
            return;
        }
    }
    if(canvas.getContext) {
        var w=Math.sqrt(3)*d;
        var h=3/2*d;
        var count=3*k*k-3*k+1;
        canvas.width=2*k*w;
        canvas.height=2*k*h+h/2;
        var o=[canvas.width/2,canvas.height/2];
        document.getElementById('p1').innerHTML='画布宽'+canvas.width+'px,高'+canvas.height+'px,含有'+count+'个小六边形';
        var ctx=canvas.getContext('2d');
        ctx.fillStyle=bj;
        ctx.fillRect(0,0,canvas.width,canvas.height);
        ctx.beginPath();
        var vs=[[0,d],[-w/2,d/2],[-w/2,-d/2],[0,-d],[w/2,-d/2],[w/2,d/2]];
        function one(xo,yo){
            ctx.beginPath();
            ctx.moveTo(xo+vs[5][0],yo+vs[5][1]);
            for(var i=0;i<vs.length;i++){
                ctx.lineTo(xo+vs[i][0],yo+vs[i][1]);
            }
            ctx.strokeStyle=xt;
            ctx.lineWidth=2;
            ctx.stroke();
            ctx.fillStyle=tc;
            ctx.fill();
        }
        for(var i=-k+1;i<k;i++){
            for(var j=0;j<2*k-1-Math.abs(i);j++){
                one(o[0]+(-k+1+Math.abs(i)/2+j)*w,o[1]+h*i);
            }
        }
    }
    else{
        console.log('你的浏览器不支持Canvas');
    }
}
</script>
</body>
</html>

效果如下:
在这里插入图片描述
第二次更新:其实本图形的绘制需求来自《蜂巢迷宫》游戏,下面的版本为的是能够直接在六边形网格上编辑文字。
首先在每个小六边形的相应位置添加输入框(用的绝对定位),改变背景色和边框使得不可见,当鼠标放上以及聚焦时改变背景色和边框,在改变大六边形边长时清空输入框并重新生成,在改变小六边形边长时修改输入框的位置,在改变颜色时无需改动输入框。
代码如下:


<!DOCTYPE HTML>
<html>
<head>
<title>六边形网格</title>
<link id="link" rel="shortcut icon" type="image/x-icon" href="">
<style>
#bc1,#bc2{width:25px;}
#bj,#xt,#tc{width:20px;}
input{
    font-size: 16px;
}
#note{
    font-size: 16px;
    font-family: 'Arial';
    height:90px;
}
input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {
    -webkit-appearance: none;
}
input[type="number"]{
    -moz-appearance: textfield;
}
</style>
</head>
<body>
<p>
设置大六边形边长:
<input id='bc1' type="number" value="3" onchange="document.getElementById('bc1s').value=this.value;change(this.id,this.value)"> 小六边形
<input id="bc1s" type="range" min="1" max="20" step="1" value="3" oninput="document.getElementById('bc1').value=this.value;" onchange="change('bc1',this.value);"/>
<span style="color: gray;">(仅改变此项时会清空文本框内容)</span>
<br>
设置小六边形边长:
<input id='bc2' type="number" value="24" onchange="document.getElementById('bc2s').value=this.value;change(this.id,this.value)"> 像素(px)
<input id="bc2s" type="range" min="1" max="50" step="1" value="24" oninput="document.getElementById('bc2').value=this.value;" onchange="change('bc2',this.value);"/>
<br>
设置背景色 <input type="color" id="bj" value="#c8ffff" onchange="change(this.id,this.value)"/>
设置线条色 <input type="color" id="xt" value="#0000ff" onchange="change(this.id,this.value)"/>
设置填充色 <input type="color" id="tc" value="#faebd7" onchange="change(this.id,this.value)"/></p>
<p id='p1'></p>
<canvas id="myCanvas" width="300" height="150">
<p>你的浏览器不支持Canvas</p>
</canvas>
<div id='texts'>div</div>
<br>
<textarea id='note' placeholder='点击输入笔记(拖动右下角可调整输入框大小)'></textarea>
<script type="text/javascript">
"use strict";
var canvas=document.getElementById('myCanvas');
if(canvas.getContext) {//如果浏览器支持Canvas
    var ctx=canvas.getContext('2d');
    var dic={};//输入参数的对象
    var para=['bc1','bc2','bj','xt','tc'];
    for(var i=0;i<para.length;i++){
        dic[para[i]]=document.getElementById(para[i]).value;
    }
    dic['bc1']=2;
    generate(0);
    link.href=myCanvas.toDataURL({format:'image/png', quality:1});//修改网页图标
    dic['bc1']=3;
    generate(2);
}
else{
    console.log('你的浏览器不支持Canvas');
}
function make_texts(i,j,xo,yo,w,h,c){
    //生成文本框
    //i,j为横纵序号,xo,yo为中心坐标,w,h为宽高
    var text =document.createElement('input');
    text.id='t_'+i+','+j;
    text.style['left']=xo-w/2+2+'px';
    text.style['top']=yo-h/2+1+'px';
    text.style['width']=w-6+'px';
    text.style['height']=h-6+'px';
    text.style['position']='absolute';
    text.style['text-align']='center';
    text.style['outline']='none';
    text.style['border']='0px';
    text.style['background-color']=hexToRgba(c,0);
    // text.value=text.id.slice(2);//填充文本框,测试用
    text.onmouseover=function(){
        text.style['background-color']=hexToRgba(c,0.9);
    };
    text.onmouseout=function(){
        text.style['background-color']=hexToRgba(c,0);
    }
    text.onfocus=function(){
        text.style['border']='1px solid red';
    }
    text.onblur=function(){
        text.style['border']='0px';
    }
    document.getElementById('texts').appendChild(text);
}
function move_texts(i,j,xo,yo,w,h){
    //移动文本框
    //i,j为横纵序号,xo,yo为中心坐标,w,h为宽高
    var text =document.getElementById('t_'+i+','+j);
    text.style['left']=xo-w/2+2+'px';
    text.style['top']=yo-h/2+1+'px';
    text.style['width']=w-6+'px';
    text.style['height']=h-6+'px';
}
function one(vs,xo,yo,xt,tc){
    ctx.beginPath();
    ctx.moveTo(xo+vs[5][0],yo+vs[5][1]);
    for(var i=0;i<vs.length;i++){
        ctx.lineTo(xo+vs[i][0],yo+vs[i][1]);
    }
    ctx.strokeStyle=xt;
    ctx.lineWidth=2;
    ctx.stroke();
    ctx.fillStyle=tc;
    ctx.fill();
}
function change(id,v){
    dic[id]=document.getElementById(id).value;
    if(dic['bc1']>100){
        var c=confirm('六边形个数过多时网页会卡,是否继续?');
        if(!c){return;}
    }
    if(id=='bc1'){
        generate(2);//大六边形边长修改时,清空文本框,重新生成
    }
    else if(id=='bc2'){
        generate(1);//小六边形边长修改时,移动文本框位置
    }
    else{
        generate(0);//颜色改变时,不改变文本框
    }
}
function generate(change_size){
    var k=Number(dic['bc1']);//大六边形边长,单位小六边形
    var d=Number(dic['bc2']);//小六边形边长,单位像素(px)
    var w=Math.sqrt(3)*d;//小六边形宽度
    var h=3/2*d;//小六边形高度
    var count=3*k*k-3*k+1;//小六边形个数
    canvas.width=2*k*w;
    canvas.height=2*k*h+h/2;
    document.getElementById('p1').innerHTML='画布宽'+canvas.width+'px,高'+canvas.height+'px,含有'+count+'个小六边形';
    var ctop=canvas.getBoundingClientRect().top;
    var cleft=canvas.getBoundingClientRect().left;
    var o=[canvas.width/2,canvas.height/2];
    ctx.fillStyle=dic['bj'];
    ctx.fillRect(0,0,canvas.width,canvas.height);
    ctx.beginPath();
    var vs=[[0,d],[-w/2,d/2],[-w/2,-d/2],[0,-d],[w/2,-d/2],[w/2,d/2]];
    if(change_size==2){
        //移除所有文本框
        document.getElementById('texts').innerHTML='';
    }
    for(var i=-k+1;i<k;i++){
        for(var j=0;j<2*k-1-Math.abs(i);j++){
            var xo=o[0]+(-k+1+Math.abs(i)/2+j)*w;
            var yo=o[1]+h*i
            one(vs,xo,yo,dic['xt'],dic['tc']);
            if(change_size==2) make_texts(i,j,cleft+xo,ctop+yo,w,d,dic['bj']);
            else if(change_size==1) move_texts(i,j,cleft+xo,ctop+yo,w,d);
        }
    }
    document.getElementById('note').style['width']=canvas.width+'px';
    document.getElementById('note').style['border']='1px solid'+dic['xt'];
}
function hexToRgba(hex, opacity) {
    return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
    + parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')';
    //JS - 将十六进制的颜色值转成rgb、rgba格式 https://www.hangge.com/blog/cache/detail_2291.html
}
</script>
</body>
</html>

效果如下:
在这里插入图片描述
在线预览网址: https://fun.rth1.me/text6.html

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值