(předpokládám, že toto je jen zjednodušený příklad; pokud ne a chcete fakt tři obdélníky, bylo by podle mě o dost jednodušší tam dát SVG obrázek, který můžete napřímo napsat v dothtml markupu)
V podstatě máte dvě možnosti jak toho dosáhnout
Knockout binding handler
to je snad dostatečně popsané na Adding interactivity using Knockout binding handlers | DotVVM Documentation. V podstatě na to potřebujete vlastní DotvvmControl, který zavolá knockout binding handler. V tom se vám spustí init
vždycky když se přidá tím repeaterem do stránky, případně update
když se změní nějaký jeho data binding.
JsComponent
což máme aktuálně zdokumentované jenom pro integraci React komponent. Použít React pro renderování do canvasu je samozřemě nesmysl, ale můžete se celkem snadno napojit do toho spojovacího API. Pořád jsem na to nenapsal dokumentaci, tak to popíšu nejdřív tady (pak to snad přeložím a publikujem to):
- Potřebujete si vyrobit JavaScriptový view modul, k tomu dokumentace existuje
- Z modulu vyexportujeme komponentu, která pak půjde použít v dothtml markupu pomocí
<js:JménoKomponenty property1={value: Data} />
(taky jí můžete předávat libovolně pojmenované commandy a templaty)
- DotVVM jako JsComponent prostě očekává funkci, která dá element a property z markupu. Můžete použít následující kostru:
function myControl(
element: HTMLElement, // wrapper tag (nastavitelný v dothtml propertou `WrapperTagName`)
props: { [key: string]: any }, // všechny property s value bindingem, resource binding nebo konstantou
commands: { [key: string]: (args: any[]) => Promise<any> }, // property s commandem, nebo staticCommandem
templates: { [key: string]: string },
setProps: (p: { [key: string]: any }) => void // funkce kterou můžete propsat změny zpět do value bindingů
): DotvvmJsComponent {
let canvas = document.createElement("canvas")
elm.appendChild(canvas)
update(props)
function update(updatedProps) {
// vyčtu si potřebná data
const { property1, property2 } = props
if (updatedProps.property1) {
// některé změny je výhodné dělat jen při určitých změnách
}
// re-render canvasu bych dělal prostě po každé změně
}
// DotVVM bude automaticky volat následující události:
return {
updateProps(updatedProps) {
// updatedProps obsahují jen změny, tímto je sloučíme s přechozím stavem
props = { ...props, ...updatedProps }
update(updatedProps)
},
dispose() {
// HTML element včetně obsahu se odstraní sám, to zde není potřeba řešit
}
}
}
- Tuto komponentu pak exportujete z view modulu podobně jako ty React komponenty -
$controls: { myComponent: { create: myControl } }
- Ve vaše případě by to bylo něco takového (pokud nepoužíváte typescript, tak prostě smažte ty typy za dvojtečkou)
function vlanCanvas(element: HTMLElement, props: { [key: string]: any }): DotvvmJsComponent {
let canvas = document.createElement("canvas")
elm.appendChild(canvas)
update(props)
function update(updatedProps) {
const { color } = props
const ctx = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height)
const computedColor = getComputedStyle(canvas).getPropertyValue("--color-vlan-" + color)
ctx.fillStyle = computedColor || 'white'
ctx.fillRect(6, 7, 38, 25)
ctx.fillRect(11, 32, 28, 6)
ctx.fillRect(17, 37, 16, 6)
}
return {
updateProps(updatedProps) {
props = { ...props, ...updatedProps }
update(updatedProps)
}
}
}
export default context => ({
$controls: { create: vlanCanvas }
})
modul je někde potřeba registrovat jako resource
config.Resources.RegisterScriptModuleFile("vlanCanvasModule", "scripts/vlanCanvasModule.js");
a v markupu pak
@js vlanCanvasModule
...
<js:vlanCanvas color={value ...} />
img onerror
pokud vám to přijde moc opruz, tak bonusová (prokletá) metoda je použít něco takového
<canvas >
<img src="/doesntexist" onerror="drawOnCanvas(event.target.previousElementSibling)"
Omlouvám se pozdní odpověď. Kdyby něco nebylo jasné nebo nefungovalo, tak se ptejte dál, zkusím odpovídat dřív