Feat: Template Styles
This commit is contained in:
parent
46214c56cf
commit
06b06ba067
|
@ -1,5 +1,5 @@
|
||||||
import { useTemplateContext } from "../../contexts/TemplateContext";
|
import { useTemplateContext } from "../../contexts/TemplateContext";
|
||||||
import { Input, Slider, Switch } from "@nextui-org/react";
|
import { Input, Select, SelectItem, Slider, Switch } from "@nextui-org/react";
|
||||||
|
|
||||||
export const TemplateSettings = () => {
|
export const TemplateSettings = () => {
|
||||||
const {
|
const {
|
||||||
|
@ -15,6 +15,8 @@ export const TemplateSettings = () => {
|
||||||
setY,
|
setY,
|
||||||
opacity,
|
opacity,
|
||||||
setOpacity,
|
setOpacity,
|
||||||
|
style,
|
||||||
|
setStyle,
|
||||||
showMobileTools,
|
showMobileTools,
|
||||||
setShowMobileTools,
|
setShowMobileTools,
|
||||||
} = useTemplateContext();
|
} = useTemplateContext();
|
||||||
|
@ -70,6 +72,29 @@ export const TemplateSettings = () => {
|
||||||
onChange={(v) => setOpacity(v as number)}
|
onChange={(v) => setOpacity(v as number)}
|
||||||
getValue={(v) => v + "%"}
|
getValue={(v) => v + "%"}
|
||||||
/>
|
/>
|
||||||
|
<Select
|
||||||
|
label="Template Style"
|
||||||
|
size="sm"
|
||||||
|
selectedKeys={[style]}
|
||||||
|
onChange={(e) => setStyle(e.target.value as any)}
|
||||||
|
>
|
||||||
|
<SelectItem key="SOURCE">Source</SelectItem>
|
||||||
|
<SelectItem key="ONE_TO_ONE">One-to-one</SelectItem>
|
||||||
|
<SelectItem key="ONE_TO_ONE_INCORRECT">
|
||||||
|
One-to-one (keep incorrect)
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem key="DOTTED_SMALL">Dotted Small</SelectItem>
|
||||||
|
<SelectItem key="DOTTED_BIG">Dotted Big</SelectItem>
|
||||||
|
<SelectItem key="SYMBOLS">Symbols</SelectItem>
|
||||||
|
<SelectItem key="NUMBERS">Numbers</SelectItem>
|
||||||
|
</Select>
|
||||||
|
{style !== "ONE_TO_ONE" && (
|
||||||
|
<div>
|
||||||
|
<b>Warning:</b> Template color picking only
|
||||||
|
<br />
|
||||||
|
works with one-to-one template style
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<Switch
|
<Switch
|
||||||
className="md:hidden"
|
className="md:hidden"
|
||||||
isSelected={showMobileTools}
|
isSelected={showMobileTools}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Canvas } from "../../lib/canvas";
|
||||||
|
|
||||||
export const Template = () => {
|
export const Template = () => {
|
||||||
const { config } = useAppContext();
|
const { config } = useAppContext();
|
||||||
const { enable, url, width, setWidth, x, y, opacity, setX, setY } =
|
const { enable, url, width, setWidth, x, y, opacity, setX, setY, style } =
|
||||||
useTemplateContext();
|
useTemplateContext();
|
||||||
const templateHolder = useRef<HTMLDivElement>(null);
|
const templateHolder = useRef<HTMLDivElement>(null);
|
||||||
const instance = useRef<TemplateCl>();
|
const instance = useRef<TemplateCl>();
|
||||||
|
@ -87,7 +87,9 @@ export const Template = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!instance.current) {
|
if (!instance.current) {
|
||||||
console.warn("Received template enable but no instance exists");
|
console.warn(
|
||||||
|
"[Template] Received template enable but no instance exists"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +97,7 @@ export const Template = () => {
|
||||||
|
|
||||||
if (enable && url) {
|
if (enable && url) {
|
||||||
instance.current.loadImage(url).then(() => {
|
instance.current.loadImage(url).then(() => {
|
||||||
console.log("enable: load image finished");
|
console.log("[Template] enable: load image finished");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [enable]);
|
}, [enable]);
|
||||||
|
@ -103,29 +105,29 @@ export const Template = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!instance.current) {
|
if (!instance.current) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"recieved template url update but no template instance exists"
|
"[Template] Recieved template url update but no template instance exists"
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
console.warn("received template url blank");
|
console.warn("[Template] Received template url blank");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
console.info("Got template URL but not enabled, ignoring");
|
console.info("[Template] Got template URL but not enabled, ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.current.loadImage(url).then(() => {
|
instance.current.loadImage(url).then(() => {
|
||||||
console.log("template loader finished");
|
console.log("[Template] Template loader finished");
|
||||||
});
|
});
|
||||||
}, [url]);
|
}, [url]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!instance.current) {
|
if (!instance.current) {
|
||||||
console.warn("received template width with no instance");
|
console.warn("[Template] Received template width with no instance");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +135,15 @@ export const Template = () => {
|
||||||
instance.current.rasterizeTemplate();
|
instance.current.rasterizeTemplate();
|
||||||
}, [width]);
|
}, [width]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!instance.current) {
|
||||||
|
console.warn("[Template] Received style update with no instance");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.current.setOption("style", style);
|
||||||
|
}, [style]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="template"
|
id="template"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
} from "react";
|
} from "react";
|
||||||
import { IRouterData, Router } from "../lib/router";
|
import { IRouterData, Router } from "../lib/router";
|
||||||
import { KeybindManager } from "../lib/keybinds";
|
import { KeybindManager } from "../lib/keybinds";
|
||||||
|
import { TemplateStyle } from "../lib/template";
|
||||||
|
|
||||||
interface ITemplate {
|
interface ITemplate {
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +31,7 @@ interface ITemplate {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
|
style: TemplateStyle;
|
||||||
|
|
||||||
showMobileTools: boolean;
|
showMobileTools: boolean;
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@ interface ITemplate {
|
||||||
setX(v: number): void;
|
setX(v: number): void;
|
||||||
setY(v: number): void;
|
setY(v: number): void;
|
||||||
setOpacity(v: number): void;
|
setOpacity(v: number): void;
|
||||||
|
setStyle(style: TemplateStyle): void;
|
||||||
setShowMobileTools(v: boolean): void;
|
setShowMobileTools(v: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,9 @@ export const TemplateContext = ({ children }: PropsWithChildren) => {
|
||||||
const [x, setX] = useState(routerData.template?.x || 0);
|
const [x, setX] = useState(routerData.template?.x || 0);
|
||||||
const [y, setY] = useState(routerData.template?.y || 0);
|
const [y, setY] = useState(routerData.template?.y || 0);
|
||||||
const [opacity, setOpacity] = useState(100);
|
const [opacity, setOpacity] = useState(100);
|
||||||
|
const [style, setStyle] = useState<TemplateStyle>(
|
||||||
|
routerData.template?.style || "ONE_TO_ONE"
|
||||||
|
);
|
||||||
const [showMobileTools, setShowMobileTools] = useState(true);
|
const [showMobileTools, setShowMobileTools] = useState(true);
|
||||||
|
|
||||||
const initAt = useRef<number>();
|
const initAt = useRef<number>();
|
||||||
|
@ -70,6 +76,7 @@ export const TemplateContext = ({ children }: PropsWithChildren) => {
|
||||||
setWidth(data.template.width);
|
setWidth(data.template.width);
|
||||||
setX(data.template.x || 0);
|
setX(data.template.x || 0);
|
||||||
setY(data.template.y || 0);
|
setY(data.template.y || 0);
|
||||||
|
setStyle(data.template.style || "ONE_TO_ONE");
|
||||||
} else {
|
} else {
|
||||||
setEnable(false);
|
setEnable(false);
|
||||||
}
|
}
|
||||||
|
@ -89,7 +96,7 @@ export const TemplateContext = ({ children }: PropsWithChildren) => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Router.setTemplate({ enabled: enable, width, x, y, url });
|
Router.setTemplate({ enabled: enable, width, x, y, url, style });
|
||||||
|
|
||||||
if (!initAt.current) {
|
if (!initAt.current) {
|
||||||
console.debug("TemplateContext updating router but no initAt");
|
console.debug("TemplateContext updating router but no initAt");
|
||||||
|
@ -102,7 +109,7 @@ export const TemplateContext = ({ children }: PropsWithChildren) => {
|
||||||
|
|
||||||
if (initAt.current && Date.now() - initAt.current > 2 * 1000)
|
if (initAt.current && Date.now() - initAt.current > 2 * 1000)
|
||||||
Router.queueUpdate();
|
Router.queueUpdate();
|
||||||
}, [enable, width, x, y, url]);
|
}, [enable, width, x, y, url, style]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<templateContext.Provider
|
<templateContext.Provider
|
||||||
|
@ -119,6 +126,8 @@ export const TemplateContext = ({ children }: PropsWithChildren) => {
|
||||||
setY,
|
setY,
|
||||||
opacity,
|
opacity,
|
||||||
setOpacity,
|
setOpacity,
|
||||||
|
style,
|
||||||
|
setStyle,
|
||||||
showMobileTools,
|
showMobileTools,
|
||||||
setShowMobileTools,
|
setShowMobileTools,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { PanZoom } from "@sc07-canvas/lib/src/renderer/PanZoom";
|
||||||
import { Canvas } from "./canvas";
|
import { Canvas } from "./canvas";
|
||||||
import throttle from "lodash.throttle";
|
import throttle from "lodash.throttle";
|
||||||
import EventEmitter from "eventemitter3";
|
import EventEmitter from "eventemitter3";
|
||||||
|
import { TemplateStyle, TemplateStyles } from "./template";
|
||||||
|
|
||||||
const CLIENT_PARAMS = {
|
const CLIENT_PARAMS = {
|
||||||
canvas_x: "x",
|
canvas_x: "x",
|
||||||
|
@ -11,6 +12,7 @@ const CLIENT_PARAMS = {
|
||||||
template_width: "tw",
|
template_width: "tw",
|
||||||
template_x: "tx",
|
template_x: "tx",
|
||||||
template_y: "ty",
|
template_y: "ty",
|
||||||
|
template_style: "ts",
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IRouterData {
|
export interface IRouterData {
|
||||||
|
@ -24,6 +26,7 @@ export interface IRouterData {
|
||||||
width?: number;
|
width?: number;
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
|
style?: TemplateStyle;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,10 +44,12 @@ class _Router extends EventEmitter<RouterEvents> {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
style: TemplateStyle;
|
||||||
} = {
|
} = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
style: "ONE_TO_ONE",
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -105,6 +110,8 @@ class _Router extends EventEmitter<RouterEvents> {
|
||||||
params.set(CLIENT_PARAMS.template_width, this.templateState.width + "");
|
params.set(CLIENT_PARAMS.template_width, this.templateState.width + "");
|
||||||
params.set(CLIENT_PARAMS.template_x, this.templateState.x + "");
|
params.set(CLIENT_PARAMS.template_x, this.templateState.x + "");
|
||||||
params.set(CLIENT_PARAMS.template_y, this.templateState.y + "");
|
params.set(CLIENT_PARAMS.template_y, this.templateState.y + "");
|
||||||
|
if (this.templateState.style)
|
||||||
|
params.set(CLIENT_PARAMS.template_style, this.templateState.style + "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -161,6 +168,7 @@ class _Router extends EventEmitter<RouterEvents> {
|
||||||
width?: number;
|
width?: number;
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
|
style?: TemplateStyle;
|
||||||
}
|
}
|
||||||
| undefined = undefined;
|
| undefined = undefined;
|
||||||
|
|
||||||
|
@ -190,6 +198,14 @@ class _Router extends EventEmitter<RouterEvents> {
|
||||||
template.y = y;
|
template.y = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.has(CLIENT_PARAMS.template_style)) {
|
||||||
|
let style = params.get(CLIENT_PARAMS.template_style);
|
||||||
|
|
||||||
|
if (style && TemplateStyles.indexOf(style) > -1) {
|
||||||
|
template.style = style as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -208,6 +224,7 @@ class _Router extends EventEmitter<RouterEvents> {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
style: TemplateStyle;
|
||||||
}) {
|
}) {
|
||||||
this.templateState = args;
|
this.templateState = args;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,30 @@ interface TemplateEvents {
|
||||||
interface ITemplateOptions {
|
interface ITemplateOptions {
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
width?: number;
|
width?: number;
|
||||||
style: TemplateStyle;
|
style: keyof typeof TemplateStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TemplateStyle {
|
const TemplateStyle = {
|
||||||
SOURCE = "",
|
SOURCE: "",
|
||||||
ONE_TO_ONE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGklEQVQoz2P8//8/AymAiYFEMKphVMPQ0QAAVW0DHZ8uFaIAAAAASUVORK5CYII=",
|
ONE_TO_ONE:
|
||||||
ONE_TO_ONE_INCORRECT = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGklEQVQoz2P8//8/AymAiYFEMKphVMPQ0QAAVW0DHZ8uFaIAAAAASUVORK5CYII=",
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGklEQVQoz2P8//8/AymAiYFEMKphVMPQ0QAAVW0DHZ8uFaIAAAAASUVORK5CYII=",
|
||||||
DOTTED_SMALL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAQAAAD9CzEMAAAAAmJLR0QA/4ePzL8AAAAzSURBVFjD7dBBDQAACMSw828aVEAI6R4T0GShGv6DECFChAgRIkSIECFChAgRIkSIruA0nub+AuTzLZoAAAAASUVORK5CYII=",
|
ONE_TO_ONE_INCORRECT:
|
||||||
DOTTED_BIG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAWklEQVR42u3UwQkAIAwEwcX+e9aP2INkBvK4d2CLqva9cXv5PWgAoAGgARoAGqABoAEaABqgAaABGgAaoAGgARoAGqABoAEaABqgAaABGgAaoAGgAT/vRwOmO8dS/DI1VxCbAAAAAElFTkSuQmCC",
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGklEQVQoz2P8//8/AymAiYFEMKphVMPQ0QAAVW0DHZ8uFaIAAAAASUVORK5CYII=",
|
||||||
SYMBOLS = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwAQMAAAD8LmYIAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAZQTFRFAAAAAwMDFQUF7wAAAAJ0Uk5TAP9bkSK1AAAAuUlEQVR4nGNgQAUhjQvdz0uwMfx82OrVIgPkBj/xaOEQ6GRuP9vHAeQGsPjzyVj8LH5+iAXEDTziMd+uplHg+VE+GQaNjwHt5+WB3A+HO+bbMRACDoed+Xg0FIMW97dIMLAwNC45OF8ip+Dh8aN8Ngwsjc2sXfNFBAoePz8xX46B5+DhNj4WlpwCx+NH5W0Yan5+fn6+xU5DwWlxf58EAWs0DFC4NQX4uBaoXAFUvaNgFIyCUTAKaAYAzI49GM5w0hQAAAAOZVhJZk1NACoAAAAIAAAAAAAAANJTkwAAAABJRU5ErkJggg==",
|
DOTTED_SMALL:
|
||||||
NUMBERS = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALAAAACwCAYAAACvt+ReAAAE10lEQVR42u3d3bKjKBQGULDy/q/MXE1VdzqRH9kqZq2bqZn5JKAmErbm5JRSSbCw0pGTlb1VdttpoAS9AUpANgW1u0q2dGxTOo7faLu92TTa7vZlozz55P2/zRyQ7RXRj97+zsyWjm1GT97aGI9kR8aWaydwxIEg7g05ms0nvcnCsq8bzrVnvVNr2RyQzReP7eeO33bBp0We/E6NnJr0nJAR7UZOpR5x/LYEC9smrCyMrETMXErpvazd4fI9c3+VnW/2teze8Ss7qwAt7ZYJ50y13deqk/fBbVYb28iY8mLZvf9ebTcnlTgeOIWAZShJyi6bfX3YOH84sfOXF7oyW3amQrXs++vMarc3m7/048w+rJT957htlU/i3HCQ93J77R7N5o4vD+/ZUvmSkRvHdiSbOvqwt/2RbA7av6cdt+0Bqw8jlMDX9M9xq5WS71xKjS5VtmxbDvZ3JJsDsvnEsU09dq+GM75MPnl72s2VQZx1JehdA23pb8/YevdDax/KhWMrM84Vy2gs7dOXuJGSZMslYLTUWbsUtbT7nm25ibqlhPqp3Z7+po7+RuyHnj707t/S8fql8/XLyHzE2qPs7bJKyTxmCgFLcimSXTa7fdiwfPn3NDGbgtq9ezYNZke++JaAbApqdzj75zrw+9rd3lrekeye1vsljmZ7+5snZL/1q2clJw3uwxnZXlGPWP3VX3PgNSh9f/HaeaeXzk+FEpzNAdl88dhSQPanjttWeafX7lZq/ZRovQPqSLanDyWo3ci70XqyvXeutbQbeVdez91onkrmmVOII3c1RV02I+8Ei2g36sc/SuOVo+WSfKS/EdOfw/2wnii7bFYpmaWZA7M8lyLZZbOvD0sUf/4z7XyJ68n++f88PfyDTw9H9WHWI0W17JFHXmqv+WnHzcymjj7Utj2yvpwC9u/yx+3uc2Al1DWddtxelfnw7DJjxI9Kt14pSuM7flY2B2TzxWO73XF7/12IM8qMtXeuEmpDCfWEsR2dSvVOu4ZuWbCMxtJaf9gkHcjNKM3WVgBqlzGl7/7+HhlfrfQ9ejdaOXqSysreKquUzNLMgVmeS5Hsstlv9wMroY5lW7+4KH1Pyr6vQiihHnsquTSMy1Pf4/v3n6w58FxK3yf7VkpWQo35M7Ol4xPzvd0SnM0B2Rw9tq1y+f7Fp4fPOHlr/SgdYysHxta7H3pOyIh2/a1kfmMK0fqJ0rrd3Uq5nh6O3Q8peP8Obywre6usUjJLMwdmeS5Fsstma6Xkb8scSqjPyC5/3Fp+nfKbI0+hRq0vp45s72MsOaC/V2eXP26z5sBKqGta/rjNWgfuyfrh7Pix/cxx2w68Iy95CvWiS5wfzt7f/rKnvi2j8egpxC2fQr355TCiXU9972xrPVF22axSMo+aQkCUsCU7lyLZM7Lhn8BKqOf39xdL31PN+kOHSqhj+yF1ju0ppe+wE9h8jKW/xK1WQj1D5GM3I9mIH5vOF49tyifwij/AfOYndk8JNqLNiDJ/CWr3tOOmlMxjphB+gPn4VErp+4Jpn3VK2TOyYXM7pWTO+h4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE/1H4IIqRgL4W2oAAAAAElFTkSuQmCC",
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAQAAAD9CzEMAAAAAmJLR0QA/4ePzL8AAAAzSURBVFjD7dBBDQAACMSw828aVEAI6R4T0GShGv6DECFChAgRIkSIECFChAgRIkSIruA0nub+AuTzLZoAAAAASUVORK5CYII=",
|
||||||
}
|
DOTTED_BIG:
|
||||||
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAWklEQVR42u3UwQkAIAwEwcX+e9aP2INkBvK4d2CLqva9cXv5PWgAoAGgARoAGqABoAEaABqgAaABGgAaoAGgARoAGqABoAEaABqgAaABGgAaoAGgAT/vRwOmO8dS/DI1VxCbAAAAAElFTkSuQmCC",
|
||||||
|
SYMBOLS:
|
||||||
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwAQMAAAD8LmYIAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAZQTFRFAAAAAwMDFQUF7wAAAAJ0Uk5TAP9bkSK1AAAAuUlEQVR4nGNgQAUhjQvdz0uwMfx82OrVIgPkBj/xaOEQ6GRuP9vHAeQGsPjzyVj8LH5+iAXEDTziMd+uplHg+VE+GQaNjwHt5+WB3A+HO+bbMRACDoed+Xg0FIMW97dIMLAwNC45OF8ip+Dh8aN8Ngwsjc2sXfNFBAoePz8xX46B5+DhNj4WlpwCx+NH5W0Yan5+fn6+xU5DwWlxf58EAWs0DFC4NQX4uBaoXAFUvaNgFIyCUTAKaAYAzI49GM5w0hQAAAAOZVhJZk1NACoAAAAIAAAAAAAAANJTkwAAAABJRU5ErkJggg==",
|
||||||
|
NUMBERS:
|
||||||
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALAAAACwCAYAAACvt+ReAAAE10lEQVR42u3d3bKjKBQGULDy/q/MXE1VdzqRH9kqZq2bqZn5JKAmErbm5JRSSbCw0pGTlb1VdttpoAS9AUpANgW1u0q2dGxTOo7faLu92TTa7vZlozz55P2/zRyQ7RXRj97+zsyWjm1GT97aGI9kR8aWaydwxIEg7g05ms0nvcnCsq8bzrVnvVNr2RyQzReP7eeO33bBp0We/E6NnJr0nJAR7UZOpR5x/LYEC9smrCyMrETMXErpvazd4fI9c3+VnW/2teze8Ss7qwAt7ZYJ50y13deqk/fBbVYb28iY8mLZvf9ebTcnlTgeOIWAZShJyi6bfX3YOH84sfOXF7oyW3amQrXs++vMarc3m7/048w+rJT957htlU/i3HCQ93J77R7N5o4vD+/ZUvmSkRvHdiSbOvqwt/2RbA7av6cdt+0Bqw8jlMDX9M9xq5WS71xKjS5VtmxbDvZ3JJsDsvnEsU09dq+GM75MPnl72s2VQZx1JehdA23pb8/YevdDax/KhWMrM84Vy2gs7dOXuJGSZMslYLTUWbsUtbT7nm25ibqlhPqp3Z7+po7+RuyHnj707t/S8fql8/XLyHzE2qPs7bJKyTxmCgFLcimSXTa7fdiwfPn3NDGbgtq9ezYNZke++JaAbApqdzj75zrw+9rd3lrekeye1vsljmZ7+5snZL/1q2clJw3uwxnZXlGPWP3VX3PgNSh9f/HaeaeXzk+FEpzNAdl88dhSQPanjttWeafX7lZq/ZRovQPqSLanDyWo3ci70XqyvXeutbQbeVdez91onkrmmVOII3c1RV02I+8Ei2g36sc/SuOVo+WSfKS/EdOfw/2wnii7bFYpmaWZA7M8lyLZZbOvD0sUf/4z7XyJ68n++f88PfyDTw9H9WHWI0W17JFHXmqv+WnHzcymjj7Utj2yvpwC9u/yx+3uc2Al1DWddtxelfnw7DJjxI9Kt14pSuM7flY2B2TzxWO73XF7/12IM8qMtXeuEmpDCfWEsR2dSvVOu4ZuWbCMxtJaf9gkHcjNKM3WVgBqlzGl7/7+HhlfrfQ9ejdaOXqSysreKquUzNLMgVmeS5Hsstlv9wMroY5lW7+4KH1Pyr6vQiihHnsquTSMy1Pf4/v3n6w58FxK3yf7VkpWQo35M7Ol4xPzvd0SnM0B2Rw9tq1y+f7Fp4fPOHlr/SgdYysHxta7H3pOyIh2/a1kfmMK0fqJ0rrd3Uq5nh6O3Q8peP8Obywre6usUjJLMwdmeS5Fsstma6Xkb8scSqjPyC5/3Fp+nfKbI0+hRq0vp45s72MsOaC/V2eXP26z5sBKqGta/rjNWgfuyfrh7Pix/cxx2w68Iy95CvWiS5wfzt7f/rKnvi2j8egpxC2fQr355TCiXU9972xrPVF22axSMo+aQkCUsCU7lyLZM7Lhn8BKqOf39xdL31PN+kOHSqhj+yF1ju0ppe+wE9h8jKW/xK1WQj1D5GM3I9mIH5vOF49tyifwij/AfOYndk8JNqLNiDJ/CWr3tOOmlMxjphB+gPn4VErp+4Jpn3VK2TOyYXM7pWTO+h4BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE/1H4IIqRgL4W2oAAAAAElFTkSuQmCC",
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TemplateStyle = keyof typeof TemplateStyle;
|
||||||
|
export const TemplateStyles = Object.keys(TemplateStyle);
|
||||||
|
|
||||||
|
const STYLES_Y = 16;
|
||||||
|
const STYLES_X = 16;
|
||||||
|
|
||||||
export class Template extends EventEmitter<TemplateEvents> {
|
export class Template extends EventEmitter<TemplateEvents> {
|
||||||
static instance: Template;
|
static instance: Template;
|
||||||
|
@ -41,7 +53,7 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
|
|
||||||
options: ITemplateOptions = {
|
options: ITemplateOptions = {
|
||||||
enable: false,
|
enable: false,
|
||||||
style: TemplateStyle.ONE_TO_ONE,
|
style: "ONE_TO_ONE",
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(config: ClientConfig, templateHolder: HTMLDivElement) {
|
constructor(config: ClientConfig, templateHolder: HTMLDivElement) {
|
||||||
|
@ -67,7 +79,11 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
|
|
||||||
this.$style = document.createElement("img");
|
this.$style = document.createElement("img");
|
||||||
this.$style.setAttribute("crossorigin", "");
|
this.$style.setAttribute("crossorigin", "");
|
||||||
this.$style.setAttribute("src", this.options!.style);
|
this.$style.setAttribute("src", TemplateStyle[this.options!.style]);
|
||||||
|
this.$style.addEventListener("load", () => {
|
||||||
|
console.log("[Template] Style loaded");
|
||||||
|
this.loadStyle();
|
||||||
|
});
|
||||||
|
|
||||||
this.$canvas = document.createElement("canvas");
|
this.$canvas = document.createElement("canvas");
|
||||||
|
|
||||||
|
@ -108,6 +124,18 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
case "enable":
|
case "enable":
|
||||||
this.setElementVisible([this.$canvas], !!value);
|
this.setElementVisible([this.$canvas], !!value);
|
||||||
break;
|
break;
|
||||||
|
case "style":
|
||||||
|
if ((value as keyof typeof TemplateStyle) in TemplateStyle) {
|
||||||
|
const key = value as keyof typeof TemplateStyle;
|
||||||
|
|
||||||
|
this.$style.setAttribute("src", TemplateStyle[key]);
|
||||||
|
this.$imageLoader.style.display = key === "SOURCE" ? "block" : "none";
|
||||||
|
|
||||||
|
if (key === "SOURCE") {
|
||||||
|
this.stylizeTemplate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit("option", key, value);
|
this.emit("option", key, value);
|
||||||
|
@ -208,15 +236,27 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
width: this.$imageLoader.naturalWidth,
|
width: this.$imageLoader.naturalWidth,
|
||||||
height: this.$imageLoader.naturalHeight,
|
height: this.$imageLoader.naturalHeight,
|
||||||
};
|
};
|
||||||
|
let style = {
|
||||||
|
width: this.$style.naturalWidth / STYLES_X,
|
||||||
|
height: this.$style.naturalHeight / STYLES_Y,
|
||||||
|
};
|
||||||
|
|
||||||
let aspectRatio = source.height / source.width;
|
let aspectRatio = source.height / source.width;
|
||||||
|
|
||||||
|
let display = {
|
||||||
|
width: Math.round(this.options?.width || source.width),
|
||||||
|
height: Math.round((this.options?.width || source.width) * aspectRatio),
|
||||||
|
};
|
||||||
|
let internal = {
|
||||||
|
width: display.width * style.width,
|
||||||
|
height: display.height * style.height,
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
source,
|
source,
|
||||||
display: {
|
style,
|
||||||
width: Math.round(this.options?.width || source.width),
|
display,
|
||||||
height: Math.round((this.options?.width || source.width) * aspectRatio),
|
internal,
|
||||||
},
|
|
||||||
aspectRatio,
|
aspectRatio,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -240,15 +280,14 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
} = { downscaling: {} } as any;
|
} = { downscaling: {} } as any;
|
||||||
|
|
||||||
updateSize() {
|
updateSize() {
|
||||||
const {
|
const { display, internal } = this.getDimentions();
|
||||||
display: { width, height },
|
|
||||||
} = this.getDimentions();
|
|
||||||
|
|
||||||
this.$wrapper.style.width = width + "px";
|
this.$wrapper.style.width = display.width + "px";
|
||||||
this.$imageLoader.style.width = width + "px";
|
this.$imageLoader.style.width = display.width + "px";
|
||||||
|
this.$canvas.style.width = display.width + "px";
|
||||||
|
|
||||||
this.$canvas.width = width;
|
this.$canvas.width = internal.width;
|
||||||
this.$canvas.height = height;
|
this.$canvas.height = internal.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,8 +300,6 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
const palette: { value: string }[] = this.config.pallete.colors.map(
|
const palette: { value: string }[] = this.config.pallete.colors.map(
|
||||||
(color) => ({ value: color.hex })
|
(color) => ({ value: color.hex })
|
||||||
);
|
);
|
||||||
const STYLES_Y = 16;
|
|
||||||
const STYLES_X = 16;
|
|
||||||
|
|
||||||
const context = this.$canvas.getContext("webgl", {
|
const context = this.$canvas.getContext("webgl", {
|
||||||
premultipliedAlpha: true,
|
premultipliedAlpha: true,
|
||||||
|
@ -589,11 +626,9 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
stylizeTemplate() {
|
stylizeTemplate() {
|
||||||
this.updateSize();
|
this.updateSize();
|
||||||
|
|
||||||
const {
|
const { internal, display } = this.getDimentions();
|
||||||
display: { width, height },
|
|
||||||
} = this.getDimentions();
|
|
||||||
|
|
||||||
if (this.context == null || width === 0 || height === 0) {
|
if (this.context == null || internal.width === 0 || internal.height === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,14 +637,14 @@ export class Template extends EventEmitter<TemplateEvents> {
|
||||||
this.framebuffers.main
|
this.framebuffers.main
|
||||||
);
|
);
|
||||||
this.context.clear(this.context.COLOR_BUFFER_BIT);
|
this.context.clear(this.context.COLOR_BUFFER_BIT);
|
||||||
this.context.viewport(0, 0, width, height);
|
this.context.viewport(0, 0, internal.width, internal.height);
|
||||||
|
|
||||||
this.context.useProgram(this.programs.stylize);
|
this.context.useProgram(this.programs.stylize);
|
||||||
|
|
||||||
this.context.uniform2f(
|
this.context.uniform2f(
|
||||||
this.context.getUniformLocation(this.programs.stylize, "u_TexelSize"),
|
this.context.getUniformLocation(this.programs.stylize, "u_TexelSize"),
|
||||||
1 / width,
|
1 / display.width,
|
||||||
1 / height
|
1 / display.height
|
||||||
);
|
);
|
||||||
|
|
||||||
this.context.activeTexture(this.context.TEXTURE0);
|
this.context.activeTexture(this.context.TEXTURE0);
|
||||||
|
|
Loading…
Reference in New Issue