Vue - Dynamic Dialogs
Vue also bound to SVG elements
by Ben Clayton
HTML
<script type="text/x-template" id="mynode-svg-template">
<g>
<circle @click="circleClick" :cx="circleX()" :cy="circleY()" :r="circleRadius()" :stroke="circleStroke()" :fill="circleFill()" stroke-width="1" />
<text :x="textX()" :y="textY()" fill="black">{{ name() }}</text>
</g>
</script>
<!-- Property template -->
<script type="text/x-template" id="mynode-dialog-template">
<div class='dialog'>
<div class="closebtn">X</div>
<div class="proplist">
<table>
<tr>
<td class='label'><label>Name:</label></td>
<td class='value'><input v-model='name'></td>
</tr>
<tr>
<td class='label'><label>Size:</label></td>
<td class='value'><input type='range' v-model='size' min='0' max='100'>{{ size }}</td>
</tr>
<tr>
<td class='label'><label>X:</label></td>
<td class='value'><input type='range' v-model='x' min='100' max='400'>{{ x }}</td>
</tr>
<tr>
<td class='label'><label>Y:</label></td>
<td class='value'><input type='range' v-model='y' min='50' max='250'>{{ y }}</td>
</tr>
<tr>
<td class='label'><label>Color:</label></td>
<td class='value'>
<my-color-selector :param="$data.getPropByRef('color')"></my-color-selector>
</td>
</tr>
</table>
</div>
</div>
</script>
<script type="text/x-template" id="my-color-selector-template">
<div>
<select v-model='param.ref[param.prop]'><option v-for='selcolor in selcolors'>{{ selcolor }}</option></select>
</div>
</script>
<!-- SVG Drawing area for Nodes -->
<div class="svgarea">
<!-- SVG Elements -->
<svg width="500" height="300">
<my-node v-for="node in nodes" :node="node.getSVGViewData()" :click="node.click"></my-node>
</svg>
</div>
<!-- Property Dialog area -->
<div class="property-dialogs">
<div><button @click="addDialog">Add Dialog for {{objarr[dialogs.length % objarr.length].name}}</button></div>
<div v-for="dialog in dialogs"...
CSS
.dialogouter {
display: inline-block;
margin: 20px;
}
.dialog {
width: 240px;
height: 300px;
display: inline-block;
border: 1px solid gray;
}
.dialog .proplist {
padding: 10px;
}
.dialog table td.label {}
.dialog table td.value {
min-width: 180px;
}
.dialog .closebtn {
float: right;
border:1px solid gray;
}
JavaScript
class myclass{
constructor( name, color, size, x, y ) {
this.name = name || "mycircle";
this.size = size || 20;
this.color = color || "gray";
this.x = x || 260;
this.y = y || 100;
}
getPropByRef( nm ){ // used to pass 'color' by ref to color selector component
return { ref : this, prop: nm };
}
getSVGViewData(){
return { ref:this, x:this.x, y:this.y, size:this.size, name:this.name, color:this.color, click:this.click };
}
propertyTemplate(){
return "#mynode-dialog-template";
}
// The click is not called with the context of the class
// but the parameter 'cls' points at this class.
click( cls ){
// 'pd' is a global pointer to the view handling the dialogs array.
pd.singleDialog(cls);
}
}
var objarray = [
new myclass("C1","red",10,100,100),
new myclass("C2","blue",20,160,100),
new myclass("C3")
];
// Vue component for driving svg object
Vue.component('my-node', {
props: ['node','click'],
template: '#mynode-svg-template',
methods: {
circleClick: function(event){
this.click( this.node.ref );
},
circleFill: function() {
return this.node.color;
},
circleRadius: function(){
return this.node.size;
},
circleX: function(){
return this.node.x;
},
circleY: function(){
return this.node.y;
},
circleStroke: function(){
return this.node.stroke || "black";
},
textX: function(){
return this.node.x - this.node.size - ( 7 * this.node.name.length ) - 10;
},
textY: function(){
return this.node.y;
},
name: function(){
return this.node.name;
}
}
});
// SVG Area Handler
vm1 = new Vue({
el: '.svgarea',
data: {
nodes: objarray
}
});
//=============================================================================
// Dynamic Vue component, which is a bit of magic config, hard to...