Enhancement: Eyedropper (#948)
* cursor helper * shortcuts * Helper styling * linter fix * dasharray param fixmaster
parent
9f77e9c63a
commit
77b7bd95b7
|
@ -780,7 +780,7 @@ class EditorStartup {
|
|||
cancelTool () {
|
||||
const mode = this.svgCanvas.getMode()
|
||||
// list of modes that are currently save to cancel
|
||||
const modesToCancel = ['zoom', 'rect', 'square', 'circle', 'ellipse', 'line', 'text', 'star', 'polygon', 'eyedropper', 'shapelib', 'image']
|
||||
const modesToCancel = ['zoom', 'rect', 'square', 'circle', 'ellipse', 'line', 'text', 'star', 'polygon', 'shapelib', 'image']
|
||||
if (modesToCancel.includes(mode)) {
|
||||
this.leftPanel.clickSelect()
|
||||
}
|
||||
|
|
|
@ -31,37 +31,57 @@ export default {
|
|||
const { ChangeElementCommand } = svgCanvas.history
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
const addToHistory = (cmd) => { svgCanvas.undoMgr.addCommandToHistory(cmd) }
|
||||
const currentStyle = {
|
||||
fillPaint: 'red',
|
||||
fillOpacity: 1.0,
|
||||
strokePaint: 'black',
|
||||
strokeOpacity: 1.0,
|
||||
strokeWidth: 5,
|
||||
strokeDashArray: null,
|
||||
opacity: 1.0,
|
||||
strokeLinecap: 'butt',
|
||||
strokeLinejoin: 'miter'
|
||||
}
|
||||
const currentStyle = {}
|
||||
const { $id, $click } = svgCanvas
|
||||
|
||||
// Helper to show what style is currectly picked
|
||||
const helperCursor = document.createElement('div')
|
||||
helperCursor.style.width = '14px'
|
||||
helperCursor.style.height = '14px'
|
||||
helperCursor.style.position = 'absolute'
|
||||
svgEditor.workarea.appendChild(helperCursor)
|
||||
|
||||
const styleHelper = () => {
|
||||
const mode = svgCanvas.getMode()
|
||||
|
||||
if (mode === name) {
|
||||
helperCursor.style.display = 'block'
|
||||
|
||||
const strokeWidthNum = Number(currentStyle.strokeWidth)
|
||||
const borderStyle = currentStyle.strokeDashArray === 'none' || !currentStyle.strokeDashArray ? 'solid' : 'dotted'
|
||||
|
||||
helperCursor.style.background = currentStyle.fillPaint ?? 'transparent'
|
||||
helperCursor.style.opacity = currentStyle.opacity ?? 1
|
||||
helperCursor.style.border = (strokeWidthNum > 0 && currentStyle.strokePaint) ? `2px ${borderStyle} ${currentStyle.strokePaint}` : 'none'
|
||||
}
|
||||
}
|
||||
|
||||
const resetCurrentStyle = () => {
|
||||
const keys = Object.keys(currentStyle)
|
||||
|
||||
keys.forEach(key => delete currentStyle[key])
|
||||
}
|
||||
|
||||
const cancelHandler = () => {
|
||||
if (Object.keys(currentStyle).length > 0) {
|
||||
resetCurrentStyle()
|
||||
styleHelper()
|
||||
} else {
|
||||
svgEditor.leftPanel.clickSelect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementChanged} opts
|
||||
* @returns {void}
|
||||
*/
|
||||
const getStyle = (opts) => {
|
||||
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
|
||||
const mode = svgCanvas.getMode()
|
||||
if (mode === 'eyedropper') { return }
|
||||
|
||||
const tool = $id('tool_eyedropper')
|
||||
// enable-eye-dropper if one element is selected
|
||||
let elem = null
|
||||
if (!opts.multiselected && opts.elems[0] &&
|
||||
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
|
||||
) {
|
||||
elem = opts.elems[0]
|
||||
tool.classList.remove('disabled')
|
||||
// grab the current style
|
||||
currentStyle.fillPaint = elem.getAttribute('fill') || 'black'
|
||||
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0
|
||||
|
@ -72,9 +92,6 @@ export default {
|
|||
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap')
|
||||
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin')
|
||||
currentStyle.opacity = elem.getAttribute('opacity') || 1.0
|
||||
// disable eye-dropper tool
|
||||
} else {
|
||||
tool.classList.add('disabled')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,29 +100,65 @@ export default {
|
|||
callback () {
|
||||
// Add the button and its handler(s)
|
||||
const title = `${name}:buttons.0.title`
|
||||
// #TODO: Come up with another shortcut (?) because 'I' is reserved for italic
|
||||
const key = `${name}:buttons.0.key`
|
||||
// const key = `${name}:buttons.0.key`
|
||||
const key = 'ctrl+I'
|
||||
const buttonTemplate = `
|
||||
<se-button id="tool_eyedropper" title="${title}" src="eye_dropper.svg" shortcut=${key}></se-button>
|
||||
`
|
||||
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 12)
|
||||
$click($id('tool_eyedropper'), () => {
|
||||
if (this.leftPanel.updateLeftPanel('tool_eyedropper')) {
|
||||
svgCanvas.setMode('eyedropper')
|
||||
svgCanvas.setMode(name)
|
||||
}
|
||||
})
|
||||
|
||||
// enables helper, resets currently picked style if no element selected
|
||||
document.addEventListener('modeChange', e => {
|
||||
if (svgCanvas.getMode() === name) {
|
||||
styleHelper()
|
||||
} else {
|
||||
helperCursor.style.display = 'none'
|
||||
}
|
||||
if (svgCanvas.getSelectedElements().length === 0) {
|
||||
resetCurrentStyle()
|
||||
}
|
||||
})
|
||||
|
||||
// Positions helper
|
||||
svgEditor.workarea.addEventListener('mousemove', (e) => {
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
|
||||
if (svgCanvas.getMode() === name) {
|
||||
helperCursor.style.top = y + 'px'
|
||||
helperCursor.style.left = x + 12 + 'px'
|
||||
styleHelper()
|
||||
}
|
||||
})
|
||||
|
||||
svgEditor.workarea.addEventListener('mouseleave', e => {
|
||||
helperCursor.style.display = 'none'
|
||||
})
|
||||
|
||||
// Listens to Esc to reset currently picked style / set Select mode
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key === 'Escape' && svgCanvas.getMode() === name) {
|
||||
cancelHandler()
|
||||
}
|
||||
})
|
||||
},
|
||||
// if we have selected an element, grab its paint and enable the eye dropper button
|
||||
selectedChanged: getStyle,
|
||||
elementChanged: getStyle,
|
||||
mouseDown (opts) {
|
||||
const mode = svgCanvas.getMode()
|
||||
if (mode === 'eyedropper') {
|
||||
if (mode === name) {
|
||||
const e = opts.event
|
||||
const { target } = e
|
||||
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
|
||||
const changes = {}
|
||||
|
||||
// If some style is picked - applies it to the target, if no style - picks it from the target
|
||||
if (Object.keys(currentStyle).length > 0) {
|
||||
const change = function (elem, attrname, newvalue) {
|
||||
changes[attrname] = elem.getAttribute(attrname)
|
||||
elem.setAttribute(attrname, newvalue)
|
||||
|
@ -116,12 +169,20 @@ export default {
|
|||
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint) }
|
||||
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity) }
|
||||
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth) }
|
||||
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray) }
|
||||
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity) }
|
||||
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap) }
|
||||
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin) }
|
||||
|
||||
if (currentStyle.strokeDashArray) {
|
||||
change(target, 'stroke-dasharray', currentStyle.strokeDashArray)
|
||||
} else {
|
||||
target.removeAttribute('stroke-dasharray')
|
||||
}
|
||||
|
||||
addToHistory(new ChangeElementCommand(target, changes))
|
||||
} else {
|
||||
getStyle({ elems: [target] })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue