HTML5自助切圖

1 評論 16670 瀏覽 2 收藏 14 分鐘

享受生活,熱愛重構,大家好,我是Json。

在現(xiàn)在這個到處是HTML5話題的時代,好像不懂點HTML5都有點落伍。那我也跟上潮流一把吧,今天給大家分享的是基于HTML5的自助切圖。

在組里經(jīng)常會被某設計師叫切板仔,確實重構很大一部分工作都花在切圖上,而如何提高切圖效率或者讓切圖自助化也是我們重構師的追求?;谶@個前提我自己抱著研究的心態(tài),使用HTML5大致實現(xiàn)了一下。一開始覺得HTML5是個很神秘很高深的東西,其實當你去了解他,你會發(fā)現(xiàn)他是很空虛,且很容易上…………….手的。

這里使用到的HTML5技術包括:

  1. 本地預覽(FileReader)
  2. 拖拽(drag?&?drop)
  3. 切圖(canvas)

拖拽:

拖拽基本事件如下:

DataTransfer 對象 退拽對象用來傳遞的媒介,使用一般為Event.dataTransfer。
draggable 屬性 就是標簽元素要設置draggable=true,否則不會有效果,例如: <div title=”拖拽我” draggable=”true”&rt;列表1</div:rt;</td&rt;
ondragstart 事件 當拖拽元素開始被拖拽的時候觸發(fā)的事件,此事件作用在被拖曳元素上
ondragenter 事件 當拖曳元素進入目標元素的時候觸發(fā)的事件,此事件作用在目標元素上
ondragover 事件 拖拽元素在目標元素上移動的時候觸發(fā)的事件,此事件作用在目標元素上
ondrop 事件 被拖拽的元素在目標元素上同時鼠標放開觸發(fā)的事件,此事件作用在目標元素上
ondragend 事件 當拖拽完成后觸發(fā)的事件,此事件作用在被拖曳元素上
drageleave事件 當拖拽離開此處時觸發(fā),只在離開這個對象時觸發(fā)一次,此事件作用在目標元素上
Event.preventDefault() 方法 阻止默認的些事件方法等執(zhí)行。在ondragover中一定要執(zhí)行preventDefault(),否則ondrop事件不會被觸發(fā)。另外,如果是從其他應用軟件或是文件中拖東西進來,尤其是圖片的時候,默認的動作是顯示這個圖片或是相關信息,并不是真的執(zhí)行drop。此時需要用用document的ondragover事件把它直接干掉。
Event.effectAllowed 屬性 就是拖拽的效果。

 

圖1是頁面上所使用到拖拽的地方。左圖為拖拽上傳圖片,右圖為拖拽參考線。

a122

介紹完拖拽基本事件后,再來看下頁面是如何通過拖拽將本地圖片通過拖拽的方式拖到頁面指定區(qū)域使用圖片上傳,這也是拖拽現(xiàn)在比較常用到的功能。

給document增加拖拽事件,當拖拽元素進入頁面時改變目標元素樣式提示用戶目標元素位置,當拖拽元素離開頁面后還原樣式。代碼如下:

document.ondragleave = function(e){
    e.preventDefault();
    var el = document.getElementById('target_box');
    el.className = el.className.replace(/over/g,'');
}
document.ondrop = function(e){
    e.preventDefault();
}
document.ondragenter = function(e){
    e.preventDefault();
    var el = document.getElementById('target_box');
    el.className = el.className + ' over';
}
document.ondragover = function(e){
    e.preventDefault();
    var el = document.getElementById('target_box');
    el.className = el.className + ' over';
}

當圖片被拖到上傳區(qū)域后通過FileReader方法讀取本地文件,然后將圖片通過canvas來繪制,如果圖片的寬度是大于畫布1000px將水平居中處理,這里因為切圖的時候需要將圖片完整切出來,所以在設置canvas寬度時需要顯示成圖片的大小,所以這里使用了負marginLeft(這里將圖片寬度減1000得出超出1000的區(qū)域,然后再除于2得出marginLeft的值)外面套一層1000px的方式來實現(xiàn)水平居中。代碼如下:

var box = document.getElementById('target_box');
box.ondrop = function(e){
    e.preventDefault();
    //獲取文件列表
    var fileList = e.dataTransfer.files;
    var reader = new FileReader();
    reader.onload = function(e){
        var img = new Image();
        img.src = this.result;
        img.onload = function(){

            if(this.width&gt;1000){
                canvas.style.marginLeft = ((this.width - 1000)/2) * -1 + 'px';
            }
            canvas.width = this.width;
            canvas.height = this.height;
            ctx.drawImage(this,0,0);
        }

    }
    reader.readAsDataURL(fileList[0]);
    document.getElementById('target_box').style.display = 'none';
    document.getElementById('doc').style.display = 'display';

};

本地預覽(FileReader)

FileReader接口的方法
readAsBinaryString(file) 將文件讀取二進制碼
通常我們將它傳送到后端,后端可以通過這段字符串存儲文件
readAsText(file,[encoding]) 將文件讀取文本
第二個參數(shù)是文本的編碼方式,默認UTF-8
readAsDataURL(file) 將文件讀取為DataURL
將文件讀取為一串Data URL字符串,將小文件以一種特殊格式的URL地址直接讀入頁面。小文件指圖像與html等格式的文件。
FileReader接口的事件
onabort 數(shù)據(jù)讀取中斷時觸發(fā)
onerror 數(shù)據(jù)讀取出錯時觸發(fā)
onloadstart 數(shù)據(jù)讀取開始時觸發(fā)
onprocess 數(shù)據(jù)讀取中
onload 數(shù)據(jù)讀取成功完成時觸發(fā)
onloadend 數(shù)據(jù)讀取完成時觸發(fā),無論成功失敗

這里因為標尺不需要做任何事情處理只需要拖拽效果,所以只需要增加draggable屬性就可以,代碼如下:
a333
然后給目標元素增加Drop事件,當拖拽的標尺在目標元素上放開時新建一個參考線并通過offsetY來獲取鼠標釋放時的Y坐標,然后再將這個Y坐標存到數(shù)組里。

//增加標尺目標事件
document.getElementById('cvs').ondrop = function(ev){
    var div = document.createElement('div');
    div.style.width = '100%'
    div.style.height = '1px';
    div.style.background = '#4affff';
    div.style.position = 'absolute'
    div.style.top = ev.offsetY + 18 + 'px';
    document.getElementById('screen').appendChild(div);
    rulerTop.push(ev.offsetY);
    return false;
}

Canvas:

這里先介紹下canvas的drawImage方法,切圖的核心方法就是這個,我們先來看看官方給出的使用方法與解釋:
drawImage(image,?sourceX,?sourceY,?sourceWidth,?sourceHeight,?destX,?destY,?destWidth,?destHeight)
image 所要繪制的圖像。這必須是表示??標記或者屏幕外圖像的 Image 對象,或者是 Canvas 元素。
sourceX, sourceY 圖像將要被繪制的區(qū)域的左上角。這些整數(shù)參數(shù)用圖像像素來度量。
sourceWidth, sourceHeight 圖像所要繪制區(qū)域的大小,用圖像像素表示。
destX, destY 所要繪制的圖像區(qū)域的左上角的畫布坐標。
destWidth, destHeight 圖像區(qū)域所要繪制的畫布大小。

了解了drawImage方法后我們來看下,如何通過drawImage達到切圖效果,其實這里的切圖,只是通過drawImage加上高寬和偏移量來實現(xiàn)所謂的切圖效果,代碼如下:

//繪制圖片
function scaleCanvas (canvas, width, height, destX, destY) {
    var w = canvas.width,
        h = canvas.height;
    var cutCanvas = document.createElement('canvas');
    var cutCtx = cutCanvas.getContext('2d');
    cutCanvas.width = width;
    cutCanvas.height = height;
    cutCtx.drawImage(canvas, 0, 0, w, h, destX, destY, w, h);
    return cutCanvas;
}
//獲取圖片URL
function getDataURL (canvas, width, height, destX, destY) {
    canvas = scaleCanvas(canvas, width, height, destX, destY);
    return canvas.toDataURL('image/jpeg');
}
//將conver轉(zhuǎn)成IMG格式
var convertToImage = function (canvas, width, height, destX, destY) {
    var strData = getDataURL(canvas, width, height, destX, destY);
    return encodeURIComponent(strData);
}

這里先說下大致實現(xiàn)的原理,首先先創(chuàng)建一個新的canvas然后設置好寬高,而這個寬高就是參考線分隔的每一塊寬高,然后過通drawImage將原圖上某塊局域復制一份出來,再通過toDataURL轉(zhuǎn)成base64編碼方便本地顯示。
所在在這個Demo中image就是我們剛上傳的那個圖片,sourceX、sourceY和destWidth、destHeight取圖片的原始高寬,而我們要復制的局域也是從新的canvas上的左上角開始,所以這里的sourceX、sourceY為0,0。這里最主要的就是destX、destY,就是他們來控制復制局域的起始坐標,因為新圖片是需要從最左邊開始復制,所以destX為0,而destY將根據(jù)參考線的縱坐標來定值。

這里要注意一下,因為域的問題,所以如果頁面不是放到服務器上運行而是本地運行的話會出現(xiàn)權限報錯情況

最后附上Demo一枚,歡迎大家盡情的暴、使勁暴。(Demo只支持chrome瀏覽器,其他瀏覽器會有不良反應,請見諒)

好了,整個HTML5自助化切圖的主要代碼就這些,這里第一次嘗試用HTML5去做一些實實在在的東西,可能代碼并不是最優(yōu),還能繼續(xù)優(yōu)化,大家如果對于文章有什么建議或不明白的地方歡迎討論。

在舊版的切圖工具里,我們的做法是將圖片上傳到服務器,然后通過服務器端把圖片切好后把對應的地址返回,前端再把頁面顯示出來。這樣的做法會導致在網(wǎng)絡慢時出現(xiàn)長時間的等待,而如果頁面放棄這里的操作,還需要將圖片從服務器端刪除掉。在拖拽參考線時也只能通過大量的代碼去實現(xiàn),還需要編寫一些服務器端代碼。

HTML5版相對有響應速度快(本地讀取)、拖拽功能簡單、前端切圖不需要依賴服務器,減少開發(fā)成本。

反正HTML5是個上流、好玩、有趣、簡單的好東西,值得你一生擁有。

寫完文章已經(jīng)凌晨兩點半,根據(jù)官方和非官方統(tǒng)計,這個時間段被坑機率是平時的0.000001%,實踐是檢驗真理的唯一標準。而為了檢驗這個標準我?guī)еv的身軀,打開客戶端進入匹配模式。
裸多蘭一級升E下路孤獨神級大嘴再次上路,德瑪西亞。。。

來源:騰訊gdc

更多精彩內(nèi)容,請關注人人都是產(chǎn)品經(jīng)理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發(fā)揮!