【HTML】Canvas 2D图像

参考链接

HTML 画布 | 菜鸟教程

特点

Canvas 是通过 JavaScript 来绘制 2D 图形,是 HTML 5 中新增的元素。

绘制的是位图,图像放大后会失真。能够以 .png 或 .jpg 格式保存图像,比较适合游戏应用。不支持事件处理器

<canvas>

图形的容器(矩形),必须使用js定义图表或其他图像。

必须设置height和width属性,不能用style设置宽高,无效操作。返回的还是默认高宽 150* 300。

<canvas id="cvs" height="150" width="300"></canvas>

getContext()

getContext() 返回一个对象,提供绘图方法属性

getContext("2d") 取得2d上下文对象。

var cvs = document.getElementById('cvs');
var ctx = cvs.getContext('2d');

样式

描边 strokeStyle、填充 fillStyle

同时具有的属性为纯色color、渐变、重复

纯色

ctx.fillStyle="#FF0000";
ctx.fillRect(20,20,150,100); //x的坐标,y的坐标,矩形宽度,矩形高度

渐变

线性渐变 createLinearGradient

var grd=ctx.createLinearGradient(170,0,0,0);
grd.addColorStop(0,"black");
grd.addColorStop(1,"white");
ctx.fillStyle=grd;
ctx.fillRect(20,20,150,100);

径向渐变 createRadialGradient

var grd=ctx.createRadialGradient(100,50,5,90,60,100);
grd.addColorStop(0,"red");
grd.addColorStop(1,"white");
ctx.fillStyle=grd;
ctx.fillRect(20,20,150,100);

重复 createPattern()

指定的方向内重复指定的元素。

var img=document.getElementById("img")
var pat=ctx.createPattern(img,"repeat"); // repeat、repeat-x、repeat-y、no-repeat
ctx.rect(0,0,220,128);
ctx.fillStyle=pat;
ctx.fill();

矩形

创建 rect

ctx.rect(20,20,150,100);
ctx.stroke();

 

ctx.rect(20,20,50,50);
ctx.fill();

描边 strokeRect

ctx.strokeStyle="#FF0000";
ctx.strokeRect(20,20,150,100);

填充 fillRect

默认是黑色

ctx.fillStyle="#FF0000";
ctx.fillRect(20,20,150,100); //x的坐标,y的坐标,矩形宽度,矩形高度

清空 clearRect

给定的矩形内清除指定的像素。

ctx.fillStyle="red";
ctx.fillRect(0,0,300,150);
ctx.clearRect(20,20,100,50);

线条

线条结束点

ctx.beginPath();
ctx.lineWidth=10;
ctx.lineCap="butt";
ctx.moveTo(20,20);
ctx.lineTo(200,20);
ctx.stroke();
	
ctx.beginPath();
ctx.lineCap="round";
ctx.moveTo(20,40);
ctx.lineTo(200,40);
ctx.stroke();
	
ctx.beginPath();
ctx.lineCap="square";
ctx.moveTo(20,60);
ctx.lineTo(200,60);
ctx.stroke();

相交拐点 

ctx.beginPath();
ctx.lineWidth=10;
ctx.lineJoin="round";
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(20,100);
ctx.stroke();
	
ctx.beginPath();
ctx.lineWidth=10;
ctx.lineJoin="bevel";
ctx.moveTo(80,20);
ctx.lineTo(160,50);
ctx.lineTo(80,100);
ctx.stroke();
	
ctx.beginPath();
ctx.lineWidth=10;
ctx.lineJoin="miter";
ctx.moveTo(140,20);
ctx.lineTo(200,50);
ctx.lineTo(140,100);
ctx.stroke();

斜接角度

 

ctx.lineWidth=10;
ctx.lineJoin="miter";
ctx.miterLimit=5;
ctx.moveTo(20,20);
ctx.lineTo(50,27);
ctx.lineTo(20,34);
ctx.stroke();

路径

线条

ctx.beginPath();  // 开始          
ctx.lineWidth="5"; // 宽度
ctx.strokeStyle="green";  
ctx.moveTo(30,25); //开始点
ctx.lineTo(150,35); // 到这个点绘制线条
ctx.lineTo(150,75);
ctx.closePath(); // 从当前点回到起始点
ctx.stroke();  // 画 

二次贝塞尔曲线

ctx.beginPath();
ctx.moveTo(20,20);
ctx.quadraticCurveTo(20,100,200,20);
ctx.stroke();

三次贝塞尔曲线

ctx.beginPath();
ctx.moveTo(20,20);
ctx.bezierCurveTo(20,100,200,100,200,20);
ctx.stroke();

剪裁 clip

从原始画布剪切任意形状和尺寸的区域。


ctx.rect(50,20,200,120);
ctx.stroke();

ctx.fillStyle="red";
ctx.fillRect(0,0,150,100);
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();

ctx.fillStyle="red";
ctx.fillRect(0,0,150,100);

 圆或者部分圆

//x坐标,y坐标,半径,开始位置,整圆:2*Math.PI,true逆时针,false是顺时针
ctx.beginPath();
ctx.arc(100,75,50,0,2*Math.PI); 
ctx.stroke();

两线之间的弧度

  

ctx.beginPath();     
ctx.moveTo(20,20);            
ctx.lineTo(100,20);           
ctx.arcTo(150,20,150,70,50);  
ctx.lineTo(150,120);           
ctx.stroke();      

测试某个点是否在路径中

ctx.rect(20,20,150,100);
ctx.stroke();
if (ctx.isPointInPath(20,80)) {
	console.log("在区域内")
}else {
	console.log("不在区域内")
}

转换

scale 放大

ctx.strokeRect(5,5,25,15);
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);

rorate 旋转

 

ctx.rotate(20*Math.PI/180);
ctx.fillRect(50,20,100,50);

translate 平移

ctx.fillRect(10,10,100,50);
ctx.translate(70,70);
ctx.fillRect(10,10,100,50);

transform

ctx.fillStyle="yellow";
ctx.fillRect(0,0,250,100)
	
ctx.transform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="red";
ctx.fillRect(0,0,250,100);
	
ctx.transform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="blue";
ctx.fillRect(0,0,250,100);

setTransform

不以上一个为基础的变化。所以蓝色会覆盖掉上一个红色的。

ctx.fillStyle="yellow";
ctx.fillRect(0,0,250,100)

ctx.setTransform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="red";
ctx.fillRect(0,0,250,100);

ctx.setTransform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="blue";
ctx.fillRect(0,0,250,100);

阴影 shadow

ctx.shadowBlur=20;
ctx.shadowColor="black";
ctx.fillStyle="red";
ctx.fillRect(10,10,50,50);


	
ctx.shadowBlur=20;
ctx.shadowOffsetX=20;
ctx.shadowColor="black";
ctx.fillStyle="red";
ctx.fillRect(70,10,50,50);


ctx.shadowBlur=20;
ctx.shadowOffsetY=20;
ctx.shadowColor="black";
ctx.fillStyle="red";
ctx.fillRect(150,10,50,50);

透明度

ctx.fillStyle="red";
ctx.fillRect(20,20,75,50);

ctx.globalAlpha=0.2;
ctx.fillStyle="blue"; 
ctx.fillRect(150,20,75,50); 

合成

红色矩形是目标图像,蓝色矩形是源图像

ctx.fillStyle="red";
ctx.fillRect(20,20,75,50);
ctx.fillStyle="blue";	
ctx.globalCompositeOperation="source-over";
ctx.fillRect(50,50,75,50);	
	
	
ctx.fillStyle="red";
ctx.fillRect(150,20,75,50);
ctx.fillStyle="blue";	
ctx.globalCompositeOperation="destination-over";
ctx.fillRect(180,50,75,50);	

文本

文字

ctx.font="italic small-caps bold 32px aria";
ctx.fillText("Hello World",10,50);

水平对齐

ctx.strokeStyle="red";
ctx.moveTo(150,20);
ctx.lineTo(150,170);
ctx.stroke();

ctx.font="15px Arial";


ctx.textAlign="start";
ctx.fillText("textAlign=start",150,60);

ctx.textAlign="end";
ctx.fillText("textAlign=end",150,80);

ctx.textAlign="left";
ctx.fillText("textAlign=left",150,100);

ctx.textAlign="center";
ctx.fillText("textAlign=center",150,120);

ctx.textAlign="right";
ctx.fillText("textAlign=right",150,140);

垂直对齐 

//在Y = 100画一条红线
ctx.strokeStyle="red";
ctx.moveTo(5,100);
ctx.lineTo(395,100);
ctx.stroke();
	
ctx.font="20px Arial"
	
ctx.textBaseline="top"; 
ctx.fillText("Top",5,100); 
	
ctx.textBaseline="bottom"; 
ctx.fillText("Bottom",50,100); 
	
ctx.textBaseline="middle"; 
ctx.fillText("Middle",120,100); 
	
ctx.textBaseline="alphabetic"; 
ctx.fillText("Alphabetic",190,100); 
	
ctx.textBaseline="hanging"; 
ctx.fillText("Hanging",290,100); 

实心字

ctx.font="30px Arial";
ctx.textAlign ="center";
ctx.textBaseline = "bottom";

ctx.fillText("fillText",80,50);

空心字

// 渐变
var grd = ctx.createLinearGradient(0,0,300,0);
grd.addColorStop("0","magenta");
grd.addColorStop("0.5","blue");
grd.addColorStop("1.0","red");
	
// 文字
ctx.font="30px Verdana";
ctx.strokeStyle=grd;
ctx.strokeText("Big smile!",10,50);

文本宽度

let wd = ctx.measureText("Hello World").width
ctx.font="30px Arial";
ctx.fillText(wd,10,50);

图像

var img=document.getElementById("scream");
img.onload = function() {
	ctx.drawImage(img,0,0);
}

img.onload = function() {
    ctx.drawImage(img,20,10,150,180);
}

 

var img=document.getElementById("scream");
img.onload = function(){
    // 图片,x坐标,y坐标,被剪切的宽度,被剪切的高度,放置图像的x坐标,放置图像的y坐标,宽度,高度
    ctx.drawImage(img,90,130,50,60,10,10,50,60)
}

图像数据 imageData

  

var imgData=ctx.createImageData(100,50);
console.log("imgdata的宽度是: " + imgData.width);
console.log("imgdata的高度是: " + imgData.height);
console.log("imgdata的长度: " + imgData.data.length);	

for (var i=0;i<imgData.data.length;i+=4)
{
	// rgba 
	imgData.data[i+0]=255; // r
	imgData.data[i+1]=0; // g
	imgData.data[i+2]=0; // b
	imgData.data[i+3]=155; // a
}
ctx.putImageData(imgData,10,10);
console.log("imgdata: " + JSON.stringify(imgData));

// 获取数据复制一份
var imgData2=ctx.getImageData(10,10,50,50);
ctx.putImageData(imgData2,10,70);

Canvas 高清屏模糊问题

原文链接:canvas生成图片模糊的解决方案 - 简书canvas生成图片模糊的解决方案 - 简书

在高清屏的设备下,出现模糊的问题可以通过 hidpi-canvas-polyfill  解决。

  • 首先去 GitHub 下载 hidpi-canvas.js 文件:传送门
  • 在项目中引入 hidpi-canvas.js 文件;
  • 调用 getPixelRatio( ) 函数,得到 ratio 值;
  • 在 drawImage( ) 中,将 width 和 height 乘以 ratio;

在部分 iOS 设备中,可能会存在 image.onload 失效的问题,会导致无法将图片画到 canvas 中。引起该现象的原因可能是:
1、iOS中存在 image.onload 失效的问题(注意:image.onload 执行的前提是图片正常加载完成,如果稍微出错,就会执行 image.onerror 而不是 image.onload);
2、如果 image.src 是 base64 格式文件,不要设置 image.crossOrigin = "anonymous",可能会出现 image.onload 无法执行的问题,从而无法正常画图。

关于 onload 失效的问题,看 Stack Overflow 这个解答,可能收获挺多的:IPhone img onload fails

// html
<div onclick="makeCanvasToPhoto()" style="width: 100px; padding: 10px 30px;background: #eee;text-align: center">生成图片</div>
<canvas id="canvasBox" style="margin: 50px auto"></canvas>
<!-- 引入js -->
<script type="text/javascript" src="canvas.js"></script>
<script type="text/javascript" src="hidpi-canvas.min.js"></script>

// canvas.js 文件
function makeCanvasToPhoto() {
    var that = this;
    var canvas = document.getElementById("canvasBox");
    var context = canvas.getContext('2d');
    var ratio = getPixelRatio(context);  // 关键代码
    canvas.width = 300 * ratio; // 画布宽度
    canvas.height = 300 * ratio; // 画布高度
    var divWidth = 300 * ratio; // 用于内容居中
    var divHeight = 300 * ratio; // 用于内容居中
    
    // 画矩形
    context.beginPath();
    context.fillStyle = "#abcdef";
    context.fillRect(0, 0, divWidth, divHeight);
    context.closePath();

    // 图片
    context.beginPath();
    var imgObj = new Image();
    imgObj.crossOrigin = "anonymous";  // 在iOS 9设备中,如果src是base64格式,设置了crossOrigin 属性,会导致无法执行image.onload 而执行image.onerror 函数
    imgObj.src = 'http://img0.imgtn.bdimg.com/it/u=458129248,1588126214&fm=26&gp=0.jpg';
    imgObj.onload = function () {
        var imgWidth = '150';
        var imgHeight = '150';
        context.drawImage(this, 50, 50, imgWidth * ratio, imgHeight * ratio)
    };
    context.closePath();

    // 文本
    context.beginPath();
    context.font = '32px bold';
    context.fillStyle = '#1a1a1a';
    context.textAlign = 'center';
    context.textBaseline = 'middle';
    context.fillText('文本', 50, 240);
    context.closePath();

    context.drawImage(canvas, 0, 0, divWidth, divHeight);
    var base64Obj = canvas.toDataURL('image/png', 1);
    console.log(base64Obj);
}

function getPixelRatio(context) {
    var backingStore = context.backingStorePixelRatio ||
        context.webkitBackingStorePixelRatio ||
        context.mozBackingStorePixelRatio ||
        context.msBackingStorePixelRatio ||
        context.oBackingStorePixelRatio ||
        context.backingStorePixelRatio || 1;
    return (window.devicePixelRatio || 1) / backingStore;
};

Canvas 图片裁剪成圆形

<p>裁剪之前</p>
<img :src="options.img" />
<p>裁剪之后</p>
<img :src="options.canvasImg">
this.options.img = store.getters.avatar;
console.log('img',this.options.img)

this.imageToCircle(this.options.img).then((res) => {
    this.options.canvasImg = res
    console.log('canvasImg',this.options.canvasImg)
})
imageToCircle(picUrl) {
  // 通过图片地址换出圆形的图片
  let radius, diameter, canvas, ctx;
  let img = new Image();
  img.setAttribute("crossOrigin", "anonymous"); // 解决图片跨域访问失败
  img.src = picUrl;
  return new Promise((reslove) => {
    img.addEventListener(
      "load",
      () => {
        let { width, height } = img;
        if (img.width > img.height) {
          radius = height / 2;
        } else {
          radius = width / 2;
        }
        diameter = radius * 2;

        canvas = document.createElement("canvas");
        if (!canvas.getContext) {
          // 判断浏览器是否支持canvas,如果不支持在此处做相应的提示
          console.log("您的浏览器版本过低,暂不支持。");
          return false;
        }
        canvas.width = diameter;
        canvas.height = diameter;

        ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, diameter, diameter);

        // 描边
        ctx.save(); //save和restore可以保证样式属性只运用于该段canvas元素
        ctx.strokeStyle = "#eee"; //设置边线的颜色
        ctx.lineWidth = 2;
        ctx.beginPath(); //开始路径
        ctx.arc(radius, radius, radius - 5, 0, Math.PI * 2); //画一个整圆.
        ctx.stroke(); //绘制边线

        // 截圆形图
        ctx.save();
        ctx.beginPath();
        ctx.arc(radius, radius, radius - 5, 0, Math.PI * 2);
        ctx.clip();

        let x = 0,
          y = 0,
          swidth = diameter,
          sheight = diameter;

        ctx.drawImage(img, x, y, swidth, sheight, 0, 0, diameter, diameter);
        ctx.restore();
        // toDataURL()是canvas对象的一种方法,用于将canvas对象转换为base64位编码
        let dataURL = canvas.toDataURL("image/png");
        reslove(dataURL);
      },
      false
    );
  });
}

猜你喜欢

转载自blog.csdn.net/wuli_youhouli/article/details/128325369
今日推荐