Skip to content

Commit

Permalink
#283 - Resize span
Browse files Browse the repository at this point in the history
- Imrprove handling of resizing across different browsers. Chrome works best. Firefox and Safari have nasty quirks that we try to work around.
  • Loading branch information
reckart committed Jan 10, 2023
1 parent 318c629 commit 689e7c9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<script lang="ts">
import { caretRangeFromPoint } from '@inception-project/inception-js-api'
import { createEventDispatcher, onMount } from 'svelte'
import { closestChunk } from '../visualizer/Visualizer'
import { findClosestChunkElement } from '../visualizer/Visualizer'
export let highlight: Element = undefined
export let position: 'begin' | 'end'
Expand Down Expand Up @@ -102,23 +102,52 @@
return
}
console.log(`clientX: ${event.clientX}, clientY: ${event.clientY}`)
const range = caretRangeFromPoint(event.clientX, event.clientY)
if (!range || !closestChunk(range.startContainer)) {
const chunk = findClosestChunkElement(range.startContainer)
console.log(chunk)
if (!range || !chunk) {
markerVisibility = 'hidden'
return
}
const rect = range.getBoundingClientRect()
const scrollerContainerRect = scrollContainer.getBoundingClientRect()
const rect = range.getBoundingClientRect()
// In Safari and Firefox, the bounding rect of the caret rect is completely broken and we need
// to fix it up. We can detect if the caret rect is broken by checking if the caret rect is
// withing the rect of the container element of the range (which should always be true!).
let container = range.commonAncestorContainer instanceof Element ? range.commonAncestorContainer : range.commonAncestorContainer.parentElement
const containerRect = container.getBoundingClientRect()
const isRectConsistent = containerRect.left <= rect.x && rect.x <= containerRect.right
&& containerRect.top <= rect.y && rect.y <= containerRect.bottom
if (!isRectConsistent) {
rect.x = rect.x - scrollerContainerRect.left + containerRect.left
rect.y = rect.y - scrollerContainerRect.top + containerRect.top
// Firefox has the additional problem that the caret rect always snaps to the begin of the
// ancestor range, so we need to adjust the rect to the actual caret position based on the
// offset within the container. This is a very rough approximation...
const avgGlyphWidth = containerRect.width / container.textContent.length
const isRtl = container.closest('svg[direction="rtl"]') !== null
const tolerance = 5
const expectedX = isRtl ?
containerRect.right - (avgGlyphWidth * range.startOffset) :
containerRect.left + (avgGlyphWidth * range.startOffset)
if (Math.abs(rect.x - expectedX) > tolerance) {
rect.x = expectedX
}
}
markerX = rect.left + scrollContainer.scrollLeft - scrollerContainerRect.left
markerY = rect.top + scrollContainer.scrollTop - scrollerContainerRect.top
markerHeight = rect.height
markerHeight = rect.height || containerRect.height // Firefox does not return a height for the caret rect
markerVisibility = 'visible'
}
function handleDragEnd(event: MouseEvent) {
console.log("handleDragEnd")
// Prevent the drag-end from turning into a mouse-up event which would trigger a selection
// of the annotation
event.stopPropagation()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ import { Box, Svg, SVGTypeMapping, Point } from '@svgdotjs/svg.js'
import { DocumentData } from '../visualizer/DocumentData'
import { INSTANCE as Configuration } from '../configuration/Configuration'
import { INSTANCE as Util } from '../util/Util'
import { DiamAjax, Offsets } from '@inception-project/inception-js-api'
import { DiamAjax } from '@inception-project/inception-js-api'
import { EntityTypeDto, VID } from '../protocol/Protocol'
import { closestChunk, Visualizer } from '../visualizer/Visualizer'
import { timeStamp } from 'console'
import { findClosestChunkElement, Visualizer } from '../visualizer/Visualizer'

export class AnnotatorUI {
private data: DocumentData
Expand Down Expand Up @@ -363,8 +362,8 @@ export class AnnotatorUI {

// let chunkIndexFrom = sel.anchorNode && $(sel.anchorNode.parentNode).attr('data-chunk-id')
// let chunkIndexTo = sel.focusNode && $(sel.focusNode.parentNode).attr('data-chunk-id')
let chunkIndexFrom = closestChunk(sel.anchorNode)?.getAttribute('data-chunk-id')
let chunkIndexTo = closestChunk(sel.focusNode)?.getAttribute('data-chunk-id')
let chunkIndexFrom = findClosestChunkElement(sel.anchorNode)?.getAttribute('data-chunk-id')
let chunkIndexTo = findClosestChunkElement(sel.focusNode)?.getAttribute('data-chunk-id')
// fallback for firefox (at least):
// it's unclear why, but for firefox the anchor and focus node parents are always undefined,
// the the anchor and focus nodes themselves do (often) have the necessary chunk ID. However,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4111,9 +4111,9 @@ export class Visualizer {
rangeToOffsets (range: Range | null) : Offsets | null {
if (!range || !this.data) return null

let anchorNode = closestChunk(range.startContainer)
let anchorNode = findClosestChunkElement(range.startContainer)
let anchorOffset = range.startOffset
let focusNode = closestChunk(range.endContainer)
let focusNode = findClosestChunkElement(range.endContainer)
let focusOffset = range.endOffset

// If neither approach worked, give up - the user didn't click on selectable text.
Expand Down Expand Up @@ -4195,13 +4195,13 @@ export class Visualizer {
* @param target a DOM node.
* @returns the closest highlight element or null if none is found.
*/
export function closestChunk (target: Node | null): Element | null {
export function findClosestChunkElement (target: Node | null): Element | null {
if (target instanceof Text) {
target = target.parentElement
}

if (target instanceof Element) {
return target.closest('[data-chunk-id]')
return target.closest(':not(.spacing)[data-chunk-id]')
}

return null
Expand Down

0 comments on commit 689e7c9

Please sign in to comment.