Add possibility to use upper layers as masks for lower ones

This commit is contained in:
Frederic Kettelhoit 2020-03-19 12:10:51 +01:00 committed by Atlas Cove
parent 7bf1686a34
commit a4236752ab
2 changed files with 72 additions and 10 deletions

View File

@ -13,14 +13,42 @@ function Manager (client) {
this.el.setAttribute('version', '1.1')
this.el.style.fill = 'none'
this.masks = []
this.layers = []
this.install = function () {
this.masks[0] = [this.maskBg()]
this.masks[1] = [this.maskBg(), document.createElementNS('http://www.w3.org/2000/svg', 'path')]
this.masks[2] = [
this.maskBg(),
document.createElementNS('http://www.w3.org/2000/svg', 'path'),
document.createElementNS('http://www.w3.org/2000/svg', 'path')
]
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')
this.el.appendChild(defs)
for (const id of [2, 1, 0]) {
const maskPath = document.createElementNS('http://www.w3.org/2000/svg', 'mask')
maskPath.setAttribute('id', 'mask' + id)
for (const mask of this.masks[id]) {
maskPath.appendChild(mask)
}
defs.appendChild(maskPath)
}
this.el.appendChild(this.layers[2] = document.createElementNS('http://www.w3.org/2000/svg', 'path'))
this.el.appendChild(this.layers[1] = document.createElementNS('http://www.w3.org/2000/svg', 'path'))
this.el.appendChild(this.layers[0] = document.createElementNS('http://www.w3.org/2000/svg', 'path'))
}
this.maskBg = function () {
const bg = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
bg.setAttribute('fill', 'white')
bg.setAttribute('width', '100%')
bg.setAttribute('height', '100%')
return bg
}
this.update = function () {
this.el.setAttribute('width', (client.tool.settings.size.width) + 'px')
this.el.setAttribute('height', (client.tool.settings.size.height) + 'px')
@ -29,19 +57,53 @@ function Manager (client) {
const styles = client.tool.styles
const paths = client.tool.paths()
const masked = styles.map((style) => style.mask)
const viewBox = this.minimalViewBox();
if (viewBox !== null) {
for (const id in this.masks) {
const [x, y, width, height] = viewBox
this.masks[id][0].setAttribute('x', x)
this.masks[id][0].setAttribute('y', y)
this.masks[id][0].setAttribute('width', width)
this.masks[id][0].setAttribute('height', height)
}
}
for (const id in this.layers) {
const style = styles[id]
const path = paths[id]
const layer = this.layers[id]
const nextLayer = parseInt(id) + 1
for (var i = nextLayer; i < 3; i++) {
const mask = this.masks[i][nextLayer]
if (style.mask) {
mask.setAttribute('d', path)
mask.style.strokeWidth = style.thickness
mask.style.strokeLinecap = style.strokeLinecap
mask.style.strokeLinejoin = style.strokeLinejoin
mask.style.stroke = style.color
mask.style.fill = style.fill
} else {
mask.setAttribute('d', '')
}
}
layer.style.strokeWidth = style.thickness
layer.style.strokeLinecap = style.strokeLinecap
layer.style.strokeLinejoin = style.strokeLinejoin
layer.style.stroke = style.color
layer.style.fill = style.fill
layer.setAttribute('d', path)
layer.setAttribute('d', style.mask ? '' : path)
const maskedAbove = masked.slice(0, id).some((mask) => mask === true)
const maskPath = !(style.mask) && maskedAbove ? 'url(#mask' + id + ')' : null
if (maskPath !== null) {
layer.setAttribute('mask', maskPath)
} else if (layer.hasAttribute('mask')) {
layer.removeAttribute('mask')
}
}
}
@ -75,9 +137,9 @@ function Manager (client) {
if (xMax === null || xMaxOfLayer > xMax) { xMax = xMaxOfLayer }
if (yMax === null || yMaxOfLayer > yMax) { yMax = yMaxOfLayer }
}
if (xMin === null || yMin === null || xMax === null || yMax === null) { return '' }
if (xMin === null || yMin === null || xMax === null || yMax === null) { return null }
return xMin + ' ' + yMin + ' ' + (xMax - xMin) + ' ' + (yMax - yMin)
return [xMin, yMin, xMax - xMin, yMax - yMin]
}
this.svg64 = function () {
@ -106,15 +168,15 @@ function Manager (client) {
this.toString = () => {
const viewBox = this.minimalViewBox();
if (viewBox !== '') {
this.el.setAttribute('width', viewBox.split(/ /)[2] + 'px')
if (viewBox !== null) {
this.el.setAttribute('width', viewBox[2] + 'px')
this.el.removeAttribute('height')
this.el.style.width = null
this.el.style.height = null
this.el.setAttribute('viewBox', this.minimalViewBox())
this.el.setAttribute('viewBox', viewBox.join(' '))
}
const serialized = new XMLSerializer().serializeToString(this.el)
if (viewBox !== '') {
if (viewBox !== null) {
this.el.setAttribute('width', (client.tool.settings.size.width) + 'px')
this.el.setAttribute('height', (client.tool.settings.size.height) + 'px')
this.el.style.width = client.tool.settings.size.width

View File

@ -7,9 +7,9 @@ function Tool (client) {
this.settings = { size: { width: 600, height: 300 } }
this.layers = [[], [], []]
this.styles = [
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#f00', fill: 'none', mirror_style: 0, transform: 'rotate(45)' },
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#0f0', fill: 'none', mirror_style: 0, transform: 'rotate(45)' },
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#00f', fill: 'none', mirror_style: 0, transform: 'rotate(45)' }
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#f00', fill: 'none', mask: false, mirror_style: 0, transform: 'rotate(45)' },
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#0f0', fill: 'none', mask: false, mirror_style: 0, transform: 'rotate(45)' },
{ thickness: 15, strokeLinecap: 'round', strokeLinejoin: 'round', color: '#00f', fill: 'none', mask: false, mirror_style: 0, transform: 'rotate(45)' }
]
this.vertices = []
this.reqs = { line: 2, arc_c: 2, arc_r: 2, arc_c_full: 2, arc_r_full: 2, bezier: 3, close: 0 }