Enhancement: Eyedropper (#948)
* cursor helper * shortcuts * Helper styling * linter fix * dasharray param fixmaster
parent
9f77e9c63a
commit
77b7bd95b7
|
@ -780,7 +780,7 @@ class EditorStartup {
|
||||||
cancelTool () {
|
cancelTool () {
|
||||||
const mode = this.svgCanvas.getMode()
|
const mode = this.svgCanvas.getMode()
|
||||||
// list of modes that are currently save to cancel
|
// 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)) {
|
if (modesToCancel.includes(mode)) {
|
||||||
this.leftPanel.clickSelect()
|
this.leftPanel.clickSelect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,37 +31,57 @@ export default {
|
||||||
const { ChangeElementCommand } = svgCanvas.history
|
const { ChangeElementCommand } = svgCanvas.history
|
||||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||||
const addToHistory = (cmd) => { svgCanvas.undoMgr.addCommandToHistory(cmd) }
|
const addToHistory = (cmd) => { svgCanvas.undoMgr.addCommandToHistory(cmd) }
|
||||||
const currentStyle = {
|
const currentStyle = {}
|
||||||
fillPaint: 'red',
|
|
||||||
fillOpacity: 1.0,
|
|
||||||
strokePaint: 'black',
|
|
||||||
strokeOpacity: 1.0,
|
|
||||||
strokeWidth: 5,
|
|
||||||
strokeDashArray: null,
|
|
||||||
opacity: 1.0,
|
|
||||||
strokeLinecap: 'butt',
|
|
||||||
strokeLinejoin: 'miter'
|
|
||||||
}
|
|
||||||
const { $id, $click } = svgCanvas
|
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
|
* @param {module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementChanged} opts
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const getStyle = (opts) => {
|
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
|
let elem = null
|
||||||
if (!opts.multiselected && opts.elems[0] &&
|
if (!opts.multiselected && opts.elems[0] &&
|
||||||
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
|
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
|
||||||
) {
|
) {
|
||||||
elem = opts.elems[0]
|
elem = opts.elems[0]
|
||||||
tool.classList.remove('disabled')
|
|
||||||
// grab the current style
|
// grab the current style
|
||||||
currentStyle.fillPaint = elem.getAttribute('fill') || 'black'
|
currentStyle.fillPaint = elem.getAttribute('fill') || 'black'
|
||||||
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0
|
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0
|
||||||
|
@ -72,9 +92,6 @@ export default {
|
||||||
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap')
|
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap')
|
||||||
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin')
|
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin')
|
||||||
currentStyle.opacity = elem.getAttribute('opacity') || 1.0
|
currentStyle.opacity = elem.getAttribute('opacity') || 1.0
|
||||||
// disable eye-dropper tool
|
|
||||||
} else {
|
|
||||||
tool.classList.add('disabled')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,29 +100,65 @@ export default {
|
||||||
callback () {
|
callback () {
|
||||||
// Add the button and its handler(s)
|
// Add the button and its handler(s)
|
||||||
const title = `${name}:buttons.0.title`
|
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 = `
|
const buttonTemplate = `
|
||||||
<se-button id="tool_eyedropper" title="${title}" src="eye_dropper.svg" shortcut=${key}></se-button>
|
<se-button id="tool_eyedropper" title="${title}" src="eye_dropper.svg" shortcut=${key}></se-button>
|
||||||
`
|
`
|
||||||
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 12)
|
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 12)
|
||||||
$click($id('tool_eyedropper'), () => {
|
$click($id('tool_eyedropper'), () => {
|
||||||
if (this.leftPanel.updateLeftPanel('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
|
// if we have selected an element, grab its paint and enable the eye dropper button
|
||||||
selectedChanged: getStyle,
|
selectedChanged: getStyle,
|
||||||
elementChanged: getStyle,
|
|
||||||
mouseDown (opts) {
|
mouseDown (opts) {
|
||||||
const mode = svgCanvas.getMode()
|
const mode = svgCanvas.getMode()
|
||||||
if (mode === 'eyedropper') {
|
if (mode === name) {
|
||||||
const e = opts.event
|
const e = opts.event
|
||||||
const { target } = e
|
const { target } = e
|
||||||
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
|
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
|
||||||
const changes = {}
|
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) {
|
const change = function (elem, attrname, newvalue) {
|
||||||
changes[attrname] = elem.getAttribute(attrname)
|
changes[attrname] = elem.getAttribute(attrname)
|
||||||
elem.setAttribute(attrname, newvalue)
|
elem.setAttribute(attrname, newvalue)
|
||||||
|
@ -116,12 +169,20 @@ export default {
|
||||||
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint) }
|
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint) }
|
||||||
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity) }
|
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity) }
|
||||||
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth) }
|
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.opacity) { change(target, 'opacity', currentStyle.opacity) }
|
||||||
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap) }
|
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap) }
|
||||||
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin) }
|
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))
|
addToHistory(new ChangeElementCommand(target, changes))
|
||||||
|
} else {
|
||||||
|
getStyle({ elems: [target] })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue