寫在最前:
前兩天老大跟我說老虎官網上那個自定義頭像的功能是flash實現的,沒有安裝過的還得手動去“允許”falsh的執行。所以讓我用canvas實現一個一樣的功能,嘿嘿,剛好最近也在研究canvas,所以欣然答應(其實,你沒研究過難道就不答應麼,哈哈哈哈哈~)
對了,大佬們記得給我的部落格點贊,要星星哦~
成果展示:
Git地址:
功能說明:
- 拖拽左側小方框,或者是滑鼠放在小方框右下角,點選拉伸方框,方框覆蓋部分的圖片被自動擷取下來,然後再在右側的多個容器裡面重繪。
- 輸入寬高,自定義你需要訂製的頭像大小,目前只支援寬高相同的頭像圖片。
實現細節:
因為你要對圖片所在的區域進行截圖,所以你得製作一張canvas,蓋在圖片所在的區域。這裡,我們給出了一個函式,根據傳入的DOM裡面元素的類名建立相同位置的canvas,蓋在原來的DOM元素上面:
function createCanvasByClassName(tag) {
var canvasInitialWidth = $('.' + tag).width();
var canvasInitialHeight = $('.' + tag).height();
var left = $('.' + tag).offset().left - $('.' + tag).parent('.portraitContainer').offset().left + 1;
var top = $('.' + tag).offset().top - $('.' + tag).parent('.portraitContainer').offset().top + 1;
//var left = $('.' + tag).offset().left + 1;
//var top = $('.' + tag).offset().top + 1;
clearCanvasObj.left = $('.' + tag).offset().left + 1;
clearCanvasObj.top = $('.' + tag).offset().top + 1;
// clearCanvasObj.left = left;
// clearCanvasObj.top = top;
var canvasElement = $('<canvas></canvas>');
var randomNum = Math.floor(getRandom(0, 10000));
clearCanvasObj.canvasId = randomNum;
canvasElement.attr({
id: 'canvas',
width: canvasInitialWidth,
height: canvasInitialHeight
});
canvasElement.css({
position: 'absolute',
top: top,
left: left
});
//$('body').append(canvasElement);
var appendEle = $('.portraitContainer').append(canvasElement);
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//ctx.fillStyle = "rgba(211,211,216,0.5)";
ctx.clearRect(0, 0, canvasInitialWidth, canvasInitialHeight);
ctx.fillStyle = "rgba(0,0,0, 0.4)";
ctx.fillRect(0, 0, canvasInitialWidth, canvasInitialHeight);
return canvas;
}複製程式碼
有了這張canvas你就可以在你圖片所在區域肆意的操作了。首先,降整個區域畫上一個淺黑色的陰影,然後再擦除初始小方框區域裡面的顏色。然後給整個頁面新增mousedown,mousemove,mouseup事件,他們所做的功能就跟你在頁面中實現一個拖拽的功能類似,這裡重點說下mousemove裡面做的操作,程式碼如下:
function mousemoveFunc(event) {
/* Act on the event */
var nowMouseX = event.clientX - clearCanvasObj.left;
var nowMouseY = event.clientY - clearCanvasObj.top;
if (nowMouseX >= clearCanvasObj.xStart && nowMouseX <= clearCanvasObj.xStart + clearCanvasObj.width && nowMouseY >= clearCanvasObj.yStart && nowMouseY <= clearCanvasObj.yStart + clearCanvasObj.height) {
clearCanvasObj.isCanvasArea = true;
//clearCanvasObj.isRightCorner = false;
imgContainerCanvas.style.cursor = 'move';
} else if ((nowMouseX >= clearCanvasObj.xStart + clearCanvasObj.width - 10) && (nowMouseX <= clearCanvasObj.xStart+ clearCanvasObj.width + 10)
&& (nowMouseY >= clearCanvasObj.yStart + clearCanvasObj.height - 10) && (nowMouseY <= clearCanvasObj.yStart + clearCanvasObj.height + 10)) {
clearCanvasObj.isCanvasArea = true;
//clearCanvasObj.beginDraw = false;
imgContainerCanvas.style.cursor = 'se-resize';
}
else {
clearCanvasObj.isCanvasArea = false;
//clearCanvasObj.isRightCorner = false;
imgContainerCanvas.style.cursor = 'default';
}
var outerDomWidth = $(".imgContainer").width();
var outerDomHeight = $(".imgContainer").height();
var xDistance = event.clientX - clearCanvasObj.mouseX;
var yDistance = event.clientY - clearCanvasObj.mouseY;
//var outerCTX = canvas.getContext('2d');
//移動小方框
if (clearCanvasObj.beginDraw && clearCanvasObj.isCanvasArea && !clearCanvasObj.isRightCorner) {
ry_CTX.fillStyle = clearCanvasObj.color;
// console.log('1', clearCanvasObj.xStart, clearCanvasObj.yStart)
ry_CTX.fillRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
//outerCTX.fillRect(0, 0, canvas.width, canvas.height);
clearCanvasObj.xStart += xDistance;
clearCanvasObj.yStart += yDistance;
//判斷方框是否達到邊界
if (clearCanvasObj.xStart <= 0) {
clearCanvasObj.xStart = 0;
}
if (clearCanvasObj.yStart <= 0) {
clearCanvasObj.yStart = 0;
}
if ((clearCanvasObj.xStart + clearCanvasObj.width) >= outerDomWidth) {
clearCanvasObj.xStart = outerDomWidth - clearCanvasObj.width;
}
if ((clearCanvasObj.yStart + clearCanvasObj.height) >= outerDomHeight) {
clearCanvasObj.yStart = outerDomHeight - clearCanvasObj.height;
}
// console.log('2', clearCanvasObj.xStart, clearCanvasObj.yStart)
ry_CTX.clearRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
produceSmallPic(clearCanvasObj.xStart+clearCanvasObj.left, clearCanvasObj.yStart+clearCanvasObj.top, clearCanvasObj.width, clearCanvasObj.height, imageURL)
clearCanvasObj.mouseX = event.clientX;
clearCanvasObj.mouseY = event.clientY;
}
//拖拽小方框
if (clearCanvasObj.isRightCorner) {
ry_CTX.fillStyle = clearCanvasObj.color;
ry_CTX.fillRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
var realDistance = Math.min(xDistance, yDistance)
clearCanvasObj.width += realDistance;
clearCanvasObj.height += realDistance;
//拖動時邊界條件的判斷
if (clearCanvasObj.xStart + clearCanvasObj.width >= outerDomWidth) {
clearCanvasObj.width = outerDomWidth - clearCanvasObj.xStart;
clearCanvasObj.height = outerDomWidth - clearCanvasObj.xStart;
}
if (clearCanvasObj.yStart + clearCanvasObj.height >= outerDomHeight) {
clearCanvasObj.width = outerDomHeight - clearCanvasObj.yStart;
clearCanvasObj.height = outerDomHeight - clearCanvasObj.yStart;
}
if (clearCanvasObj.width <= 10) {
clearCanvasObj.width = 10;
}
if (clearCanvasObj.height <= 10) {
clearCanvasObj.height = 10;
}
ry_CTX.clearRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
produceSmallPic(clearCanvasObj.xStart+clearCanvasObj.left, clearCanvasObj.yStart+clearCanvasObj.top, clearCanvasObj.width, clearCanvasObj.height, imageURL);
clearCanvasObj.mouseX = event.clientX;
clearCanvasObj.mouseY = event.clientY;
}
}複製程式碼
函式裡面,你需要注意拖拽的邊界條件,一個是方框不能拖到圖片所在DOM外的邊界;另外一個就是當你滑鼠放在小方框所在的區域改變滑鼠的樣式。方框在拖動的過程中,我們不斷重繪方框移動的區域(也就是不斷的畫上陰影),然後在新的位置呼叫clearRect函式,重新擦出一個小方框出來。在拖拽或是拉伸的過程中,我們會不斷呼叫produceSmallPic函式,在右邊的容器(每個容器都是一個canvas)裡面不斷根據容器大小重繪出所需的頭像。程式碼如下:
function produceSmallPic(imageURL,left, top, width, height) {
var img = new Image();
img.src = imageURL;
var targetCtx = new Array();
var targetCanvas = null;
img.onload = function() {
portraitGroupsArr.forEach(function(item, index) {
targetCanvas = document.getElementById(item.class);
targetCtx.push(targetCanvas.getContext('2d'));
targetCtx[index].clearRect(0,0, item.width, item.height);
targetCtx[index].drawImage(img, left - clearCanvasObj.left, top - clearCanvasObj.top, width, height, 0, 0 , item.width, item.height);
})
}
}複製程式碼
我們說下這個函式的作用,這裡我們要注意一個引數imageURL,這個URL是由圖片所在的DOM轉化來的。因為你要把DOM所在的區域變成一張圖片,這樣你才能在利用drawImage函式擷取你所需要的區域。所以我們先利用html2canvas庫函式講圖片所在的DOM轉化為canvas,這張canvas的內容是包含你所要擷取的圖片的,然後把這張canvas轉化為圖片取得圖片地址imageURL,程式碼如下:
html2canvas(document.getElementById('imgContainer'), {
onrendered: function(canvas) {
var imageURL = canvasTransToImage(canavs);
...
}
})
function canvasTransToImage(canvas) {
var imageURL = canvas.toDataURL('image/png');
return imageURL;
}複製程式碼
接著,你就可以便利右側的canvas容器,講圖片重回到裡面了,整個過程就這樣結束,回頭看來是不是很簡單。
相關依賴:
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>複製程式碼
寫在最後:
canvas的操作,要多多注意那些邊界條件,什麼時候該重繪什麼時候該清除,這些是比較重要的。邏輯清晰了,canvas本身的API也就那麼幾個,操作起來也就沒那麼麻煩了,最後,謝謝大家查閱,寫的不是很清楚,有不懂的可以一起討論~