document.getElementById("info").innerHTML += "paper width (px)" + document.getElementById("paper").offsetWidth + "
"; function css(element, property) { return window.getComputedStyle(element, null).getPropertyValue(property); } var paper = document.getElementById('paper'); var paperPage1 = document.getElementById('paper-page1'); var font_family = css(paper, 'font-family'); var font_size = css(paper, 'font-size'); paper.addEventListener('input', getWordsWidth); paper.addEventListener('keydown', function (e) { if (e.key == " ") { //enter e.preventDefault(); //Prevent default browser behavior var sel; var range; sel = window.getSelection(); range = sel.getRangeAt(0); range.deleteContents(); var textNode = document.createTextNode('\u00A0'); // no linebreaking-space range.insertNode(textNode); range.setStartAfter(textNode); sel.addRange(range); getWordsWidth(); // paper.innerHTML+= paper.innerHTML; //var currentPage = document.getElementById(getCaretCurrentPageId()); //var currentRange = getCursorLengthRange(currentPage); //var HTMLBeforeCaret = rangeToHTMLFragement(currentRange); } }); // 如果游標在 contentdiveditable id "paper-page1" 裡面, // 該函數返回 "paper-page1" function getCaretCurrentPageId() { var anchorNode = window.getSelection().anchorNode; var currentNode = anchorNode; while (currentNode.id === undefined || !(currentNode.id.match(/^paper-page\d+/))) { currentNode = currentNode.parentNode; } return currentNode.id; } // 得到子節點(文字物件) // ["dolore", [ "m ips", ["um si"], "t am"], "et"] function getChildNodes(ele) { var res_array; res_array = []; if (ele.nodeType == Node.TEXT_NODE) { return ele; } else { for (var i = 0; i < ele.childNodes.length; i++) { res_array.push(getChildNodes((ele.childNodes[i]))); } return res_array; } } // 平坦化陣列 // [a, [b, c, d], [[e]]] => [a, b, c, d, e] function flatten(arr) { if (!Array.isArray(arr)) { return arr; } else { var result = []; for (var i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result.push(arr[i]); } } return result; } } /* 從第幾個字到第幾個字選 range. */ function selecRengeFromCharToChar(i, j, ele) { var range = document.createRange(); var sel = document.getSelection(); var flattened_ar = flatten(getChildNodes(ele)); range.selectNodeContents(ele); var ran_start = i; var ran_end = j; var ran_start_is_set = false; for (var i = 0; i < flattened_ar.length; i++) { var fragement_text_length = flattened_ar[i].textContent.length; // 如果 ran_start > 碎片長度 if (ran_start > fragement_text_length) { ran_start -= fragement_text_length; ran_end -= fragement_text_length; // 如果 ran_start <= 碎片長度 } else if (ran_start <= fragement_text_length && ran_start_is_set == false) { range.setStart(flattened_ar[i], ran_start); ran_start_is_set = true; // 如果 ran_end > 碎片長度 if (ran_end > fragement_text_length) { ran_end -= fragement_text_length; // 如果 ran_end <= 碎片長度,setEnd 中止迴圈 } else { range.setEnd(flattened_ar[i], ran_end); break; } // 如果 ran_end > 碎片長度 } else if (ran_end > fragement_text_length && ran_start_is_set == true) { ran_end -= fragement_text_length; } // 如果 ran_end <= 碎片長度,setEnd 中止迴圈 else { range.setEnd(flattened_ar[i], ran_end); break; } } var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); return range; } /* 設置游標位置於 ele 要素的第 col 個字(不含標籤),例子: HTML
dolorem ipsum sit amet 1234
setCaret(document.getElementById('paper-page1'),10) V CARET
dolorem ip|sum sit amet 1234
*/ function setCaret(ele, col) { var range = document.createRange(); var sel = document.getSelection(); var flattened_ar = flatten(getChildNodes(ele)); // flattened array range.selectNodeContents(ele); var ran_start = col; for (var i = 0; i < flattened_ar.length; i++) { var fragement_text_length = flattened_ar[i].textContent.length; if (ran_start > fragement_text_length) { ran_start -= fragement_text_length; } else { range.setEnd(flattened_ar[i], ran_start); range.collapse(); break; } } var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } // 將座標轉成座標所在位置的 range function getCursorLengthRange(ele) { var win = ele.ownerDocument.defaultView; var range = win.getSelection().getRangeAt(0); var cloneRange = range.cloneRange(); cloneRange.selectNodeContents(ele); cloneRange.setEnd(range.endContainer, range.endOffset); return cloneRange; } // 將座標 range 轉成字串的長度 function rangeToStringLen(range) { return range.toString().length; } // 將座標位置 range 轉成 html 斷片 function rangeToHTMLFragement(range) { var nodes = range.cloneContents().childNodes; var result = ""; for (var i = 0; i < nodes.length; i++) { var parentNode = nodes[i].parentNode; var div = document.createElement("div"); div.appendChild(parentNode); if (typeof (nodes[i].outerHTML) === "undefined") { result += nodes[i].textContent; } else { result += nodes[i].outerHTML; } console.log("Parent Node" + div.outerHTML); } return result; } // 得到一個 word 或是 character 的寬度 function getTextWidth(text, fontfamily, fontsize) { console.log(text); var decodedText = decodeEntities(text); var canvas = document.createElement("canvas"); var context = canvas.getContext("2d"); context.font = fontsize + " " + fontfamily; var width = context.measureText(decodedText).width; return width; } // 得到字寬 function getWordsWidth() { document.getElementById('line-info').innerHTML = ""; var array = paper.childNodes; var res = []; for (var i = 0; i < array.length; i++) { if (array[i].nodeType != Node.TEXT_NODE) { res.push(array[i]); } } var innerArray = res.map(function (x) { return x.innerHTML; }); var innerHTMLTotal = innerArray.reduce(function (x, y) { return (x + y); }); var innerHTMLRemoveTags = innerHTMLTotal.replace(/[<][\/]?[^<]+[\/]?[>]/gi, ""); // 移除標籤 var innerHTMLSplitted = innerHTMLRemoveTags.split(/( |\s| |[⺀-\u2efe\u3000-〾㇀-\u31ee㌀-㏾㐀-\u4dbe一-\u9ffe豈-\ufafe︰-﹎]|[\ud840-\ud868\ud86a-\ud86c][\udc00-\udfff]|\ud869[\udc00-\udede\udf00-\udfff]|\ud86d[\udc00-\udf3e\udf40-\udfff]|\ud86e[\udc00-\udc1e]|\ud87e[\udc00-\ude1e])/).filter(function (item) { return item != ""; }); console.log(innerHTMLSplitted); //var innerHTMLSplittedLength = innerHTMLSplitted.map((x)=>x.length) //var innerHTMLSelectedRange = []; /*var sum = 0 for (var i=0; i rangeToHTMLFragement(selecRengeFromCharToChar(x[0],x[1],paper))) console.log("Range 結果"+innerHTMLSplittedRange);*/ var textWidthList = innerHTMLSplitted.map(function (x) { return getTextWidth(x, font_family, font_size); }); var lineInfoLength = []; for (var i = 0; i < innerHTMLSplitted.length; i++) { var object = { "content": innerHTMLSplitted[i], "length": textWidthList[i] }; document.getElementById("line-info").innerHTML += "(" + innerHTMLSplitted[i] + ","; document.getElementById("line-info").innerHTML += textWidthList[i] + ")"; lineInfoLength.push(object); } // document.getElementById("info").innerHTML += lineInfoLength; } // 將要在地幾個字插入符號,改為修正為在有標籤的 HTML 的片段中,第幾個不算標籤的字插入符號 /* > getrealcol(5, "example") > 5 > getrealcol(5, "example") > 14 */ function getrealcol(n, str) { var arr = str.split(RegExp("(<[^<>]+>)")).map(function (x) { return ({ cont: x, len: x.length }); }); var j = 0; var k = 0; for (var i = 0; i < arr.length; i++) { if (arr[i].cont.match(/^[<]/)) { continue; } else { if (n > arr[i].len) { n = n - arr[i].len; } else { j = i; k = n; break; } } ; } var res_col = 0; for (var i = 0; i < j; i++) { res_col += arr[i].len; } res_col += k; return res_col; } // 解碼 &1234; 這種東西用 function decodeEntities(encodedString) { var textArea = document.createElement('textarea'); textArea.innerHTML = encodedString; return textArea.value; }