|
|
|
|
@ -31,25 +31,21 @@ export const AnnotationEditorPlugin: React.FC<AnnotationEditorPluginProps> = ({ |
|
|
|
|
plotInstance.setSelect({ top: 0, left: 0, width: 0, height: 0 }); |
|
|
|
|
} |
|
|
|
|
setIsAddingAnnotation(false); |
|
|
|
|
}, [setSelection, , setIsAddingAnnotation, plotCtx]); |
|
|
|
|
}, [plotCtx]); |
|
|
|
|
|
|
|
|
|
useLayoutEffect(() => { |
|
|
|
|
let annotating = false; |
|
|
|
|
let isClick = false; |
|
|
|
|
|
|
|
|
|
const setSelect = (u: uPlot) => { |
|
|
|
|
if (annotating) { |
|
|
|
|
setIsAddingAnnotation(true); |
|
|
|
|
const min = u.posToVal(u.select.left, 'x'); |
|
|
|
|
const max = u.posToVal(u.select.left + u.select.width, 'x'); |
|
|
|
|
|
|
|
|
|
setSelection({ |
|
|
|
|
min, |
|
|
|
|
max, |
|
|
|
|
min: u.posToVal(u.select.left, 'x'), |
|
|
|
|
max: u.posToVal(u.select.left + u.select.width, 'x'), |
|
|
|
|
bbox: { |
|
|
|
|
left: u.select.left, |
|
|
|
|
top: 0, |
|
|
|
|
height: u.bbox.height / window.devicePixelRatio, |
|
|
|
|
height: u.select.height, |
|
|
|
|
width: u.select.width, |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|
@ -61,19 +57,17 @@ export const AnnotationEditorPlugin: React.FC<AnnotationEditorPluginProps> = ({ |
|
|
|
|
|
|
|
|
|
config.addHook('init', (u) => { |
|
|
|
|
// Wrap all setSelect hooks to prevent them from firing if user is annotating
|
|
|
|
|
const setSelectHooks = u.hooks['setSelect']; |
|
|
|
|
const setSelectHooks = u.hooks.setSelect; |
|
|
|
|
|
|
|
|
|
if (setSelectHooks) { |
|
|
|
|
for (let i = 0; i < setSelectHooks.length; i++) { |
|
|
|
|
const hook = setSelectHooks[i]; |
|
|
|
|
if (hook === setSelect) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setSelectHooks[i] = (...args) => { |
|
|
|
|
if (!annotating) { |
|
|
|
|
hook!(...args); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
if (hook !== setSelect) { |
|
|
|
|
setSelectHooks[i] = (...args) => { |
|
|
|
|
!annotating && hook!(...args); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
@ -81,40 +75,23 @@ export const AnnotationEditorPlugin: React.FC<AnnotationEditorPluginProps> = ({ |
|
|
|
|
config.setCursor({ |
|
|
|
|
bind: { |
|
|
|
|
mousedown: (u, targ, handler) => (e) => { |
|
|
|
|
if (e.button === 0) { |
|
|
|
|
handler(e); |
|
|
|
|
if (e.metaKey || e.ctrlKey) { |
|
|
|
|
isClick = true; |
|
|
|
|
annotating = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
}, |
|
|
|
|
mousemove: (u, targ, handler) => (e) => { |
|
|
|
|
if (e.button === 0) { |
|
|
|
|
handler(e); |
|
|
|
|
// handle cmd+drag
|
|
|
|
|
if (e.metaKey || e.ctrlKey) { |
|
|
|
|
isClick = false; |
|
|
|
|
annotating = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
annotating = e.button === 0 && (e.metaKey || e.ctrlKey); |
|
|
|
|
handler(e); |
|
|
|
|
return null; |
|
|
|
|
}, |
|
|
|
|
mouseup: (u, targ, handler) => (e) => { |
|
|
|
|
// handle cmd+click
|
|
|
|
|
if (isClick && u.cursor.left && e.button === 0 && (e.metaKey || e.ctrlKey)) { |
|
|
|
|
u.setSelect({ left: u.cursor.left, width: 0, top: 0, height: 0 }); |
|
|
|
|
annotating = true; |
|
|
|
|
// uPlot will not fire setSelect hooks for 0-width && 0-height selections
|
|
|
|
|
// so we force it to fire on single-point clicks by mutating left & height
|
|
|
|
|
if (annotating && u.select.width === 0) { |
|
|
|
|
u.select.left = u.cursor.left!; |
|
|
|
|
u.select.height = u.bbox.height / window.devicePixelRatio; |
|
|
|
|
} |
|
|
|
|
handler(e); |
|
|
|
|
return null; |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|
}, [config, setIsAddingAnnotation]); |
|
|
|
|
}, [config]); |
|
|
|
|
|
|
|
|
|
const startAnnotating = useCallback<StartAnnotatingFn>( |
|
|
|
|
({ coords }) => { |
|
|
|
|
@ -146,7 +123,7 @@ export const AnnotationEditorPlugin: React.FC<AnnotationEditorPluginProps> = ({ |
|
|
|
|
}); |
|
|
|
|
setIsAddingAnnotation(true); |
|
|
|
|
}, |
|
|
|
|
[plotCtx, setSelection, setIsAddingAnnotation] |
|
|
|
|
[plotCtx] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|