diff --git a/.github/workflows/onpullrequest.yml b/.github/workflows/onpullrequest.yml
index b5572acc3..a9a7f4d1f 100644
--- a/.github/workflows/onpullrequest.yml
+++ b/.github/workflows/onpullrequest.yml
@@ -1,6 +1,9 @@
name: Node CI
on: [pull_request]
+# To be able to write in the PR, we need write permission.
+permissions:
+ pull-requests: write
jobs:
build:
diff --git a/src/editor/Editor.js b/src/editor/Editor.js
index cc314893b..17978aca7 100644
--- a/src/editor/Editor.js
+++ b/src/editor/Editor.js
@@ -71,49 +71,240 @@ class Editor extends EditorStartup {
this.docprops = false
this.configObj.preferences = false
this.canvMenu = null
- this.goodLangs = ['ar', 'cs', 'de', 'en', 'es', 'fa', 'fr', 'fy', 'hi', 'it', 'ja', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'zh-CN', 'zh-TW']
- const modKey = (isMac() ? 'meta+' : 'ctrl+')
+ this.goodLangs = [
+ 'ar',
+ 'cs',
+ 'de',
+ 'en',
+ 'es',
+ 'fa',
+ 'fr',
+ 'fy',
+ 'hi',
+ 'it',
+ 'ja',
+ 'nl',
+ 'pl',
+ 'pt-BR',
+ 'ro',
+ 'ru',
+ 'sk',
+ 'sl',
+ 'sv',
+ 'tr',
+ 'uk',
+ 'zh-CN',
+ 'zh-TW'
+ ]
+ const modKey = isMac() ? 'meta+' : 'ctrl+'
this.shortcuts = [
// Shortcuts not associated with buttons
- { key: 'ctrl+arrowleft', fn: () => { this.rotateSelected(0, 1) } },
- { key: 'ctrl+arrowright', fn: () => { this.rotateSelected(1, 1) } },
- { key: 'ctrl+shift+arrowleft', fn: () => { this.rotateSelected(0, 5) } },
- { key: 'ctrl+shift+arrowright', fn: () => { this.rotateSelected(1, 5) } },
- { key: 'shift+o', fn: () => { this.svgCanvas.cycleElement(0) } },
- { key: 'shift+p', fn: () => { this.svgCanvas.cycleElement(1) } },
- { key: 'tab', fn: () => { this.svgCanvas.cycleElement(0) } },
- { key: 'shift+tab', fn: () => { this.svgCanvas.cycleElement(1) } },
- { key: [modKey + 'arrowup', true], fn: () => { this.zoomImage(2) } },
- { key: [modKey + 'arrowdown', true], fn: () => { this.zoomImage(0.5) } },
- { key: [modKey + ']', true], fn: () => { this.moveUpDownSelected('Up') } },
- { key: [modKey + '[', true], fn: () => { this.moveUpDownSelected('Down') } },
- { key: ['arrowup', true], fn: () => { this.moveSelected(0, -1) } },
- { key: ['arrowdown', true], fn: () => { this.moveSelected(0, 1) } },
- { key: ['arrowleft', true], fn: () => { this.moveSelected(-1, 0) } },
- { key: ['arrowright', true], fn: () => { this.moveSelected(1, 0) } },
- { key: 'shift+arrowup', fn: () => { this.moveSelected(0, -10) } },
- { key: 'shift+arrowdown', fn: () => { this.moveSelected(0, 10) } },
- { key: 'shift+arrowleft', fn: () => { this.moveSelected(-10, 0) } },
- { key: 'shift+arrowright', fn: () => { this.moveSelected(10, 0) } },
- { key: ['alt+arrowup', true], fn: () => { this.svgCanvas.cloneSelectedElements(0, -1) } },
- { key: ['alt+arrowdown', true], fn: () => { this.svgCanvas.cloneSelectedElements(0, 1) } },
- { key: ['alt+arrowleft', true], fn: () => { this.svgCanvas.cloneSelectedElements(-1, 0) } },
- { key: ['alt+arrowright', true], fn: () => { this.svgCanvas.cloneSelectedElements(1, 0) } },
- { key: ['alt+shift+arrowup', true], fn: () => { this.svgCanvas.cloneSelectedElements(0, -10) } },
- { key: ['alt+shift+arrowdown', true], fn: () => { this.svgCanvas.cloneSelectedElements(0, 10) } },
- { key: ['alt+shift+arrowleft', true], fn: () => { this.svgCanvas.cloneSelectedElements(-10, 0) } },
- { key: ['alt+shift+arrowright', true], fn: () => { this.svgCanvas.cloneSelectedElements(10, 0) } },
+ {
+ key: ['ctrl+arrowleft', true],
+ fn: () => {
+ this.rotateSelected(0, 1)
+ }
+ },
+ {
+ key: 'ctrl+arrowright',
+ fn: () => {
+ this.rotateSelected(1, 1)
+ }
+ },
+ {
+ key: ['ctrl+shift+arrowleft', true],
+ fn: () => {
+ this.rotateSelected(0, 5)
+ }
+ },
+ {
+ key: 'ctrl+shift+arrowright',
+ fn: () => {
+ this.rotateSelected(1, 5)
+ }
+ },
+ {
+ key: 'shift+o',
+ fn: () => {
+ this.svgCanvas.cycleElement(0)
+ }
+ },
+ {
+ key: 'shift+p',
+ fn: () => {
+ this.svgCanvas.cycleElement(1)
+ }
+ },
+ {
+ key: 'tab',
+ fn: () => {
+ this.svgCanvas.cycleElement(0)
+ }
+ },
+ {
+ key: 'shift+tab',
+ fn: () => {
+ this.svgCanvas.cycleElement(1)
+ }
+ },
+ {
+ key: [modKey + 'arrowup', true],
+ fn: () => {
+ this.zoomImage(2)
+ }
+ },
+ {
+ key: [modKey + 'arrowdown', true],
+ fn: () => {
+ this.zoomImage(0.5)
+ }
+ },
+ {
+ key: [modKey + ']', true],
+ fn: () => {
+ this.moveUpDownSelected('Up')
+ }
+ },
+ {
+ key: [modKey + '[', true],
+ fn: () => {
+ this.moveUpDownSelected('Down')
+ }
+ },
+ {
+ key: ['arrowup', true],
+ fn: () => {
+ this.moveSelected(0, -1)
+ }
+ },
+ {
+ key: ['arrowdown', true],
+ fn: () => {
+ this.moveSelected(0, 1)
+ }
+ },
+ {
+ key: ['arrowleft', true],
+ fn: () => {
+ this.moveSelected(-1, 0)
+ }
+ },
+ {
+ key: ['arrowright', true],
+ fn: () => {
+ this.moveSelected(1, 0)
+ }
+ },
+ {
+ key: 'shift+arrowup',
+ fn: () => {
+ this.moveSelected(0, -10)
+ }
+ },
+ {
+ key: 'shift+arrowdown',
+ fn: () => {
+ this.moveSelected(0, 10)
+ }
+ },
+ {
+ key: 'shift+arrowleft',
+ fn: () => {
+ this.moveSelected(-10, 0)
+ }
+ },
+ {
+ key: 'shift+arrowright',
+ fn: () => {
+ this.moveSelected(10, 0)
+ }
+ },
+ {
+ key: ['alt+arrowup', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(0, -1)
+ }
+ },
+ {
+ key: ['alt+arrowdown', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(0, 1)
+ }
+ },
+ {
+ key: ['alt+arrowleft', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(-1, 0)
+ }
+ },
+ {
+ key: ['alt+arrowright', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(1, 0)
+ }
+ },
+ {
+ key: ['alt+shift+arrowup', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(0, -10)
+ }
+ },
+ {
+ key: ['alt+shift+arrowdown', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(0, 10)
+ }
+ },
+ {
+ key: ['alt+shift+arrowleft', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(-10, 0)
+ }
+ },
+ {
+ key: ['alt+shift+arrowright', true],
+ fn: () => {
+ this.svgCanvas.cloneSelectedElements(10, 0)
+ }
+ },
{
key: ['delete/backspace', true],
fn: () => {
- if (this.selectedElement || this.multiselected) { this.svgCanvas.deleteSelectedElements() }
+ if (this.selectedElement || this.multiselected) {
+ this.svgCanvas.deleteSelectedElements()
+ }
+ }
+ },
+ {
+ key: 'a',
+ fn: () => {
+ this.svgCanvas.selectAllInCurrentLayer()
+ }
+ },
+ {
+ key: [modKey + 'a', true],
+ fn: () => {
+ this.svgCanvas.selectAllInCurrentLayer()
}
},
- { key: 'a', fn: () => { this.svgCanvas.selectAllInCurrentLayer() } },
- { key: modKey + 'a', fn: () => { this.svgCanvas.selectAllInCurrentLayer() } },
- { key: modKey + 'x', fn: () => { this.cutSelected() } },
- { key: modKey + 'c', fn: () => { this.copySelected() } },
- { key: modKey + 'v', fn: () => { this.pasteInCenter() } }
+ {
+ key: modKey + 'x',
+ fn: () => {
+ this.cutSelected()
+ }
+ },
+ {
+ key: modKey + 'c',
+ fn: () => {
+ this.copySelected()
+ }
+ },
+ {
+ key: modKey + 'v',
+ fn: () => {
+ this.pasteInCenter()
+ }
+ }
]
this.leftPanel = new LeftPanel(this)
this.bottomPanel = new BottomPanel(this)
@@ -204,7 +395,7 @@ class Editor extends EditorStartup {
setAll () {
const keyHandler = {} // will contain the action for each pressed key
- this.shortcuts.forEach(shortcut => {
+ this.shortcuts.forEach((shortcut) => {
// Bind function to shortcut key
if (shortcut.key) {
// Set shortcut based on options
@@ -218,14 +409,14 @@ class Editor extends EditorStartup {
}
keyval = String(keyval)
const { fn } = shortcut
- keyval.split('/').forEach(key => {
+ keyval.split('/').forEach((key) => {
keyHandler[key] = { fn, pd }
})
}
return true
})
// register the keydown event
- document.addEventListener('keydown', e => {
+ document.addEventListener('keydown', (e) => {
// only track keyboard shortcuts for the body containing the SVG-Editor
if (e.target.nodeName !== 'BODY') return
// normalize key
@@ -282,7 +473,7 @@ class Editor extends EditorStartup {
* @returns {module:SVGthis.ToolButton}
*/
getButtonData (sel) {
- return Object.values(this.shortcuts).find(btn => {
+ return Object.values(this.shortcuts).find((btn) => {
return btn.sel === sel
})
}
@@ -350,7 +541,9 @@ class Editor extends EditorStartup {
const { workarea } = this
const cnvs = $id('svgcanvas')
- let w = parseFloat(getComputedStyle(workarea, null).width.replace('px', ''))
+ let w = parseFloat(
+ getComputedStyle(workarea, null).width.replace('px', '')
+ )
let h = parseFloat(
getComputedStyle(workarea, null).height.replace('px', '')
)
@@ -444,9 +637,8 @@ class Editor extends EditorStartup {
}
`
if (document.querySelectorAll('#wireframe_rules').length > 0) {
- document.querySelector(
- '#wireframe_rules'
- ).textContent = this.workarea.classList.contains('wireframe') ? rule : ''
+ document.querySelector('#wireframe_rules').textContent =
+ this.workarea.classList.contains('wireframe') ? rule : ''
}
}
@@ -538,7 +730,7 @@ class Editor extends EditorStartup {
this.leftPanel.clickSelect()
}
- elems.forEach(elem => {
+ elems.forEach((elem) => {
const isSvgElem = elem?.tagName === 'svg'
if (isSvgElem || this.svgCanvas.isLayer(elem)) {
this.layersPanel.populateLayers()
@@ -593,18 +785,14 @@ class Editor extends EditorStartup {
* @returns {void}
*/
afterClear (win) {
- this.svgCanvas.runExtensions(
- 'afterClear'
- )
+ this.svgCanvas.runExtensions('afterClear')
}
/**
* @returns {void}
*/
beforeClear (win) {
- this.svgCanvas.runExtensions(
- 'beforeClear'
- )
+ this.svgCanvas.runExtensions('beforeClear')
}
/**
@@ -1135,7 +1323,7 @@ class Editor extends EditorStartup {
return this.ready(() => {
return new Promise((resolve, reject) => {
fetch(url, { cache: cache ? 'force-cache' : 'no-cache' })
- .then(response => {
+ .then((response) => {
if (!response.ok) {
if (noAlert) {
reject(new Error('URLLoadFail'))
@@ -1146,16 +1334,18 @@ class Editor extends EditorStartup {
}
return response.text()
})
- .then(str => {
+ .then((str) => {
this.loadSvgString(str, { noAlert })
return str
})
- .catch(error => {
+ .catch((error) => {
if (noAlert) {
reject(new Error('URLLoadFail'))
return
}
- seAlert(this.i18next.t('notification.URLLoadFail') + ': \n' + error)
+ seAlert(
+ this.i18next.t('notification.URLLoadFail') + ': \n' + error
+ )
resolve()
})
})
diff --git a/src/editor/components/seColorPicker.js b/src/editor/components/seColorPicker.js
index 72b77d3db..8231be4e1 100644
--- a/src/editor/components/seColorPicker.js
+++ b/src/editor/components/seColorPicker.js
@@ -634,7 +634,7 @@ div.jGraduate_Slider img {
}
#color_picker {
z-index: 1000;
- top: 60%;
+ bottom: 0;
}
@@ -651,8 +651,8 @@ div.jGraduate_Slider img {
*/
export class SeColorPicker extends HTMLElement {
/**
- * @function constructor
- */
+ * @function constructor
+ */
constructor () {
super()
// create the shadowDom and insert the template
diff --git a/src/editor/components/sePalette.js b/src/editor/components/sePalette.js
index e7a63e092..5ab3def5d 100644
--- a/src/editor/components/sePalette.js
+++ b/src/editor/components/sePalette.js
@@ -2,16 +2,48 @@
/* eslint-disable max-len */
const palette = [
// Todo: Make into configuration item?
- 'none', '#000000', '#3f3f3f', '#7f7f7f', '#bfbfbf', '#ffffff',
- '#ff0000', '#ff7f00', '#ffff00', '#7fff00',
- '#00ff00', '#00ff7f', '#00ffff', '#007fff',
- '#0000ff', '#7f00ff', '#ff00ff', '#ff007f',
- '#7f0000', '#7f3f00', '#7f7f00', '#3f7f00',
- '#007f00', '#007f3f', '#007f7f', '#003f7f',
- '#00007f', '#3f007f', '#7f007f', '#7f003f',
- '#ffaaaa', '#ffd4aa', '#ffffaa', '#d4ffaa',
- '#aaffaa', '#aaffd4', '#aaffff', '#aad4ff',
- '#aaaaff', '#d4aaff', '#ffaaff', '#ffaad4'
+ 'none',
+ '#000000',
+ '#3f3f3f',
+ '#7f7f7f',
+ '#bfbfbf',
+ '#ffffff',
+ '#ff0000',
+ '#ff7f00',
+ '#ffff00',
+ '#7fff00',
+ '#00ff00',
+ '#00ff7f',
+ '#00ffff',
+ '#007fff',
+ '#0000ff',
+ '#7f00ff',
+ '#ff00ff',
+ '#ff007f',
+ '#7f0000',
+ '#7f3f00',
+ '#7f7f00',
+ '#3f7f00',
+ '#007f00',
+ '#007f3f',
+ '#007f7f',
+ '#003f7f',
+ '#00007f',
+ '#3f007f',
+ '#7f007f',
+ '#7f003f',
+ '#ffaaaa',
+ '#ffd4aa',
+ '#ffffaa',
+ '#d4ffaa',
+ '#aaffaa',
+ '#aaffd4',
+ '#aaffff',
+ '#aad4ff',
+ '#aaaaff',
+ '#d4aaff',
+ '#ffaaff',
+ '#ffaad4'
]
const template = document.createElement('template')
@@ -32,8 +64,9 @@ template.innerHTML = `
#js-se-palette {
float: left;
- width: 632px;
- height: 16px;
+ min-width: 30px;
+ height: 15px;
+ overflow: hidden;
}
div.palette_item {
@@ -45,12 +78,40 @@ template.innerHTML = `
div.palette_item:first-child {
background: white;
}
+
+ .palette_expand_btn {
+ background: none;
+ border: none;
+ width: 14px;
+ height: 14px;
+ font-size: 12px;
+ cursor: pointer;
+ user-select:none;
+ }
+
+ #palette_popup {
+ padding: 4px;
+ margin-left: 24px;
+ background: white;
+ min-width: 180px;
+ max-width: 360px;
+ min-height: 14px;
+ flex-wrap: wrap;
+ border-radius: 4px;
+
+ position: absolute;
+ bottom: 36px;
+ right: 30px;
+ }
+
+
+
`
/**
@@ -58,20 +119,38 @@ template.innerHTML = `
*/
export class SEPalette extends HTMLElement {
/**
- * @function constructor
- */
+ * @function constructor
+ */
constructor () {
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$strip = this._shadowRoot.querySelector('#js-se-palette')
+ this.expand_btn = this._shadowRoot.querySelector(
+ 'button.palette_expand_btn'
+ )
+ this.popUp = this._shadowRoot.getElementById('palette_popup')
+ svgEditor.$click(this.expand_btn, (e) => {
+ e.stopPropagation()
+ const { display } = this.popUp.style
+ if (display === 'none') {
+ this.showPopUp()
+ } else {
+ this.hidePopUp()
+ }
+ })
+ svgEditor.svgCanvas.container.addEventListener('click', () =>
+ this.hidePopUp()
+ )
+
palette.forEach((rgb) => {
const newDiv = document.createElement('div')
newDiv.classList.add('square')
if (rgb === 'none') {
const img = document.createElement('img')
- img.src = 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgY2xhc3M9InN2Z19pY29uIj48c3ZnIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNkNDAwMDAiIGlkPSJzdmdfOTAiIHkyPSIyNCIgeDI9IjI0IiB5MT0iMCIgeDE9IjAiLz4KICAgIDxsaW5lIGlkPSJzdmdfOTIiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q0MDAwMCIgeTI9IjI0IiB4Mj0iMCIgeTE9IjAiIHgxPSIyNCIvPgogIDwvc3ZnPjwvc3ZnPg=='
+ img.src =
+ 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgY2xhc3M9InN2Z19pY29uIj48c3ZnIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNkNDAwMDAiIGlkPSJzdmdfOTAiIHkyPSIyNCIgeDI9IjI0IiB5MT0iMCIgeDE9IjAiLz4KICAgIDxsaW5lIGlkPSJzdmdfOTIiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q0MDAwMCIgeTI9IjI0IiB4Mj0iMCIgeTE9IjAiIHgxPSIyNCIvPgogIDwvc3ZnPjwvc3ZnPg=='
img.style.width = '15px'
img.style.height = '15px'
newDiv.append(img)
@@ -79,19 +158,31 @@ export class SEPalette extends HTMLElement {
newDiv.style.backgroundColor = rgb
}
newDiv.dataset.rgb = rgb
- svgEditor.$click(newDiv, (evt) => {
+ const clickCb = (evt) => {
evt.preventDefault()
// shift key or right click for stroke
const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill'
let color = newDiv.dataset.rgb
// Webkit-based browsers returned 'initial' here for no stroke
- if (color === 'none' || color === 'transparent' || color === 'initial') {
+ if (
+ color === 'none' ||
+ color === 'transparent' ||
+ color === 'initial'
+ ) {
color = 'none'
}
- const paletteEvent = new CustomEvent('change', { detail: { picker, color }, bubbles: false })
+ const paletteEvent = new CustomEvent('change', {
+ detail: { picker, color },
+ bubbles: false
+ })
this.dispatchEvent(paletteEvent)
- })
+ }
+ svgEditor.$click(newDiv, clickCb)
this.$strip.append(newDiv)
+
+ const divDialog = newDiv.cloneNode(true)
+ svgEditor.$click(divDialog, clickCb)
+ this.popUp.append(divDialog)
})
}
@@ -131,7 +222,21 @@ export class SEPalette extends HTMLElement {
* @function connectedCallback
* @returns {void}
*/
- connectedCallback () {
+ connectedCallback () {}
+
+ /**
+ * Shows popUp window with the whole palette
+ */
+ showPopUp () {
+ this.popUp.style.display = 'flex'
+ this.expand_btn.textContent = '▲'
+ this.expand_btn.setAttribute('title', 'Hide palette window')
+ }
+
+ hidePopUp () {
+ this.popUp.style.display = 'none'
+ this.expand_btn.textContent = '▼'
+ this.expand_btn.setAttribute('title', 'Show palette window')
}
}
diff --git a/src/editor/panels/BottomPanel.js b/src/editor/panels/BottomPanel.js
index 7a4598330..e172a9fd1 100644
--- a/src/editor/panels/BottomPanel.js
+++ b/src/editor/panels/BottomPanel.js
@@ -8,12 +8,12 @@ const { $id } = SvgCanvas
* register actions for left panel
*/
/**
- * @type {module}
-*/
+ * @type {module}
+ */
class BottomPanel {
/**
* @param {PlainObject} editor svgedit handler
- */
+ */
constructor (editor) {
this.editor = editor
}
@@ -26,26 +26,30 @@ class BottomPanel {
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
get multiselected () {
return this.editor.multiselected
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
changeStrokeWidth (e) {
let val = e.target.value
- if (val === 0 && this.editor.selectedElement && ['line', 'polyline'].includes(this.editor.selectedElement.nodeName)) {
+ if (
+ val === 0 &&
+ this.editor.selectedElement &&
+ ['line', 'polyline'].includes(this.editor.selectedElement.nodeName)
+ ) {
val = 1
}
this.editor.svgCanvas.setStrokeWidth(val)
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
changeZoom (value) {
switch (value) {
case 'canvas':
@@ -54,34 +58,51 @@ class BottomPanel {
case 'content':
this.editor.zoomChanged(window, value)
break
- default:
- {
+ default: {
const zoomlevel = Number(value) > 0.1 ? Number(value) * 0.01 : 0.1
const zoom = this.editor.svgCanvas.getZoom()
const { workarea } = this.editor
- this.editor.zoomChanged(window, {
- width: 0,
- height: 0,
- // center pt of scroll position
- x: (workarea.scrollLeft + parseFloat(getComputedStyle(workarea, null).width.replace('px', '')) / 2) / zoom,
- y: (workarea.scrollTop + parseFloat(getComputedStyle(workarea, null).height.replace('px', '')) / 2) / zoom,
- zoom: zoomlevel
- }, true)
+ this.editor.zoomChanged(
+ window,
+ {
+ width: 0,
+ height: 0,
+ // center pt of scroll position
+ x:
+ (workarea.scrollLeft +
+ parseFloat(
+ getComputedStyle(workarea, null).width.replace('px', '')
+ ) /
+ 2) /
+ zoom,
+ y:
+ (workarea.scrollTop +
+ parseFloat(
+ getComputedStyle(workarea, null).height.replace('px', '')
+ ) /
+ 2) /
+ zoom,
+ zoom: zoomlevel
+ },
+ true
+ )
}
}
}
/**
- * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate
- * @returns {void}
- */
+ * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate
+ * @returns {void}
+ */
updateToolButtonState () {
- const bNoFill = (this.editor.svgCanvas.getColor('fill') === 'none')
- const bNoStroke = (this.editor.svgCanvas.getColor('stroke') === 'none')
+ const bNoFill = this.editor.svgCanvas.getColor('fill') === 'none'
+ const bNoStroke = this.editor.svgCanvas.getColor('stroke') === 'none'
const buttonsNeedingStroke = ['tool_fhpath', 'tool_line']
const buttonsNeedingFillAndStroke = [
- 'tools_rect', 'tools_ellipse',
- 'tool_text', 'tool_path'
+ 'tools_rect',
+ 'tools_ellipse',
+ 'tool_text',
+ 'tool_path'
]
if (bNoStroke) {
@@ -120,8 +141,8 @@ class BottomPanel {
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
handleColorPicker (type, evt) {
const { paint } = evt.detail
this.editor.svgCanvas.setPaint(type, paint)
@@ -129,44 +150,50 @@ class BottomPanel {
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
handleStrokeAttr (type, evt) {
this.editor.svgCanvas.setStrokeAttr(type, evt.detail.value)
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
handleOpacity (evt) {
const val = Number.parseInt(evt.currentTarget.value.split('%')[0])
this.editor.svgCanvas.setOpacity(val / 100)
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
handlePalette (e) {
e.preventDefault()
// shift key or right click for stroke
const { picker, color } = e.detail
// Webkit-based browsers returned 'initial' here for no stroke
- const paint = color === 'none' ? new jGraduate.Paint() : new jGraduate.Paint({ alpha: 100, solidColor: color.substr(1) })
+ const paint =
+ color === 'none'
+ ? new jGraduate.Paint()
+ : new jGraduate.Paint({ alpha: 100, solidColor: color.substr(1) })
if (picker === 'fill') {
$id('fill_color').setPaint(paint)
} else {
$id('stroke_color').setPaint(paint)
}
this.editor.svgCanvas.setColor(picker, color)
- if (color !== 'none' && this.editor.svgCanvas.getPaintOpacity(picker) !== 1) {
+ if (
+ color !== 'none' &&
+ this.editor.svgCanvas.getPaintOpacity(picker) !== 1
+ ) {
this.editor.svgCanvas.setPaintOpacity(picker, 1.0)
}
this.updateToolButtonState()
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
init () {
// register actions for Bottom panel
const template = document.createElement('template')
@@ -177,26 +204,56 @@ class BottomPanel {
$id('palette').addEventListener('change', this.handlePalette.bind(this))
$id('palette').init(i18next)
const { curConfig } = this.editor.configObj
- $id('fill_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initFill.color }))
- $id('stroke_color').setPaint(new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initStroke.color }))
- $id('zoom').addEventListener('change', (e) => this.changeZoom.bind(this)(e.detail.value))
- $id('stroke_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('stroke', evt))
- $id('fill_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('fill', evt))
- $id('stroke_width').addEventListener('change', this.changeStrokeWidth.bind(this))
- $id('stroke_style').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-dasharray', evt))
- $id('stroke_linejoin').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linejoin', evt))
- $id('stroke_linecap').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linecap', evt))
+ $id('fill_color').setPaint(
+ new jGraduate.Paint({ alpha: 100, solidColor: curConfig.initFill.color })
+ )
+ $id('stroke_color').setPaint(
+ new jGraduate.Paint({
+ alpha: 100,
+ solidColor: curConfig.initStroke.color
+ })
+ )
+ $id('zoom').addEventListener('change', (e) =>
+ this.changeZoom.bind(this)(e.detail.value)
+ )
+ $id('stroke_color').addEventListener('change', (evt) =>
+ this.handleColorPicker.bind(this)('stroke', evt)
+ )
+ $id('fill_color').addEventListener('change', (evt) =>
+ this.handleColorPicker.bind(this)('fill', evt)
+ )
+ $id('stroke_width').addEventListener(
+ 'change',
+ this.changeStrokeWidth.bind(this)
+ )
+ $id('stroke_style').addEventListener('change', (evt) =>
+ this.handleStrokeAttr.bind(this)('stroke-dasharray', evt)
+ )
+ $id('stroke_linejoin').addEventListener('change', (evt) =>
+ this.handleStrokeAttr.bind(this)('stroke-linejoin', evt)
+ )
+ $id('stroke_linecap').addEventListener('change', (evt) =>
+ this.handleStrokeAttr.bind(this)('stroke-linecap', evt)
+ )
$id('opacity').addEventListener('change', this.handleOpacity.bind(this))
$id('fill_color').init(i18next)
$id('stroke_color').init(i18next)
}
/**
- * @type {module}
- */
+ * @type {module}
+ */
updateColorpickers (apply) {
- $id('fill_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply)
- $id('stroke_color').update(this.editor.svgCanvas, this.editor.selectedElement, apply)
+ $id('fill_color').update(
+ this.editor.svgCanvas,
+ this.editor.selectedElement,
+ apply
+ )
+ $id('stroke_color').update(
+ this.editor.svgCanvas,
+ this.editor.selectedElement,
+ apply
+ )
}
}
diff --git a/src/editor/svgedit.css b/src/editor/svgedit.css
index 77b07ac14..8bf49bf28 100644
--- a/src/editor/svgedit.css
+++ b/src/editor/svgedit.css
@@ -323,14 +323,16 @@ hr {
#tools_bottom {
grid-area: bottom;
- overflow: auto;
+ overflow-x: auto;
+ overflow-y: hidden;
display: flex;
align-items: center;
scrollbar-width: thin; /* Firefox */
}
-#tools_bottom ::-webkit-scrollbar { /* Chrome, Edge, and Safari */
+#tools_bottom::-webkit-scrollbar { /* Chrome, Edge, and Safari */
width: 3px;
+ height: 3px;
}
#tools_bottom se-list, #tools_bottom se-select {
@@ -358,11 +360,11 @@ hr {
width: 3px;
}
-#tools_left::-webkit-scrollbar-track {
+#tools_left::-webkit-scrollbar-track, #tools_bottom::-webkit-scrollbar-track{
background: transparent;
}
-#tools_left::-webkit-scrollbar-thumb {
+#tools_left::-webkit-scrollbar-thumb, #tools_bottom::-webkit-scrollbar-thumb {
background-color:rgb(70, 70, 70);
}
@@ -530,6 +532,9 @@ input[type=text] {
#palette {
margin-left: auto;
+ margin-right: 16px;
+ display: flex;
+ align-items: center;
}
#stroke_expand {