Fine-tune markup drawing

This adjusts markup color slightly for the dark display, makes it fully
opaque, alternates the squiggly line between grammar and spelling
mistakes to visualize one-word-two-mistake-types, paints most important
mistakes last/on top etc.

All to make the markup as visible as possible.
This commit is contained in:
Simon Rozman 2025-03-04 11:09:57 +01:00
parent ef0d35ccee
commit c27f9628f4
7 changed files with 63 additions and 30 deletions

View File

@ -91,8 +91,8 @@ Kategorije pravopisnih pravil so:
Privzeto servis uporablja podčrtovanje pravopisnih napak (nastavitev `'underline'`). Videz lahko spreminjamo. Privzeto servis uporablja podčrtovanje pravopisnih napak (nastavitev `'underline'`). Videz lahko spreminjamo.
<img src="samples/markup_underline.png" alt="underline" width="448"/> <img src="samples/images/markup_underline.png" alt="underline" width="448"/>
<img src="samples/markup_lector.png" alt="lector" width="448"/> <img src="samples/images/markup_lector.png" alt="lector" width="448"/>
Levo `'underline'`, desno `'lector'`. Levo `'underline'`, desno `'lector'`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View File

@ -371,13 +371,19 @@ class BesService {
if (match.highlights.length === 0) return if (match.highlights.length === 0) return
const dpr = window.devicePixelRatio const dpr = window.devicePixelRatio
this.ctx.lineWidth = 2 * dpr // Use 2 for clearer visibility this.ctx.lineWidth = 2 * dpr // Use 2 for clearer visibility
let amplitude = 0
const ruleId = match.match.rule.id const ruleId = match.match.rule.id
this.ctx.strokeStyle = ruleId.startsWith('MORFOLOGIK_RULE') if (ruleId.startsWith('MORFOLOGIK_RULE')) {
? 'rgba(0, 123, 255, 0.8)' const styles = window.getComputedStyle(this.highlightSpelling)
: 'rgba(255, 115, 0, 0.8)' this.ctx.strokeStyle = styles.color
this.ctx.fillStyle = ruleId.startsWith('MORFOLOGIK_RULE') this.ctx.fillStyle = styles.color
? 'rgba(0, 123, 255, 0.8)' amplitude = -1
: 'rgba(255, 115, 0, 0.8)' } else {
const styles = window.getComputedStyle(this.highlightGrammar)
this.ctx.strokeStyle = styles.color
this.ctx.fillStyle = styles.color
amplitude = 1
}
let markerY1, markerY2 let markerY1, markerY2
switch (this.markupStyle) { switch (this.markupStyle) {
case 'lector': case 'lector':
@ -681,7 +687,7 @@ class BesService {
const x2 = rect.right const x2 = rect.right
const y = rect.bottom const y = rect.bottom
const scale = (rect.bottom - rect.top) / 18 const scale = (rect.bottom - rect.top) / 18
this.drawAttentionRequired(x1, x2, y, scale) this.drawAttentionRequired(x1, x2, y, amplitude, scale)
} }
markerY1 = Math.min(...match.highlights.map(rect => rect.top)) markerY1 = Math.min(...match.highlights.map(rect => rect.top))
@ -865,17 +871,18 @@ class BesService {
* @param {Number} x1 Sign left [px] * @param {Number} x1 Sign left [px]
* @param {Number} x2 Sign right [px] * @param {Number} x2 Sign right [px]
* @param {Number} y Sign baseline [px] * @param {Number} y Sign baseline [px]
* @param {Number} amplitude Sign amplitude [px]
* @param {Number} scale Sign scale * @param {Number} scale Sign scale
*/ */
drawAttentionRequired(x1, x2, y, scale) { drawAttentionRequired(x1, x2, y, amplitude, scale) {
const dpr = window.devicePixelRatio const dpr = window.devicePixelRatio
this.ctx.beginPath() this.ctx.beginPath()
this.ctx.moveTo(x1 * dpr, (y - scale) * dpr) this.ctx.moveTo(x1 * dpr, (y - amplitude * scale) * dpr)
for (let x = x1; ; ) { for (let x = x1; ; ) {
if (x >= x2) break if (x >= x2) break
this.ctx.lineTo((x += 2 * scale) * dpr, (y + scale) * dpr) this.ctx.lineTo((x += 2 * scale) * dpr, (y + amplitude * scale) * dpr)
if (x >= x2) break if (x >= x2) break
this.ctx.lineTo((x += 2 * scale) * dpr, (y - scale) * dpr) this.ctx.lineTo((x += 2 * scale) * dpr, (y - amplitude * scale) * dpr)
} }
this.ctx.stroke() this.ctx.stroke()
} }
@ -972,7 +979,16 @@ class BesService {
this.ctx = this.canvasPanel.getContext('2d') this.ctx = this.canvasPanel.getContext('2d')
this.ctx.scale(1, 1) this.ctx.scale(1, 1)
this.highlightSpelling = document.createElement('div')
this.highlightSpelling.classList.add('bes-highlight-placeholder')
this.highlightSpelling.classList.add('bes-highlight-spelling')
this.highlightGrammar = document.createElement('div')
this.highlightGrammar.classList.add('bes-highlight-placeholder')
this.highlightGrammar.classList.add('bes-highlight-grammar')
this.correctionPanel.appendChild(this.scrollPanel) this.correctionPanel.appendChild(this.scrollPanel)
this.correctionPanel.appendChild(this.highlightSpelling)
this.correctionPanel.appendChild(this.highlightGrammar)
this.scrollPanel.appendChild(this.canvasPanel) this.scrollPanel.appendChild(this.canvasPanel)
this.textElement.parentElement.insertBefore( this.textElement.parentElement.insertBefore(
this.correctionPanel, this.correctionPanel,
@ -1066,8 +1082,8 @@ class BesService {
el.classList.add('bes-highlight-rect') el.classList.add('bes-highlight-rect')
el.classList.add( el.classList.add(
match.match.rule.id.startsWith('MORFOLOGIK_RULE') match.match.rule.id.startsWith('MORFOLOGIK_RULE')
? 'bes-highlight-spelling-rect' ? 'bes-highlight-spelling'
: 'bes-highlight-grammar-rect' : 'bes-highlight-grammar'
) )
el.style.left = `${rect.x + canvasPanelRect.x + window.scrollX}px` el.style.left = `${rect.x + canvasPanelRect.x + window.scrollX}px`
el.style.top = `${rect.y + canvasPanelRect.y + window.scrollY}px` el.style.top = `${rect.y + canvasPanelRect.y + window.scrollY}px`
@ -1107,7 +1123,9 @@ class BesService {
redrawAllMistakeMarkup() { redrawAllMistakeMarkup() {
this.ctx.clearRect(0, 0, this.canvasPanel.width, this.canvasPanel.height) this.ctx.clearRect(0, 0, this.canvasPanel.width, this.canvasPanel.height)
this.results.forEach(result => { this.results.forEach(result => {
result.matches.forEach(match => this.drawMistakeMarkup(match)) // Most important matches are first, we want to draw them last => iterate in reverse.
for (let i = result.matches.length; i-- > 0; )
this.drawMistakeMarkup(result.matches[i])
}) })
} }
@ -1263,9 +1281,11 @@ class BesTreeService extends BesService {
), ),
match: match match: match
} }
this.drawMistakeMarkup(m)
matches.push(m) matches.push(m)
}) })
// Most important matches are first, we want to draw them last => iterate in reverse.
for (let i = matches.length; i-- > 0; )
this.drawMistakeMarkup(matches[i])
this.markProofed(node, matches) this.markProofed(node, matches)
this.onProofingProgress(matches.length) this.onProofingProgress(matches.length)
}) })
@ -2052,9 +2072,11 @@ class BesPlainTextService extends BesService {
), ),
match: match match: match
} }
this.drawMistakeMarkup(m)
matches.push(m) matches.push(m)
}) })
// Most important matches are first, we want to draw them last => iterate in reverse.
for (let i = matches.length; i-- > 0; )
this.drawMistakeMarkup(matches[i])
this.markProofed(paragraphRange, matches) this.markProofed(paragraphRange, matches)
this.onProofingProgress(matches.length) this.onProofingProgress(matches.length)
}) })

View File

@ -1,23 +1,29 @@
/* Mistake types styles */ /* Mistake types styles */
.bes-spelling-mistake {
border-bottom: 2px solid #ff7300;
position: absolute;
z-index: 3;
cursor: text;
}
.bes-highlight-rect { .bes-highlight-rect {
position: absolute; position: absolute;
opacity: 0.3;
cursor: text; cursor: text;
} }
.bes-highlight-spelling-rect { .bes-highlight-spelling {
background: rgb(0, 123, 255); color: hsl(211, 100%, 60%);
background: hsla(211, 100%, 60%, 0.3);
} }
.bes-highlight-grammar-rect { .bes-highlight-grammar {
background: rgb(255, 115, 0); color: hsl(27, 100%, 45%);
background: hsla(27, 100%, 45%, 0.3);
}
@media (prefers-color-scheme: dark) {
.bes-highlight-spelling {
color: hsl(211, 100%, 55%);
background: hsla(211, 100%, 55%, 0.3);
}
.bes-highlight-grammar {
color: hsl(27, 100%, 65%);
background: hsla(27, 100%, 65%, 0.3);
}
} }
/* Styles required to ensure full functionality and optimal user experience. */ /* Styles required to ensure full functionality and optimal user experience. */
@ -54,3 +60,8 @@
background: none; background: none;
z-index: -1; z-index: -1;
} }
.bes-highlight-placeholder {
display: none;
visibility: hidden;
}