import { IEditableAttribute } from "../../core/EditableAttributes.js";
import HtmlControl from "../../core/HtmlControl.js";
import { isInsideHtmlEditor } from "../../core/HtmlEditor.js";
import { updateIntrinsicSize } from "../../core/updateIntrinsicSize.js";
import { XNode } from "../../core/XNode.js";
export default class ImageSlices extends HtmlControl {
static observedAttributes = [
"src",
"width",
"height",
"rows",
"columns",
"delay",
"delayFunc"
];
root: ShadowRoot;
img: HTMLImageElement;
get editableAttributes(): IEditableAttribute[] {
return [
{ name: "src", type: "image" },
{ name: "render-size", type: "number" },
{ name: "height", type: "size" },
{ name: "width", type: "size" },
{ name: "rows", type: "number" },
{ name: "columns", type: "number" },
{ name: "delay", type: "number" },
{
name: "delayFunc",
type: "string",
value: "",
suggestions: [
{ label: "(x, y) => 10*(x + 10*y)", value: "(x, y) => 10*(x + 10*y)"},
{ label: "(x, y) => 100*x + 100*y", value: "(x, y) => 100*x + 100*y"},
{ label: "(x, y) => 150*x + 300*y", value: "(x, y) => 150*x + 300*y"},
]
},
{ name: "mode", type: "enum", values: [
"shadow",
"dom"
] }
];
}
prepare() {
updateIntrinsicSize(this, "width");
updateIntrinsicSize(this, "height");
if (isInsideHtmlEditor(this)) {
const root = this.attachShadow({ mode: "open"})
this.root = root;
XNode.render(root,
);
this.img = this.root.querySelector("img") as HTMLImageElement;
}
this.updateImage().catch(console.error);
}
attributeChangedCallback(name, oldValue, newValue) {
switch(name) {
case "width":
updateIntrinsicSize(this, "width");
break;
case "height":
updateIntrinsicSize(this, "height");
break;
case "src":
case "rows":
case "delay":
case "delayFunc":
case "columns":
this.updateImage().catch(console.error);
break;
}
}
async updateImage() {
// prepare slices...
this.innerHTML = "";
let src = this.getAttribute("src");
if (!src) {
return;
}
const originalSrc = src;
src = CSS.escape(src);
if (isInsideHtmlEditor(this)) {
// addAdoptedStyleRule(this, `[src="${src}"]`, `background-image: url("${src}");`);
this.img?.setAttribute("src", originalSrc);
return;
}
const rows = this.getAttributeAsNumber("rows", 10);
const columns = this.getAttributeAsNumber("columns", 10);
const delay = this.getAttributeAsTime("delay",15);
const df = this.getDelayFunc(delay);
const diffRow = 100 / rows;
const diffCol = 100 / columns;
for (let row = 0; row < rows; row++) {
for(let col = 0; col < columns; col++) {
const d = df(row, col);
const slice = document.createElement("img");
const { style } = slice;
style.animationDelay = d + "ms";
const left = `${col * diffCol}%`;
const top = `${row * diffRow}%`;
const right = `${(col + 1) * diffCol}%`;
const bottom = `${(row + 1) * diffRow}%`;
slice.setAttribute("src", originalSrc);
style.clipPath = `polygon(${left} ${top}, ${right} ${top}, ${right} ${bottom}, ${left} ${bottom})`
this.appendChild(slice);
}
}
}
getDelayFunc(delay) {
let start = 0;
const df = this.getAttribute("delayFunc");
if (!df) {
return () => start += delay;
}
return new Function("row", "col", `return (${df})(row, col);`)
}
}
customElements.define("image-slices", ImageSlices);