diff --git a/scratch2/filter.js b/scratch2/filter.js deleted file mode 100644 index dbd2934a..00000000 --- a/scratch2/filter.js +++ /dev/null @@ -1,78 +0,0 @@ -import SVG from "./draw.js" - -export default class Filter { - constructor(id, props) { - this.el = SVG.el("filter", { - ...props, - id: id, - x0: "-50%", - y0: "-50%", - width: "200%", - height: "200%", - }) - this.highestId = 0 - } - - fe(name, props, children) { - const shortName = name.toLowerCase().replace(/gaussian|osite/, "") - const id = `${shortName}-${++this.highestId}` - this.el.appendChild( - SVG.withChildren( - SVG.el(`fe${name}`, { ...props, result: id }), - children || [], - ), - ) - return id - } - - comp(op, in1, in2, props) { - return this.fe("Composite", { ...props, operator: op, in: in1, in2: in2 }) - } - - subtract(in1, in2) { - return this.comp("arithmetic", in1, in2, { k2: +1, k3: -1 }) - } - - offset(dx, dy, in1) { - return this.fe("Offset", { - in: in1, - dx: dx, - dy: dy, - }) - } - - flood(color, opacity, in1) { - return this.fe("Flood", { - in: in1, - "flood-color": color, - "flood-opacity": opacity, - }) - } - - blur(dev, in1) { - return this.fe("GaussianBlur", { - in: in1, - stdDeviation: `${dev} ${dev}`, - }) - } - - colorMatrix(in1, values) { - return this.fe("ColorMatrix", { - in: in1, - type: "matrix", - values: values.join(" "), - }) - } - - merge(children) { - this.fe( - "Merge", - {}, - children.map(name => - SVG.el("feMergeNode", { - in: name, - }), - ), - ) - } -} diff --git a/scratch2/style.js b/scratch2/style.js index 30bb49a7..85f4875c 100644 --- a/scratch2/style.js +++ b/scratch2/style.js @@ -1,6 +1,5 @@ import SVG from "./draw.js" import Color from "../shared/color.js" -import Filter from "./filter.js" import cssContent from "./style.css.js" export default class Style { @@ -1317,49 +1316,59 @@ export default class Style { } static bevelFilter(id, inset) { - const f = new Filter(id) + return SVG.withChildren( + SVG.el("filter", { id, x: "0", y: "0", width: "1", height: "1" }), + [ + SVG.el("feOffset", { dx: inset ? "1" : "-1", dy: inset ? "1" : "-1", in: "SourceAlpha" }), + SVG.el("feGaussianBlur", { stdDeviation: "1", edgeMode: "none" }), + SVG.el("feColorMatrix", { type: "matrix", values: ` + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 -.7 .7 + `, result: "shadow" }), - const alpha = "SourceAlpha" - const s = inset ? -1 : 1 - const blur = f.blur(1, alpha) + SVG.el("feOffset", { dx: inset ? "-1" : "1", dy: inset ? "-1" : "1", in: "SourceAlpha" }), + SVG.el("feGaussianBlur", { stdDeviation: "1", edgeMode: "none" }), + SVG.el("feColorMatrix", { type: "matrix", values: ` + 0 0 0 0 1 + 0 0 0 0 1 + 0 0 0 0 1 + 0 0 0 -.15 .15 + ` }), - f.merge([ - "SourceGraphic", - f.comp( - "in", - f.flood("#fff", 0.15), - f.subtract(alpha, f.offset(+s, +s, blur)), - ), - f.comp( - "in", - f.flood("#000", 0.7), - f.subtract(alpha, f.offset(-s, -s, blur)), - ), - ]) - - return f.el + SVG.el("feComposite", { operator: "atop", in2: "SourceGraphic" }), + SVG.el("feComposite", { operator: "atop", in: "shadow" }), + ], + ) } static darkFilter(id) { - const f = new Filter(id) - - f.merge([ - "SourceGraphic", - f.comp("in", f.flood("#000", 0.2), "SourceAlpha"), - ]) - - return f.el + return SVG.withChildren( + SVG.el("filter", { id, x: "0", y: "0", width: "1", height: "1" }), + [ + SVG.el("feColorMatrix", { type: "matrix", values: ` + .8 0 0 0 0 + 0 .8 0 0 0 + 0 0 .8 0 0 + 0 0 0 1 0 + ` }), + ], + ) } static lightFilter(id) { - const f = new Filter(id) - - f.merge([ - "SourceGraphic", - f.comp("in", f.flood("#fff", 0.4), "SourceAlpha"), - ]) - - return f.el + return SVG.withChildren( + SVG.el("filter", { id, x: "0", y: "0", width: "1", height: "1" }), + [ + SVG.el("feColorMatrix", { type: "matrix", values: ` + .6 0 0 0 .4 + 0 .6 0 0 .4 + 0 0 .6 0 .4 + 0 0 0 1 0 + ` }), + ], + ) } static darkRect(w, h, color, el) { diff --git a/scratch3/filter.js b/scratch3/filter.js deleted file mode 100644 index c4e07294..00000000 --- a/scratch3/filter.js +++ /dev/null @@ -1,88 +0,0 @@ -import SVG from "./draw.js" - -export default class Filter { - constructor(id, props) { - this.el = SVG.el("filter", { - ...props, - id: id, - x0: "-50%", - y0: "-50%", - width: "200%", - height: "200%", - }) - this.highestId = 0 - } - - fe(name, props, children) { - const shortName = name.toLowerCase().replace(/gaussian|osite/, "") - const id = `${shortName}-${++this.highestId}` - this.el.appendChild( - SVG.withChildren( - SVG.el(`fe${name}`, { ...props, result: id }), - children || [], - ), - ) - return id - } - - comp(op, in1, in2, props) { - return this.fe("Composite", { ...props, operator: op, in: in1, in2: in2 }) - } - - subtract(in1, in2) { - return this.comp("arithmetic", in1, in2, { k2: +1, k3: -1 }) - } - - offset(dx, dy, in1) { - return this.fe("Offset", { - in: in1, - dx: dx, - dy: dy, - }) - } - - flood(color, opacity, in1) { - return this.fe("Flood", { - in: in1, - "flood-color": color, - "flood-opacity": opacity, - }) - } - - blur(dev, in1) { - return this.fe("GaussianBlur", { - in: in1, - stdDeviation: `${dev} ${dev}`, - }) - } - - dropShadow(dx, dy, blur, color, opacity) { - return this.fe("DropShadow", { - dx: dx, - dy: dy, - stdDeviation: blur, - "flood-color": color, - "flood-opacity": opacity, - }) - } - - colorMatrix(in1, values) { - return this.fe("ColorMatrix", { - in: in1, - type: "matrix", - values: values.join(" "), - }) - } - - merge(children) { - this.fe( - "Merge", - {}, - children.map(name => - SVG.el("feMergeNode", { - in: name, - }), - ), - ) - } -} diff --git a/scratch3/style.js b/scratch3/style.js index d99f19c5..9fcde3c8 100644 --- a/scratch3/style.js +++ b/scratch3/style.js @@ -1,7 +1,6 @@ import SVG from "./draw.js" import Color from "../shared/color.js" import cssContent from "./style.css.js" -import Filter from "./filter.js" // Need to define here, as we cannot reference Style#makeNewIcons // during JS loading phase. @@ -2339,13 +2338,16 @@ export default class Style { } static zebraFilter(id, isDark) { - const f = new Filter(id) - - f.merge([ - "SourceGraphic", - f.comp("in", f.flood(isDark ? "#000" : "#fff", 0.3), "SourceAlpha"), - ]) - - return f.el + return SVG.withChildren( + SVG.el("filter", { id, x: "0", y: "0", width: "1", height: "1" }), + [ + SVG.el("feColorMatrix", { type: "matrix", values: ` + .7 0 0 0 ${isDark ? 0 : .3} + 0 .7 0 0 ${isDark ? 0 : .3} + 0 0 .7 0 ${isDark ? 0 : .3} + 0 0 0 1 0 + ` }), + ], + ) } } diff --git a/snap/blocks.js b/snap/blocks.js index 131cbd68..c04f8300 100644 --- a/snap/blocks.js +++ b/snap/blocks.js @@ -2636,6 +2636,7 @@ export class DocumentView { group.querySelectorAll(".snap-drop-shadow").forEach(el => { el.style.filter = `url(#snapDropShadow-${this.id})` + el.setAttribute("transform", `${el.getAttribute("transform") || ""} translate(-1 -1)`) }) group.querySelectorAll(".snap-bevel").forEach(el => { el.style.filter = `url(#snapBevelFilter-${this.id})` diff --git a/snap/filter.js b/snap/filter.js deleted file mode 100644 index 7275c27a..00000000 --- a/snap/filter.js +++ /dev/null @@ -1,164 +0,0 @@ -import SVG from "./draw.js" - -export default class Filter { - /** - * Creates an instance of Filter. - * - * @constructor - * @param {string} id - * @param {Object} props - */ - constructor(id, props) { - this.el = SVG.el("filter", { - ...props, - id: id, - x0: "-50%", - y0: "-50%", - width: "200%", - height: "200%", - }) - this.highestId = 0 - } - - /** - * Filter element - * - * @param {string} name - * @param {Object} props - * @param {SVGElement[]} children - * @returns {string} - Filter id - */ - fe(name, props, children) { - const shortName = name.toLowerCase().replace(/gaussian|osite/, "") - const id = `${shortName}-${++this.highestId}` - this.el.appendChild( - SVG.withChildren( - SVG.el(`fe${name}`, { ...props, result: id }), - children || [], - ), - ) - return id - } - - /** - * Add composite filter - * - * @param {string} op - * @param {string} in1 - * @param {string} in2 - * @param {Object} props - * @returns {string} - */ - comp(op, in1, in2, props) { - return this.fe("Composite", { ...props, operator: op, in: in1, in2: in2 }) - } - - /** - * Subtract filter - * - * @param {string} in1 - * @param {string} in2 - * @returns {string} - */ - subtract(in1, in2) { - return this.comp("arithmetic", in1, in2, { k2: +1, k3: -1 }) - } - - /** - * Offset filter - * - * @param {number} dx - * @param {number} dy - * @param {string} in1 - * @returns {string} - */ - offset(dx, dy, in1) { - return this.fe("Offset", { - in: in1, - dx: dx, - dy: dy, - }) - } - - /** - * Flood filter - * - * @param {string} color - * @param {number} opacity - * @param {string} in1 - * @returns {string} - */ - flood(color, opacity, in1) { - return this.fe("Flood", { - in: in1, - "flood-color": color, - "flood-opacity": opacity, - }) - } - - /** - * Blur filter - * - * @param {number} dev - * @param {string} in1 - * @returns {string} - */ - blur(dev, in1) { - return this.fe("GaussianBlur", { - in: in1, - stdDeviation: `${dev} ${dev}`, - }) - } - - /** - * Dropshadow filter - * - * @param {number} dx - * @param {number} dy - * @param {number} blur - * @param {string} color - * @param {number} opacity - * @returns {string} - */ - dropShadow(dx, dy, blur, color, opacity) { - return this.fe("DropShadow", { - dx: dx, - dy: dy, - stdDeviation: blur, - "flood-color": color, - "flood-opacity": opacity, - }) - } - - /** - * Color matrix - * - * @param {string} in1 - * @param {string[]} values - * @returns {string} - */ - colorMatrix(in1, values) { - return this.fe("ColorMatrix", { - in: in1, - type: "matrix", - values: values.join(" "), - }) - } - - /** - * Merge - * - * @param {string[]} children - Filter ids - */ - merge(children) { - this.fe( - "Merge", - {}, - children.map(name => - SVG.el("feMergeNode", { - in: name, - }), - ), - ) - } -} diff --git a/snap/style.js b/snap/style.js index b80718b0..3bc4e70d 100644 --- a/snap/style.js +++ b/snap/style.js @@ -1,6 +1,5 @@ import SVG from "./draw.js" import Color from "../shared/color.js" -import Filter from "./filter.js" import cssContent from "./style.css.js" export default class Style { @@ -2004,18 +2003,22 @@ export default class Style { /** * Create dropshadow filter + * make sure to also use `transform:translate(-1px,-1px);` on the element + * the movement can't be done in the filter due to issues in firefox * * @static * @param {string} id * @returns {SVGFilterElement} */ static dropShadowFilter(id) { - const f = new Filter(id) - // f.dropShadow(-0.5, -0.5, 0, "black", 0.3) - let flood = f.flood("#000", 0.3, "SourceAlpha") - let offset = f.offset(-0.6, -0.6, f.blur(0, "SourceAlpha")) - f.comp("over", "SourceGraphic", f.comp("in", flood, offset)) - return f.el + return SVG.withChildren( + SVG.el("filter", { id, x: "0", y: "0", width: "2", height: "2" }), + [ + SVG.el("feOffset", { dx: "1", dy: "1", result: "o" }), + SVG.el("feComposite", { operator: "arithmetic", k2: ".3", in: "SourceAlpha" }), + SVG.el("feComposite", { in: "o" }), + ], + ) } /** @@ -2023,36 +2026,43 @@ export default class Style { * * @static * @param {string} id - * @param {number} inset + * @param {boolean} inset * @returns {SVGFilterElement} */ static bevelFilter(id, inset) { - const f = new Filter(id) - - const alpha = "SourceAlpha" - const blur = f.blur(0.3, alpha) + return SVG.withChildren( + SVG.el("filter", { id }), + [ + SVG.el("feOffset", { dx: inset ? "1" : "-1", dy: inset ? "1" : "-1", in: "SourceAlpha" }), + SVG.el("feGaussianBlur", { stdDeviation: ".6", edgeMode: "none" }), + SVG.el("feColorMatrix", { type: "matrix", values: ` + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 -1.1 .9 + `, result: "shadow" }), - f.merge([ - "SourceGraphic", - f.comp( - "in", - f.flood("#fff", 0.4), - f.subtract( - alpha, - f.offset(inset ? -0.4 : 0.4, inset ? -0.4 : 0.4, blur), - ), - ), - f.comp( - "in", - f.flood("#000", inset ? 0.9 : 0.8), - f.subtract( - alpha, - f.offset(inset ? 0.7 : -0.7, inset ? 0.7 : -0.7, blur), - ), - ), - ]) + SVG.el("feOffset", { dx: inset ? "-1" : "1", dy: inset ? "-1" : "1", in: "SourceAlpha" }), + SVG.el("feGaussianBlur", { stdDeviation: ".6", edgeMode: "none" }), + SVG.el("feColorMatrix", { type: "matrix", values: ` + 0 0 0 0 1 + 0 0 0 0 1 + 0 0 0 0 1 + 0 0 0 -.7 .5 + `, result: "highlight" }), - return f.el + // offset .4px, .2px + SVG.el("feConvolveMatrix", { + order: "2", + divisor: "100", + kernelMatrix: inset ? "100 0 0 0" : "48 32 12 8", + edgeMode: "none", + in: "SourceGraphic" + }), + SVG.el("feComposite", { operator: "atop", in: "highlight" }), + SVG.el("feComposite", { operator: "atop", in: "shadow" }), + ], + ) } /** @@ -2094,6 +2104,6 @@ export default class Style { * @constant */ static get defaultFontFamily() { - return "Lucida Grande, Verdana, Arial, DejaVu Sans, sans-serif" + return "Verdana, sans-serif" } }