原文地址html
最近在學習canvas,而後照葫蘆畫瓢簡單實現了幾個小demo,跟你們一塊學習一下。前端
用法:vue
context.drawImage(img[, sx, sy, swidth, sheight], x, y[, width, height]);
複製代碼
參數 | 描述 |
---|---|
img | 能夠是圖片、視頻、畫布 |
sx | 可選。開始剪切的 x 座標位置。 |
sy | 可選。開始剪切的 y 座標位置。 |
swidth | 可選。被剪切圖像的寬度。 |
sheight | 可選。被剪切圖像的高度。 |
x | 在畫布上放置圖像的 x 座標位置。 |
y | 在畫布上放置圖像的 y 座標位置。 |
width | 可選。要使用的圖像的寬度。(伸展或縮小圖像) |
height | 可選。要使用的圖像的高度。(伸展或縮小圖像) |
用法:git
context.getImageData(x, y, width, height);
複製代碼
參數 | 描述 |
---|---|
x | 開始複製的左上角位置的 x 座標。 |
y | 開始複製的左上角位置的 y 座標。 |
width | 將要複製的矩形區域的寬度。 |
height | 將要複製的矩形區域的高度。 |
方法返回 ImageData 對象,該對象拷貝了畫布指定矩形的像素數據。 是Uint8ClampedArray類型的一維數組,包含着RGBA格式的整型數據。 對於 ImageData 對象中的每一個像素,都存在着四方面的信息,即RGBA值:github
color/alpha 以數組形式存在,並存儲於 ImageData 對象的 data 屬性中。canvas
這個樣子: 跨域
先來一下demo,經過getImageData方法獲取鼠標指針處的像素值。數組
部分代碼:服務器
methods: {
import imgUrl from './component/sample.jpg';
export default {
data () {
return {
canvas: null,
ctx: null,
color: null
}
},
methods: {
pick (e, ctx) {
let x = e.layerX,
y = e.layerY,
pixel = ctx.getImageData(x, y, 1, 1),
data = pixel.data,
rgba = 'rgba(' + data[0] + ',' + data[1] + ',' + data[2] + ',' + ((data[3] / 255).toFixed(2)) + ')';
this.color.style.background = rgba;
this.color.textContent = rgba;
}
},
mounted () {
this.canvas = this.$refs['canvas'];
this.ctx = this.canvas.getContext('2d');
this.color = this.$refs['color'];
let img = new Image();
img.src = imgUrl;
img.onload = () => {
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
};
this.canvas.onmousemove = () => {
this.pick(event, this.ctx);
}
}
}
複製代碼
還能夠取本地或者遠程跨域的圖片,像這樣ide
但這裏有兩個問題:一個是本地圖片預覽,一個是跨域圖片報錯。
第一個問題以前有寫過一篇文章,能夠看這裏,這裏不贅述了。
注意 第二個問題源於canvas沒法對沒有權限的跨域圖片進行操做,如出現跨域,對圖片的操做(如getImageData、canvas.toDataURL)會報錯:Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 即canvas已經被跨域的數據污染了。
要解決這個問題,就須要圖片所在的服務器容許跨域訪問(設置消息頭Access-Control-Allow-Origin="*"或者你的網站域名),且本地也須要開啓跨域權限(img.crossOrigin = "anonymous")。
因爲通常的服務器都是容許跨域的,因此前端只要設置img.crossOrigin = "anonymous"就能夠了。
固然,若是服務器設置了圖片防盜鏈的話,咱們本地開啓了跨域權限也是沒有用的。
部分代碼:
data () {
return {
canvas: null,
ctx: null,
color: null,
exterbalUrl: 'http://p8rbt50i2.bkt.clouddn.com/blog/else/miaoWechatIMG241526366731_.pic.jpg'
}
},
methods: {
pick (e, ctx) {
let x = e.layerX,
y = e.layerY,
pixel = ctx.getImageData(x, y, 1, 1),
data = pixel.data,
rgba = 'rgba(' + data[0] + ',' + data[1] + ',' + data[2] + ',' + (data[3] / 255).toFixed(2) + ')';
this.color.style.background = rgba;
this.color.textContent = rgba;
},
onFileChange (e) {
let file = e.target.files[0],
blob = new Blob([file]), // 文件轉化成二進制文件
url = URL.createObjectURL(blob); //轉化成url
let img = new Image();
img.src = url;
img.onload = () => {
this.draw(img);
URL.revokeObjectURL(url);
};
},
draw (img) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
},
onConfirmUrl () {
let img = new Image();
//解決跨域問題
img.crossOrigin = 'anonymous';
img.src = this.exterbalUrl;
img.onload = () => {
this.draw(img);
};
}
},
mounted () {
this.canvas = this.$refs['canvas'];
this.ctx = this.canvas.getContext('2d');
this.color = this.$refs['color'];
this.onConfirmUrl();
this.canvas.onmousemove = () => {
this.pick(event, this.ctx);
}
}
複製代碼
下面是一個放大鏡效果,相似PC端淘寶頁面產品預覽的效果。這樣:
這個效果的實現至關簡單,只是直接利用了drawImage的「截取」功能,把左側截取的50 * 50的畫布放大後,從新畫在了新的畫布上。
部分代碼:
const SAMPLE_WIDTH = 50,
CANVAS_WIDHT = 300;
export default {
data () {
return {
exterbalUrl: 'http://p8rbt50i2.bkt.clouddn.com/blog/else/miaoWechatIMG241526366731_.pic.jpg'
}
},
methods: {
pick (e, ctx) {
let x = e.layerX,
y = e.layerY;
if(x < SAMPLE_WIDTH / 2) {
x = SAMPLE_WIDTH / 2;
}
if(x > CANVAS_WIDHT - SAMPLE_WIDTH / 2) {
x = CANVAS_WIDHT - SAMPLE_WIDTH / 2;
}
if(y < SAMPLE_WIDTH / 2) {
y = SAMPLE_WIDTH / 2;
}
if(y > CANVAS_WIDHT - SAMPLE_WIDTH / 2) {
y = CANVAS_WIDHT - SAMPLE_WIDTH / 2;
}
let x1 = x - SAMPLE_WIDTH / 2,
y1 = y - SAMPLE_WIDTH / 2;
this.drawCanvas(this.img);
this.showMagnifier(x1, y1);
this.drawSampleFrame(x1, y1);
},
drawSampleFrame (x1, y1) {
this.ctx.fillRect(x1, y1, 50, 50);
this.ctx.strokeRect(x1, y1, 50, 50);
},
onFileChange (e) {
let file = e.target.files[0],
blob = new Blob([file]), // 文件轉化成二進制文件
url = URL.createObjectURL(blob); //轉化成url
let img = new Image();
img.src = url;
img.onload = () => {
this.img = img;
this.drawCanvas(img);
URL.revokeObjectURL(url);
};
},
drawCanvas (img) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(img, 0, 0, this.canvas.width, this.canvas.height);
},
onConfirmUrl () {
let img = new Image();
//解決跨域問題
img.crossOrigin = 'anonymous';
img.src = this.exterbalUrl;
img.onload = () => {
this.img = img;
this.drawCanvas(img);
};
},
showMagnifier (x, y) {
//重點所在
this.magnifierCtx.drawImage(this.canvas, x, y, SAMPLE_WIDTH, SAMPLE_WIDTH, 0, 0, this.magnifier.width, this.magnifier.height);
}
},
mounted () {
this.canvas = this.$refs['canvas'];
this.magnifier = this.$refs['magnifier'];
this.ctx = this.canvas.getContext('2d');
this.magnifierCtx = this.magnifier.getContext('2d');
this.ctx.fillStyle = 'rgba(30, 144, 255, .5)';
this.ctx.strokeStyle = '#000';
this.onConfirmUrl();
this.canvas.onmousemove = () => {
this.pick(event, this.ctx);
}
this.canvas.onmouseout = () => {
this.magnifierCtx.clearRect(0, 0, this.magnifier.width, this.magnifier.height);
this.drawCanvas(this.img);
}
}
}
複製代碼