# 新增可移動文字方塊與Html2Canvas區塊下載 ###### codepen:https://codepen.io/liu_0821/pen/NWePBZQ ![](https://hackmd.io/_uploads/S1o933STh.png) ## 主要說明 1. 說明 `touchmove` 和 `mousemove` 的實際應用方式。 2. 當 `Html2Canvas` 遇到不支援的 CSS3 的解決方法。 3. 簡易的文字設定與套用方法。 ## 部分HTML ``` <div class="col-12 selectGroup"> <select class="form-select" id="fontStyle"> ... // 文字字型 </select> <select class="form-select" id="fontSize"> ... // 文字大小 </select> <select class="form-select" id="fontWeight"> ... // 文字粗細 </select> <select class="form-select" id="fontOrientation"> ... // 文字方向 </select> </div> <input type="text" class="col-12 inputText" placeholder="請輸入文字"> <div class="col-12 btnGroup"> <button class="col-12 btn btn-success" id="addText">新增</button> </div> <div class="moveGroup"> <button class="btn btn-danger" id="delete"> 刪除 </button> <button class="btn btn-success" id="save"> 下載 </button> <div class="col-12 touchDiv"> </div> </div> ``` ## 部分CSS - `writing-mode` 不支援html2Canvas。 ``` .moveDivText{ // 移動文字方塊 width: auto; border:1px solid #ced4da; border-radius: .375rem; font-family:"serif"; font-size:18px; font-weight: 500; text-align: center; position: absolute; // 設定可移動 cursor: move; z-index: 0; transform: scale(1); left: 0; top: 0; padding: .375rem; } .moveDivText:active{ // 點選之後有紅框 opacity: .8; border:2px solid #d13e3e; } .mixed{ // 文字方塊橫向 -webkit-writing-mode: horizontal-tb; writing-mode: horizontal-tb; text-orientation:mixed; } .upright{ // 文字方塊直向 // 解決方案 transform: rotate(0deg); // html2Canvas 不支援的CSS樣式 /* -webkit-writing-mode: vertical-lr; writing-mode: sideways-rl; 中文垂直 text-orientation:upright; 英文垂直 */ } .chose{ // 被選取的樣式 opacity: .8; border:2px solid #d13e3e; } ``` ## JS ### 建立文字方塊與設定文字屬性 - 由於html2Canvas不支援垂直屬性,在每個字中間穿插`</br>`換行,再利用`transform`屬性呈現出文字垂直的樣式 ``` // 文字屬性 $("#fontStyle").on("change",(e)=>{ $('.inputText').css('font-family',$(e.target)val()); }); $("#fontSize").on("change",(e)=>{ $('.inputText').css('font-size',$(e.target).val() + "px"); }); $("#fontWeight").on("change",(e)=>{ $('.inputText').css('font-weight',$(e.target).val()); }); $("#addText").on('click',(e)=>{ // 未輸入文字會跳出去 if($(".inputText").val() =="" ){ return; } // 建立文字方塊 let div = document.createElement("div"); if($("#fontOrientation").val().includes("mixed")){ $(div).attr('class','moveDivText mixed'); $(div).text($('.inputText').val()); }else if($("#fontOrientation").val().includes("upright")){ $(div).attr('class','moveDivText upright'); // 穿插</br> 換行顯示出直向的感覺 let _inputValue = $('.inputText').val().split('').join('</br>'); $(div).html(_inputValue); } $(div).css('font-family',$("#fontStyle").val()); $(div).css('font-size',$("#fontSize").val() + "px"); $(div).css('font-weight',$("#fontWeight").val()); $(div).css('z-index',$(".touchDiv").find('.moveDivText').length); $('.touchDiv').append(div); move(); setTimeout((e)=>{ $('.inputText').val(""); },300); }); ``` ### 觸控與滑鼠操作 ``` let moveDiv = false; // 移動 function move(){ $('.moveDivText').each((i,dom)=>{ $('.moveDivText').removeClass('chose'); $(dom).click((e)=>{ $(e.target).addClass('chose'); clickMove($(e.target)); }); }); } // 被選取的可移動 function clickMove(dom){ document.body.addEventListener('touchmove',function(e){e.preventDefault(); },false); let doms = $(dom).[0]; let _text_scale = $(doms).css('transform'); let tr = _text_scale.split('(')[1].split(')')[0].split(',') let scale =Math.sqrt(tr[0] * tr[0] + tr[1] * tr[1]); // 抓目前scale值 let store={ scale:Math.sqrt(tr[0] * tr[0] + tr[1] * tr[1]) }; doms.onmousedown = function (e) { $('.moveDivText').removeClass('chose'); $(dom).addClass('chose'); moveDiv = true; x = e.clientX - doms.offsetLeft; y = e.clientY - doms.offsetTop; // $(doms).addClass('chose'); document.onmousemove = function (e) { if (!moveDiv) { return; } doms.style.left = e.clientX - x + 'px'; doms.style.top = e.clientY - y + 'px'; // 按住左鍵才可以滾輪放大 / 縮小 doms.onmousewheel = (e) => { if (!moveDiv) { return; } if (e.wheelDelta > 0) { scale += 0.04 if (scale > 3.5) { scale = 3.5 } } if (e.wheelDelta < 0) { scale -= 0.04 if (scale < 0.75) { scale = .75 } } $(doms).css('transform', 'scale(' + scale + ')'); }; document.onmouseup = function () { moveDiv = false; $(doms).removeClass('chose'); doms.onmousemove = null; document.onmouseup = null; }; } } // touch doms.addEventListener('touchstart', function (event) { $('.moveDivText').removeClass('chose'); $(event.target).addClass('chose'); moveDiv = false; var touches = event.touches; var events = touches[0]; var events2 = touches[1]; var x = doms.offsetLeft; var y = doms.offsetTop; console.log(events) event.preventDefault(); // 擷取第1根手指座標 store.pageX = events.pageX; store.pageY = events.pageY; store.moveable = true; store.x = x; store.y = y; if (events2) { store.pageX2 = events2.pageX; store.pageY2 = events2.pageY; } store.originScale = store.scale || 1; }); doms.addEventListener('touchmove', function (event) { if (!store.moveable) { return; } event.preventDefault(); var touches = event.touches; var events = touches[0]; var events2 = touches[1]; // 兩隻手指移動 if (events2) { // 擷取第2根手指座標 if (!store.pageX2) { store.pageX2 = events2.pageX; } if (!store.pageY2) { store.pageY2 = events2.pageY; } // 獲取座標 var getDistance = function (start, stop) { return Math.hypot(stop.x - start.x, stop.y - start.y); }; // 雙指縮放比例計算 var zoom = getDistance({ x: events.pageX, y: events.pageY }, { x: events2.pageX, y: events2.pageY }) / getDistance({ x: store.pageX, y: store.pageY }, { x: store.pageX2, y: store.pageY2 }); // 應用在div上的比例 var newScale = store.originScale * zoom; // 最小比例 if (newScale < .5) { newScale = .5; } // 最大比例 if (newScale > 3) { newScale = 3; } store.scale = newScale; // 圖片縮放應用 doms.style.transform = 'scale(' + newScale + ')'; } else { var moveX = events.pageX - store.pageX; var moveY = events.pageY - store.pageY; var imagetop = store.x + moveX; var imageleft = store.y + moveY; // console.log(imagetop,imageleft) $(doms).css({ 'top': imageleft + 'px', 'left': imagetop + 'px' }); } }); doms.addEventListener('touchend', function () { $(event.target).addClass('chose'); store.moveable = false; moveDiv = false; delete store.pageX2; delete store.pageY2; }); doms.addEventListener('touchcancel', function (event) { $(event.target).addClass('chose'); store.moveable = false; moveDiv = false; delete store.pageX2; delete store.pageY2; }); } ``` ### 刪除被選取的元素 ``` $('#delete').click((e)=>{ console.log(111) $('.moveDivText').each((i,dom)=>{ console.log(dom) if($(dom).attr('class').includes('chose')){ $(dom).remove(); return; } }); }); ``` ### Html2Canvas下載 - 關於這個套件的簡單說明可以看我另一篇文章唷~[點我查看](https://hackmd.io/@LindaLiu/S1VCu9B6n) ``` $('#save').click((e) => { $('.moveDivText').css('border','none'); let dom =document.querySelector(".touchDiv"); html2canvas(dom,{ width:dom.clientWidth, //擷取畫面之寬高 height:dom.clientHeight, scrollX:0, scrollY:0, useCORS:true, allowTaint:true }).then(function (canvas) { a = document.createElement("a"); a.href = canvas.toDataURL("image/jpeg"); a.download = "我的檔案.jpeg"; a.click(); $('.moveDivText').css('border','1px solid #ced4da'); $('.touchDiv').find('div').remove(); }); }); ``` --- ##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人 ##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~