I try to embed <https://github.com/data2viz> (a d3...
# kvision
j
I try to embed https://github.com/data2viz (a d3 port to kotlin).
The js example uses a canvas. How can I embed that in KVision?
r
I've taken https://raw.githubusercontent.com/data2viz/data2viz-examples/master/examples/chord/src/commonMain/kotlin/ChordCommon.kt, put into kvision template and called like this:
Copy code
root("kvapp") {
            canvas(800, 600) {
                addAfterInsertHook {
                    chordViz().bindRendererOn(this.getElement().unsafeCast<HTMLCanvasElement>())
                }
            }
        }
Seems to work fine (had to remove
d2v-contour
dependency, because it couldn't be found).
👍 1
j
How can I wrapp a canvas in a SimplePanel?
r
What do you mean?
j
Can I assign a canvas to any widget?
r
canvas component is just for a html
<canvas>
tag, you can put it wherever you need
👍 1
j
Somehow I'm missing the Point (or is it pairOf({})) (-:
Copy code
import io.data2viz.color.Colors
import io.data2viz.geom.size
import io.data2viz.scale.Scales
import io.data2viz.viz.TextHAlign
import io.data2viz.viz.TextVAlign
import io.data2viz.viz.bindRendererOn
import io.data2viz.viz.viz
import io.kvision.html.Canvas
import kotlinx.browser.document
import kotlinx.dom.appendElement
import org.apache.isis.client.kroviz.core.event.LogEntry
import org.apache.isis.client.kroviz.ui.core.RoDialog
import org.w3c.dom.ElementCreationOptions

class ChartDialog(
    private val expectedEvents: List<LogEntry>,
    canvasId: String
) : Controller() {

    init {
        dialog = RoDialog(
            caption = canvasId,
            items = mutableListOf(),
            controller = this,
            defaultAction = "OK",
            widthPerc = 60,
            heightPerc = 70,
            customButtons = mutableListOf()
        )
        val options = ElementCreationOptions("HTMLCanvasElement")
        val element = document.createElement(canvasId, options)
        document.body!!.appendElement(canvasId, {element})
        val canvasWidth = 100
        val canvasHeight = 200
        val cssClassName: String? = null
        val canvas = Canvas(canvasWidth, canvasHeight, cssClassName, { barchartExample(canvasId) })

        dialog.add(canvas)
    }

    private fun Canvas.barchartExample(canvasId: String) {
        val vizSize = 500.0
        val barHeight = 14.0
        val cPadding = 2.0
        val data = listOf(4, 8, 15, 16, 23, 42)

        val xScale = Scales.Continuous.linear {
            domain = listOf(.0, data.maxOrNull()!!.toDouble())
            range = listOf(.0, vizSize - 2 * cPadding)
        }

        val viz = viz {
            size = size(vizSize, vizSize)
            data.forEachIndexed { index, datum ->
                group {
                    transform {
                        translate(
                            x = cPadding,
                            y = cPadding + index * (cPadding + barHeight)
                        )
                    }
                    rect {
                        width = xScale(datum.toDouble())
                        height = barHeight
                        fill = Colors.Web.steelblue
                    }
                    text {
                        textContent = datum.toString()
                        hAlign = TextHAlign.RIGHT
                        vAlign = TextVAlign.HANGING
                        x = xScale(datum.toDouble()) - 2.0
                        y = 1.5
                        textColor = Colors.Web.white
                        fontSize = 10.0
                    }
                }
            }
        }
        viz.bindRendererOn(canvasId)
    }

}
r
I don't understand ... 🙂
j
No wonder - I get "No canvas in the document corresponding to"
Meanwhile I'm a bit further and a window is opened, but I see no diagram and the buttons do not work:
Copy code
document.body!!.appendElement(canvasId, {})
val canvas = Canvas(200, 200)
canvas.addAfterInsertHook {
    val htmlCanvas = document.getElementById(canvasId).unsafeCast<HTMLCanvasElement>()
    viz().bindRendererOn(htmlCanvas)
}
dialog.add(canvas)
r
You want do show canvas and draw on it inside the dialog window?
j
Exactly. Is that possible?
r
RoDialog
is inherited from 'Modal' or 'Window'?
No need to play with canvasId manually, just stick to canvas elements.
Copy code
class CanvasWindow: Window("Let's draw") {
    init {
        canvas(800, 600) {
            barchartExample()
        }
    }
}

private fun Canvas.barchartExample() {
    val vizSize = 500.0
    val barHeight = 14.0
    val cPadding = 2.0
    val data = listOf(4, 8, 15, 16, 23, 42)

    val xScale = Scales.Continuous.linear {
        domain = listOf(.0, data.maxOrNull()!!.toDouble())
        range = listOf(.0, vizSize - 2 * cPadding)
    }

    val viz = viz {
        size = size(vizSize, vizSize)
        data.forEachIndexed { index, datum ->
            group {
                transform {
                    translate(
                        x = cPadding,
                        y = cPadding + index * (cPadding + barHeight)
                    )
                }
                rect {
                    width = xScale(datum.toDouble())
                    height = barHeight
                    fill = Colors.Web.steelblue
                }
                text {
                    textContent = datum.toString()
                    hAlign = TextHAlign.RIGHT
                    vAlign = TextVAlign.HANGING
                    x = xScale(datum.toDouble()) - 2.0
                    y = 1.5
                    textColor = Colors.Web.white
                    fontSize = 10.0
                }
            }
        }
    }
    addAfterInsertHook {
        viz.bindRendererOn(this.getElement().unsafeCast<HTMLCanvasElement>())
    }
}
The "desktop" example uses canvas element inside a floating
Window
. Here you can see how canvas is resized to dynamically match window size. https://github.com/rjaros/kvision-examples/blob/master/desktop/src/main/kotlin/com/example/Paint.kt#L156
👍 1
j
Thanks!
Hmm - still not what I want - it seems using canvas like:
Copy code
init {
    dialog = RoDialog(
        caption = canvasId,
        items = mutableListOf(),
        controller = this,
        defaultAction = "OK",
        widthPerc = 50,
        heightPerc = 50,
        customButtons = mutableListOf()
    )
    val canvas = Canvas(200, 200)
    canvas.addAfterInsertHook {
        val htmlCanvas = canvas.unsafeCast<HTMLCanvasElement>()
        viz().bindRendererOn(htmlCanvas)
    }
    dialog.add(canvas)
}
leads to restrictions when moving windows.
What am I missing?
r
No idea. Can I see the whole code?
j
I‘ll create a branch and post the link
If you want to run it: You only need to compile kroviz, in case you want to see more, use the 'incode' url in the Connect dialog.
Should be:
Copy code
val htmlCanvas = canvas.getElement().unsafeCast<HTMLCanvasElement>()
j
You made my day - sometimes I feel like a monkey (https://en.wikipedia.org/wiki/Infinite_monkey_theorem)