Ui-template, svg, cannot dynamically set viewBox

I am trying to dynamically set the svg viewBox in a D2 ui-template, and failing miserably. This example contains two templates each with an svg image. One, which works as I expected, sets the viewBox using
<svg width="100%" height="100%" viewBox="0 0 100 100">.
The other uses
<svg width="100%" height="100%" :viewBox="theViewBox">
where theViewBox is a computed function that returns the string "0 0 100 100", and does not draw the contained circle the correct size. The only difference I can see in the DOM inspector is that the first shows
<svg width="100%" height="100%" viewBox="0 0 100 100"><g><circle cx="50" cy="50" r="50"></circle></g></svg>
and the second shows
<svg width="100%" height="100%" viewbox="0 0 100 100"><g><circle cx="50" cy="50" r="50"></circle></g></svg>
The only difference I can see is viewBox vs viewbox.

Can anyone see my mistake or is something not working as it should?

image

[{"id":"87db3b23f4d4d43a","type":"ui-template","z":"997da33a0beedade","group":"4f87bd59a15b847e","name":"viewbox test template 1","order":0,"width":"4","height":"4","head":"","format":"\n<script>\n    export default{\n        data(){\n        }\n  }\n</script>\n\n<template>\n    <div >\n        <div >Viewbox test 1</div>\n        <svg  width=\"100%\" height=\"100%\" viewBox=\"0 0 100 100\">\n            <g>\n                <circle cx=\"50\" cy=\"50\" r=\"50\"></circle>\n            </g>\n        </svg>\n    </div>\n</template>\n\n<script>\n    export default{\n        methods:{\n        },\n        watch: {\n            msg: function(){\n                console.log(`msg: ${JSON.stringify(this.msg)}`)\n            }\n        },\n        computed: {\n        },\n        mounted(){\n        }\n\n    }\n</script>\n\n<style>\n \n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":630,"y":3980,"wires":[[]]},{"id":"c2589b96a4d75d33","type":"ui-template","z":"997da33a0beedade","group":"4f87bd59a15b847e","name":"viewbox test template 2","order":0,"width":"4","height":"4","head":"","format":"\n<script>\n    export default{\n        data(){\n        }\n  }\n</script>\n\n<template>\n    <div class=\"hn-sng\">\n        <div class=\"label\">Viewbox test 2</div>\n        <svg width=\"100%\" height=\"100%\" :viewBox=\"theViewBox\">\n            <g>\n                <circle cx=\"50\" cy=\"50\" r=\"50\"></circle>\n            </g>\n        </svg>\n    </div>\n</template>\n\n<script>\n    export default{\n        methods:{\n\n        },\n        watch: {\n            msg: function(){\n                console.log(`msg: ${JSON.stringify(this.msg)}`)\n            }\n        },\n        computed: {\n            theViewBox: function() {\n                const answer = \"0 0 100 100\"\n                console.log(`theViewBox: ${answer}`)\n                return answer\n            },\n        },\n        mounted(){\n        }\n\n    }\n</script>\n\n<style>\n \n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":630,"y":4040,"wires":[[]]},{"id":"4f87bd59a15b847e","type":"ui-group","name":"test","page":"ebe9054315fb0b03","width":"6","height":"1","order":-1,"showTitle":false,"className":"","visible":"true","disabled":"false"},{"id":"ebe9054315fb0b03","type":"ui-page","name":"Test","ui":"ID-BASE-1","path":"/test","icon":"home","layout":"grid","theme":"f9b6670b127dc219","order":-1,"className":"","visible":"true","disabled":"false"},{"id":"ID-BASE-1","type":"ui-base","name":"Dashboard","path":"/dashboard"},{"id":"f9b6670b127dc219","type":"ui-theme","name":"FlowForge Theme","colors":{"surface":"#152a47","primary":"#005aff","bgPage":"#ffffff","groupBg":"#ffffff","groupOutline":"#cc3e3e"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]

This here may explain what happens but most probably doesn't provide the solution ...

I think you are right. If, in the developer tools, I add the attribute viewBox="0 0 100 100" then it fixes it. Having googled a bit it is not clear to me whether this is a fundamental problem with veutify or is a @joepavitt issue.

Do you know of a workaround that I could use in the meantime?

I'd suspect vue. It doesn't take account that the attribute is for SVG element thus should be treated accordingly.

For workaround maybe to make the attribute change by yourself using setAttributeNS. Haven't tired obviously..

Also the thing to try is to declare the namespace for svg <svg xmlns="http://www.w3.org/2000/svg">

Do you mean change what I have to
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" :viewBox="theViewBox">
If so then it doesn't appear to help.

I will research how to call setAttributeNS in the template and give that a go if I can work it out.

This doesn't make sense.

If I remove the viewbox setting from the svg definition and then in the browser tools add the attribute viewBox="0 0 100 100" the circle instantly jumps to the correct size, as described above, but if I add a ref to svg so that I can reference it using $refs["svg-element] then, in mounted() I have

        const svgElement = this.$refs["svg-element"]
        if (svgElement) {
            svgElement.setAttributeNS("http://www.w3.org/2000/svg", "viewBox", "0 0 100 100")
        }

then in the the browser I now see
<svg width="100%" height="100%" viewBox="0 0 100 100"><g><circle cx="50" cy="50" r="50"></circle></g></svg>
but the circle does not change. I tried doing it watch msg instead, and can see the attribute appear but again it doesn't change the image.

[Edit] Oh, If I use svgElement.setAttributeNS("", "viewBox", "0 0 100 100") it works perfectly.

Seems to be a Vue issue when its v-bind it doesnt keep the camel case (link)

Try

:view-box.camel="theViewBox"
1 Like

Brilliant, that fixed it. Thanks.