From f7a1773105268bbb6b593f8f0d29309bd7c5f548 Mon Sep 17 00:00:00 2001 From: Kulikova Svetlana Date: Fri, 16 Jul 2021 18:30:30 +0300 Subject: [PATCH] text selection --- DjVuFile/wasm/all_files_test/code.js | 67 +++++-------- DjVuFile/wasm/all_files_test/file.js | 143 ++++++++++++++++++--------- 2 files changed, 119 insertions(+), 91 deletions(-) diff --git a/DjVuFile/wasm/all_files_test/code.js b/DjVuFile/wasm/all_files_test/code.js index 6c7f584fca..b31a153023 100644 --- a/DjVuFile/wasm/all_files_test/code.js +++ b/DjVuFile/wasm/all_files_test/code.js @@ -108,13 +108,13 @@ window.onload = function() this.zoom = 1; this.drawingPages = []; this.isRepaint = false; - this.canvas = document.getElementById("main"); + this.canvas = document.getElementById("main"); this.scroller = document.getElementById("pos"); - this.documentWidth = 0; + this.documentWidth = 0; this.documentHeight = 0; + this.Selection = { IsSelection : false, Image : null, page : -1 }; this.file = new AscViewer.DjVuFile(); - this.file.cacheManager = new CCacheManager(); /* [TIMER START] @@ -161,8 +161,8 @@ window.onload = function() }; window.onscroll = function(e) { if (window.Viewer) window.Viewer.scroll(e); }; - window.onmousedown = function(e) { if (window.Viewer) window.Viewer.OnMouseDown(e); }; - window.onmousemove = function(e) { if (window.Viewer) window.Viewer.OnMouseMove(e); }; + window.onmousedown = function(e) { if (window.Viewer) window.Viewer.OnMouse(e, true); }; + window.onmousemove = function(e) { if (window.Viewer) window.Viewer.OnMouse(e, false); }; window.onmouseup = function(e) { if (window.Viewer) window.Viewer.OnMouseUp(e); }; this.timerAnimation = function() @@ -249,6 +249,7 @@ window.onload = function() if (this.file) this.file.close(); this.file = window["AscViewer"].createFile(data); + this.Selection.Image = this.cacheManager ? this.cacheManager.lock(0, 0) : document.createElement("canvas"); document.scrollingElement.scrollLeft = 0; document.scrollingElement.scrollTop = 0; @@ -322,60 +323,40 @@ window.onload = function() this.paint(); }; - this.OnMouseDown = function(e) + this.OnMouse = function(e, down) { if (!this.file.isValid()) return; - let yPos = e.clientY; - let yMax = yPos + this.height; let lCurrentPage = -1; - - let lPagesCount = this.drawingPages.length; - for (let i = 0; i < lPagesCount; i++) + for (let i = 0; i < this.drawingPages.length; i++) { let page = this.drawingPages[i]; let pageT = page.Y; let pageB = page.Y + page.H; - if (yPos > pageT && yPos < pageB) + if (e.pageY > pageT && e.pageY < pageB) { lCurrentPage = i; break; } } - // TODO: координаты относительно страницы if (lCurrentPage >= 0) - this.file.OnMouseDown(lCurrentPage, e.clientX, e.clientY); - }; - - this.OnMouseMove = function(e) - { - if (!this.file.isValid()) - return; - - let yPos = e.clientY; - let yMax = yPos + this.height; - let lCurrentPage = -1; - - let lPagesCount = this.drawingPages.length; - for (let i = 0; i < lPagesCount; i++) { - let page = this.drawingPages[i]; - let pageT = page.Y; - let pageB = page.Y + page.H; - - if (yPos > pageT && yPos < pageB) - { - lCurrentPage = i; - break; - } + let yPos = (document.scrollingElement.scrollTop * this.zoom) >> 0; + let page = this.drawingPages[lCurrentPage]; + let w = (page.W * this.retinaPixelRatio) >> 0; + let h = (page.H * this.retinaPixelRatio) >> 0; + let x = e.pageX - (Math.max(0, (this.width - this.documentWidth) >> 1) * this.retinaPixelRatio) >> 0; + let y = e.pageY - (page.Y * this.retinaPixelRatio) >> 0; + this.Selection.page = lCurrentPage; + if (down) + this.file.OnMouseDown(lCurrentPage, this.Selection, x, y, w, h); + else + this.file.OnMouseMove(lCurrentPage, this.Selection, x, y, w, h); + this.paint(); } - - // TODO: координаты относительно страницы - if (lCurrentPage >= 0) - this.file.OnMouseMove(lCurrentPage, e.clientX, e.clientY); }; this.OnMouseUp = function(e) @@ -395,8 +376,7 @@ window.onload = function() if (!this.file.isValid()) return; - - this.canvas.width = this.canvas.width; + let ctx = this.canvas.getContext("2d"); ctx.strokeStyle = "#000000"; let lineW = this.retinaPixelRatio >> 0; @@ -472,6 +452,8 @@ window.onload = function() let y = ((page.Y - yPos) * this.retinaPixelRatio) >> 0; ctx.drawImage(page.Image, 0, 0, w, h, x, y, w, h); + if (this.Selection.page == i && this.Selection.IsSelection) + ctx.drawImage(this.Selection.Image, 0, 0, w, h, x, y, w, h); ctx.strokeRect(x + lineW / 2, y + lineW / 2, w - lineW, h - lineW); } @@ -481,6 +463,7 @@ window.onload = function() window.Viewer = new CHtmlPage(); window.Viewer.resize(); window.Viewer.startTimer(); + window.CCacheManager = CCacheManager; }; window.onresize = function(e) diff --git a/DjVuFile/wasm/all_files_test/file.js b/DjVuFile/wasm/all_files_test/file.js index fc4bd827ed..1e627edaa9 100644 --- a/DjVuFile/wasm/all_files_test/file.js +++ b/DjVuFile/wasm/all_files_test/file.js @@ -84,98 +84,143 @@ var _glyph = -1; var minDist = Number.MAX_SAFE_INTEGER; - // TODO: оптимизировать по горизонтальной линии for (let i = 0; i < this.pages[pageIndex].Lines.length; i++) { - for (let j = 0; j < this.pages[pageIndex].Lines[i].Glyphs.length; j++) + let Y = this.pages[pageIndex].Lines[i].Glyphs[0].Y; + if (Math.abs(Y - y) < minDist) { - let glyph = this.pages[pageIndex].Lines[i].Glyphs[j]; - let d = Math.sqrt(Math.pow(glyph.X - x, 2) + Math.pow(glyph.Y - y, 2)); - if (d < minDist) - { - minDist = d; - _line = i; - _glyph = j; - } + minDist = Math.abs(Y - y); + _line = i; + } + } + minDist = Number.MAX_SAFE_INTEGER; + for (let j = 0; j < this.pages[pageIndex].Lines[_line].Glyphs.length; j++) + { + let X = this.pages[pageIndex].Lines[_line].Glyphs[j].X; + if (Math.abs(X - x) < minDist) + { + minDist = Math.abs(X - x); + _glyph = j; } } return { Line : _line, Glyph : _glyph }; } - CFile.prototype.OnUpdateSelection = function() + CFile.prototype.OnUpdateSelection = function(Selection, width, height) { - // TODO: выделять не после OnMouseUp - if (this.Selection.IsSelection) + if (!this.Selection.IsSelection) return; var sel = this.Selection; - var page1 = sel.Page1 < sel.Page2 ? sel.Page1 : sel.Page2; - var page2 = sel.Page1 > sel.Page2 ? sel.Page1 : sel.Page2; - var line1 = sel.Line1 < sel.Line2 ? sel.Line1 : sel.Line2; - var line2 = sel.Line1 > sel.Line2 ? sel.Line1 : sel.Line2; - var glyph1 = sel.Glyph1 < sel.Glyph2 ? sel.Glyph1 : sel.Glyph2; - var glyph2 = sel.Glyph1 > sel.Glyph2 ? sel.Glyph1 : sel.Glyph2; + var page1 = sel.Page1; + var page2 = sel.Page2; + var line1 = sel.Line1; + var line2 = sel.Line2; + var glyph1 = sel.Glyph1; + var glyph2 = sel.Glyph2; + if (page1 == page2 && line1 == line2 && glyph1 == glyph2) + { + Selection.IsSelection = false; + return; + } + else if (page1 == page2 && line1 == line2) + { + glyph1 = Math.min(sel.Glyph1, sel.Glyph2); + glyph2 = Math.max(sel.Glyph1, sel.Glyph2); + } + else if (page1 == page2) + { + if (line1 > line2) + { + line1 = sel.Line2; + line2 = sel.Line1; + glyph1 = sel.Glyph2; + glyph2 = sel.Glyph1; + } + } + + if (this.cacheManager) + { + this.cacheManager.unlock(Selection.Image); + Selection.Image = this.cacheManager.lock(width, height); + } + else + { + delete Selection.Image; + Selection.Image = document.createElement("canvas"); + Selection.Image.width = width; + Selection.Image.height = height; + } + let ctx = Selection.Image.getContext("2d"); + // TODO: После изменения размера экрана наложение областей выделения + ctx.clearRect(0, 0, Selection.Image.width, Selection.Image.height); + ctx.globalAlpha = 0.4; + ctx.fillStyle = "#7070FF"; for (let page = page1; page <= page2; page++) { - // TODO: если страница не последняя, то выделить целиком - for (let line = line1; line <= line2; line++) + let start = 0; + let end = this.pages[page].Lines.length; + if (page == page1) + start = line1; + if (page == page2) + end = line2; + for (let line = start; line <= end; line++) { let Glyphs = this.pages[page].Lines[line].Glyphs; let x = Glyphs[0].X; - let y = Glyphs[0].Y; - let w = Glyphs[Glyphs.length - 1].X; - let h = x + Glyphs[0].fontSize; - // если последняя строка - if (line == line2) - w = Glyphs[glyph2].X; - // TODO: поступить аналогично _pixelsToCanvas2d - let canvas = document.getElementById("main"); - let ctx = canvas.getContext("2d"); - ctx.globalAlpha = 0.5; - ctx.fillStyle = "#0000FF"; + let y = Glyphs[0].Y - Glyphs[0].fontSize; + // первая строка на первой странице + if (page == page1 && line == start) + x = Glyphs[glyph1].X; + let w = Glyphs[Glyphs.length - 1].X - x; + let h = Glyphs[0].fontSize; + // последняя строка на последней странице + if (page == page2 && line == end) + w = Glyphs[glyph2].X - x; + ctx.fillRect(x, y, w, h); - ctx.globalAlpha = 1; } } + ctx.globalAlpha = 1; + Selection.IsSelection = true; } - CFile.prototype.OnMouseDown = function(pageIndex, x, y) + CFile.prototype.OnMouseDown = function(pageIndex, Selection, x, y, w, h) { var ret = this.GetNearestPos(pageIndex, x, y); var sel = this.Selection; - sel.Page1 = pageIndex; - sel.Line1 = ret.Line; + sel.Page1 = pageIndex; + sel.Line1 = ret.Line; sel.Glyph1 = ret.Glyph; - sel.Page2 = pageIndex; - sel.Line2 = ret.Line; + sel.Page2 = pageIndex; + sel.Line2 = ret.Line; sel.Glyph2 = ret.Glyph; sel.IsSelection = true; - //this.OnUpdateSelection(); + this.OnUpdateSelection(Selection, w, h); } - CFile.prototype.OnMouseMove = function(pageIndex, x, y) + CFile.prototype.OnMouseMove = function(pageIndex, Selection, x, y, w, h) { if (false === this.Selection.IsSelection) return; var ret = this.GetNearestPos(pageIndex, x, y); var sel = this.Selection; - sel.Page2 = pageIndex; - sel.Line2 = ret.Line; + sel.Page2 = pageIndex; + sel.Line2 = ret.Line; sel.Glyph2 = ret.Glyph; - //this.OnUpdateSelection(); + this.OnUpdateSelection(Selection, w, h); } CFile.prototype.OnMouseUp = function() { this.Selection.IsSelection = false; - this.OnUpdateSelection(); } CFile.prototype.getPageBase64 = function(pageIndex, width, height) @@ -222,7 +267,9 @@ return canvas; }; - var vs_source = "\ + CFile.prototype._pixelsToCanvas3d = function(pixels, width, height) + { + var vs_source = "\ attribute vec2 aVertex;\n\ attribute vec2 aTex;\n\ varying vec2 vTex;\n\ @@ -231,16 +278,13 @@ void main() {\n\ vTex = aTex;\n\ }"; - var fs_source = "\ + var fs_source = "\ precision mediump float;\n\ uniform sampler2D uTexture;\n\ varying vec2 vTex;\n\ void main() {\n\ gl_FragColor = texture2D(uTexture, vTex);\n\ }"; - - CFile.prototype._pixelsToCanvas3d = function(pixels, width, height) - { var canvas = null; if (this.cacheManager) { @@ -403,6 +447,7 @@ void main() {\n\ } file.loadFromData(data); + file.cacheManager = new window.CCacheManager(); return file; };