Revise canvas management
This commit is contained in:
		| @@ -10,8 +10,8 @@ | ||||
|     <script src="../service.js"></script> | ||||
|     <script src="common.js"></script> | ||||
|   </head> | ||||
|   <body style="background-color: gray;"> | ||||
|     <!-- <p class="my-block">This is an example of a simple <code><div contenteditable="true"></code> edit control. Edit the text, resize the control or browser window, scroll around, click...</p> --> | ||||
|   <body> | ||||
|     <p class="my-block">This is an example of a simple <code><div contenteditable="true"></code> edit control. Edit the text, resize the control or browser window, scroll around, click...</p> | ||||
|     <div id="my-editor" class="my-block my-control" contenteditable="true"> | ||||
|       <p>Tukaj vpišite besedilo ki ga želite popraviti.</p> | ||||
|       <p>Prišla je njena lepa hčera. Smatram da tega nebi bilo potrebno storiti. Predavanje je trajalo dve ure. S njim grem v Kamnik. Janez jutri nebo prišel. Prišel je z 100 idejami.</p> | ||||
|   | ||||
							
								
								
									
										178
									
								
								service.js
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								service.js
									
									
									
									
									
								
							| @@ -279,6 +279,7 @@ class BesService { | ||||
|     // Scroll panel is "position: absolute", we need to keep it aligned with the host element. | ||||
|     this.scrollPanel.style.top = `${-this.hostElement.scrollTop}px` | ||||
|     this.scrollPanel.style.left = `${-this.hostElement.scrollLeft}px` | ||||
|  | ||||
|     if (this.hostElement !== this.textElement) { | ||||
|       this.textElement.scrollTop = this.hostElement.scrollTop | ||||
|       this.textElement.scrollLeft = this.hostElement.scrollLeft | ||||
| @@ -314,11 +315,7 @@ class BesService { | ||||
|       rect.left !== this.hostBoundingClientRect.left | ||||
|     ) | ||||
|       this.onReposition() | ||||
|     if ( | ||||
|       rect.width !== this.hostBoundingClientRect.width || | ||||
|       rect.height !== this.hostBoundingClientRect.height | ||||
|     ) | ||||
|       this.onResize() | ||||
|     this.onResize() | ||||
|     this.hostBoundingClientRect = rect | ||||
|   } | ||||
|  | ||||
| @@ -330,62 +327,29 @@ class BesService { | ||||
|    * @returns {Array} Grammar mistake highlight elements | ||||
|    */ | ||||
|   addMistakeMarkup(range, ruleId) { | ||||
|     const canvasPanelRect = this.canvasPanel.getBoundingClientRect() | ||||
|     const highlights = [] | ||||
|     this.canvasPanel.classList.add('bes-canvas') | ||||
|  | ||||
|     this.ctx.lineWidth = 1 | ||||
|     const scrollPanelRect = this.scrollPanel.getBoundingClientRect() | ||||
|     let highlights = [] | ||||
|     const dpr = window.devicePixelRatio | ||||
|     this.ctx.lineWidth = 1 * dpr | ||||
|     this.ctx.strokeStyle = ruleId.startsWith('MORFOLOGIK_RULE') | ||||
|       ? '#e91313' | ||||
|       : '#269b26' | ||||
|  | ||||
|     for (let rect of range.getClientRects()) { | ||||
|       const x = rect.left - canvasPanelRect.left | ||||
|       const y = rect.top - canvasPanelRect.top + rect.height | ||||
|       const width = rect.width | ||||
|       const height = rect.height | ||||
|  | ||||
|       const globalX = rect.left + window.scrollX | ||||
|       const globalY = rect.top + window.scrollY | ||||
|       const x = (rect.left - scrollPanelRect.left) * dpr | ||||
|       const y = (rect.top - scrollPanelRect.top) * dpr | ||||
|       const width = rect.width * dpr | ||||
|       const height = rect.height * dpr | ||||
|  | ||||
|       // Draw the underline | ||||
|       this.ctx.beginPath() | ||||
|       this.ctx.moveTo(x, y) | ||||
|       this.ctx.lineTo(x + width, y) | ||||
|       this.ctx.moveTo(x, y + height) | ||||
|       this.ctx.lineTo(x + width, y + height) | ||||
|       this.ctx.stroke() | ||||
|       const rectCoords = { x, y, width, height, globalX, globalY } | ||||
|       highlights.push(rectCoords) | ||||
|       highlights.push(rect) | ||||
|     } | ||||
|  | ||||
|     return highlights | ||||
|   } | ||||
|  | ||||
|   // addMistakeMarkup(range, ruleId) { | ||||
|   //   const scrollPanelRect = this.scrollPanel.getBoundingClientRect() | ||||
|   //   let highlights = [] | ||||
|   //   for (let rect of range.getClientRects()) { | ||||
|   //     const highlight = document.createElement('div') | ||||
|   //     highlight.classList.add( | ||||
|   //       ruleId.startsWith('MORFOLOGIK_RULE') | ||||
|   //         ? 'bes-spelling-mistake' | ||||
|   //         : 'bes-grammar-mistake' | ||||
|   //     ) | ||||
|   //     highlight.style.left = `${rect.left - scrollPanelRect.left}px` | ||||
|   //     highlight.style.top = `${rect.top - scrollPanelRect.top}px` | ||||
|   //     highlight.style.width = `${rect.width}px` | ||||
|   //     highlight.style.height = `${rect.height}px` | ||||
|   //     this.scrollPanel.appendChild(highlight) | ||||
|   //     highlights.push(highlight) | ||||
|   //   } | ||||
|   //   return highlights | ||||
|   // } | ||||
|   // highlight.style.left = `${rect.left - scrollPanelRect.left}px` | ||||
|   // highlight.style.top = `${rect.top - scrollPanelRect.top}px` | ||||
|   // highlight.style.width = `${rect.width}px` | ||||
|   // highlight.style.height = `${rect.height}px` | ||||
|   // this.scrollPanel.appendChild(highlight) | ||||
|   // highlights.push(highlight) | ||||
|  | ||||
|   /** | ||||
|    * Tests if given coordinate is inside of a rectangle. | ||||
|    * | ||||
| @@ -394,28 +358,8 @@ class BesService { | ||||
|    * @param {DOMRect} rect Rectangle | ||||
|    * @returns | ||||
|    */ | ||||
|   static isPointInRect(x, y, rect, canvasPanel) { | ||||
|     const canvasRect = canvasPanel.getBoundingClientRect() | ||||
|     const globalWidth = rect.x + rect.width | ||||
|     const globalHeight = rect.y - rect.height | ||||
|  | ||||
|     const newX = x - canvasRect.left | ||||
|     const newY = y - canvasRect.top | ||||
|     console.log( | ||||
|       'x:', | ||||
|       newX, | ||||
|       'y:', | ||||
|       newY, | ||||
|       'globalWidth:', | ||||
|       globalWidth, | ||||
|       'globalHeight:', | ||||
|       globalHeight | ||||
|     ) | ||||
|     console.log(rect) | ||||
|     return ( | ||||
|       rect.x <= newX && newX < globalWidth && globalHeight <= newY && newY < y | ||||
|     ) | ||||
|     // return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom | ||||
|   static isPointInRect(x, y, rect) { | ||||
|     return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom | ||||
|   } | ||||
|  | ||||
|   /** | ||||
| @@ -432,6 +376,9 @@ class BesService { | ||||
|     this.scrollPanel.classList.add('bes-correction-panel-scroll') | ||||
|  | ||||
|     this.canvasPanel = document.createElement('canvas') | ||||
|     this.canvasPanel.classList.add('bes-canvas') | ||||
|     this.ctx = this.canvasPanel.getContext('2d') | ||||
|     this.ctx.scale(1, 1) | ||||
|  | ||||
|     panelParent.appendChild(this.correctionPanel) | ||||
|     this.correctionPanel.appendChild(this.scrollPanel) | ||||
| @@ -446,6 +393,7 @@ class BesService { | ||||
|   clearCorrectionPanel() { | ||||
|     this.correctionPanel.remove() | ||||
|     this.scrollPanel.remove() | ||||
|     this.canvasPanel.remove() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
| @@ -465,8 +413,16 @@ class BesService { | ||||
|     this.scrollPanel.style.height = `${this.hostElement.scrollHeight}px` | ||||
|     this.canvasPanel.style.width = `${this.hostElement.scrollWidth}px` | ||||
|     this.canvasPanel.style.height = `${this.hostElement.scrollHeight}px` | ||||
|     this.ctx = this.canvasPanel.getContext('2d') | ||||
|     this.setCanvasDpr() | ||||
|     const dpr = window.devicePixelRatio | ||||
|     const canvasPanelRect = this.canvasPanel.getBoundingClientRect() | ||||
|     if ( | ||||
|       this.canvasPanel.width !== canvasPanelRect.width * dpr || | ||||
|       this.canvasPanel.height !== canvasPanelRect.height * dpr | ||||
|     ) { | ||||
|       this.canvasPanel.width = canvasPanelRect.width * dpr | ||||
|       this.canvasPanel.height = canvasPanelRect.height * dpr | ||||
|       this.repositionAllMarkup() | ||||
|     } | ||||
|     if (this.isHostElementInline()) { | ||||
|       const totalWidth = | ||||
|         parseFloat(styles.paddingLeft) + | ||||
| @@ -482,21 +438,6 @@ class BesService { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Sets canvas panel device pixel ratio. | ||||
|    */ | ||||
|   setCanvasDpr() { | ||||
|     const dpr = window.devicePixelRatio || 1 | ||||
|     const canvasPanelRect = this.canvasPanel.getBoundingClientRect() | ||||
|     this.canvasPanel.width = canvasPanelRect.width * dpr | ||||
|     this.canvasPanel.height = canvasPanelRect.height * dpr | ||||
|     this.ctx.scale(dpr, dpr) | ||||
|     if (!this.ctx) { | ||||
|       this.ctx = this.canvasPanel.getContext('2d') | ||||
|     } | ||||
|     this.ctx.scale(dpr, dpr) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Displays correction panel. | ||||
|    * | ||||
| @@ -544,16 +485,16 @@ class BesService { | ||||
|    * Updates all grammar mistake markup positions. | ||||
|    */ | ||||
|   repositionAllMarkup() { | ||||
|     const dpr = window.devicePixelRatio | ||||
|     this.ctx.clearRect( | ||||
|       0, | ||||
|       0, | ||||
|       this.canvasPanel.width * dpr, | ||||
|       this.canvasPanel.height * dpr | ||||
|     ) | ||||
|     this.results.forEach(result => { | ||||
|       result.matches.forEach(match => { | ||||
|         if (match.highlights) { | ||||
|           match.highlights.forEach(h => { | ||||
|             this.ctx.clearRect(h.x - 2, h.y - 2, h.width + 4, h.height) | ||||
|           }) | ||||
|  | ||||
|           delete match.highlights | ||||
|           // match.highlights.forEach(h => h.remove()) | ||||
|         } | ||||
|         if (match.highlights) delete match.highlights | ||||
|         match.highlights = this.addMistakeMarkup( | ||||
|           match.range, | ||||
|           match.match.rule.id | ||||
| @@ -812,22 +753,22 @@ class BesTreeService extends BesService { | ||||
|    * @param {Element} el DOM element we want to clean markup for | ||||
|    */ | ||||
|   clearMarkup(el) { | ||||
|     const dpr = window.devicePixelRatio | ||||
|     this.results | ||||
|       .filter(result => BesTreeService.isSameParagraph(result.element, el)) | ||||
|       .forEach(result => | ||||
|         result.matches.forEach(match => { | ||||
|           console.log(match) | ||||
|           if (match.highlights) { | ||||
|             // match.highlights.forEach(h => h.remove()) | ||||
|             match.highlights.forEach(h => { | ||||
|               console.log(h) | ||||
|               // Figure out why i need to add 2px to width | ||||
|               this.ctx.clearRect(h.x - 2, h.y - 2, h.width + 4, h.height) | ||||
|             }) | ||||
|             delete match.highlights | ||||
|           } | ||||
|         }) | ||||
|       ) | ||||
|       .forEach(result => { | ||||
|         let sourceRect = result.element.getBoundingClientRect() | ||||
|         let targetRect = this.canvasPanel.getBoundingClientRect() | ||||
|         let newX = sourceRect.left - targetRect.left | ||||
|         let newY = sourceRect.top - targetRect.top | ||||
|         this.ctx.clearRect( | ||||
|           newX * dpr, | ||||
|           newY * dpr, | ||||
|           sourceRect.width * dpr, | ||||
|           sourceRect.height * dpr | ||||
|         ) | ||||
|         delete result.matches | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
| @@ -967,14 +908,7 @@ class BesTreeService extends BesService { | ||||
|     for (let result of this.results) { | ||||
|       for (let m of result.matches) { | ||||
|         for (let h of m.highlights) { | ||||
|           if ( | ||||
|             BesService.isPointInRect( | ||||
|               source.clientX, | ||||
|               source.clientY, | ||||
|               h, | ||||
|               this.canvasPanel | ||||
|             ) | ||||
|           ) { | ||||
|           if (BesService.isPointInRect(source.clientX, source.clientY, h)) { | ||||
|             this.popupCorrectionPanel(el, m, source) | ||||
|             return | ||||
|           } | ||||
| @@ -1647,13 +1581,7 @@ class BesPlainTextService extends BesService { | ||||
|     for (let result of this.results) { | ||||
|       for (let m of result.matches) { | ||||
|         for (let h of m.highlights) { | ||||
|           if ( | ||||
|             BesService.isPointInRect( | ||||
|               source.clientX, | ||||
|               source.clientY, | ||||
|               h.getBoundingClientRect() | ||||
|             ) | ||||
|           ) { | ||||
|           if (BesService.isPointInRect(source.clientX, source.clientY, h)) { | ||||
|             this.popupCorrectionPanel(result.range, m, source) | ||||
|             return | ||||
|           } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|   cursor: text; | ||||
| } | ||||
|  | ||||
| /* TODO: Cleanup */ | ||||
| .bes-grammar-mistake { | ||||
|   border-bottom: 2px solid #007bff; | ||||
|   position: absolute; | ||||
| @@ -21,11 +22,13 @@ | ||||
|   cursor: text; | ||||
| } | ||||
|  | ||||
| /* TODO: Cleanup */ | ||||
| .bes-spelling-mistake.bes-mistake-highlight-selected { | ||||
|   background: #cc7024; | ||||
|   opacity: 0.5; | ||||
| } | ||||
|  | ||||
| /* TODO: Cleanup */ | ||||
| .bes-grammar-mistake.bes-mistake-highlight-selected { | ||||
|   background: #3691f3; | ||||
|   opacity: 0.5; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user