Vue dynamic Properties Dialog
The properties dialogs can be added on the fly. Visual for Objects is a SVG object
by Ben Clayton
HTML
<script type="text/x-template" id="mynode-svg-template">
<g>
<circle v-on: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>
<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'><select v-model='color'><option v-for='selcolor in selcolors'>{{ selcolor }}</option></select></td>
</tr>
</table>
</div>
</script>
<!-- Drawing area for Nodes -->
<div class="svgarea">
<!-- SVG Elements -->
<svg width="500" height="300">
<g v-for="node in nodes">
<my-node :node="node.getViewData()" :click="node.click"></my-node>
</g>
</svg>
</div>
<!-- Property Dialog area -->
<div class="property-dialogs">
<div v-for="dialog in dialogs" class="dialogouter">
<propertydialog :refobj="dialog.refobj"></propertydialog>
</div>
<div style="clear:both" />
<button v-on:click="addDialog">Add Dialog</button>
</div>
CSS
.dialogouter {
display: inline-block;
margin: 20px;
}
.dialog {
width: 200px;
height: 300px;
display: inline-block;
border: 1px solid gray;
padding: 10px;
}
.dialog table td.label {}
.dialog table td.value {
min-width: 180px;
}
JavaScript
class myclass{
constructor(name,color,size,x,y) {
this.color=color || "gray";
this.name=name || "Fred";
this.size=size || 20;
this.selcolors=["pink","red","green","gray","blue","yellow"];
this.x = x || 260;
this.y = y || 100;
}
getViewData(){
return { x:this.x, y:this.y, size:this.size, name:this.name, color:this.color, click:this.click };
}
propertyTemplate(){
return "#mynode-dialog-template";
}
click(){
alert("Node Clicked in SVG View");
}
}
var objarray = [new myclass("C1","red",10,100,100),new myclass("C2","blue",20,160,100),new myclass("C3")]
Vue.component('my-node', {
props: ['node','click'],
template: '#mynode-svg-template',
methods: {
circleClick: function(event){
this.click();
},
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 - 20;
},
textY: function(){
return this.node.y;
},
name: function(){
return this.node.name;
},
prop: function(nm) {
var v = this.node[nm] || this[nm];
return v;
}
}
})
// bootstrap the demo
vm1 = new Vue({
el: '.svgarea',
data: {
nodes: objarray
}
})
//=============================================================================
var Loading = {
template: `<div>Loading...</div>`
}
var propertydialog = {
functional: true,
props: {
refobj : { type: Object, default: function(){} }
},
render(h, context) {
const template = context.props.refobj.propertyTemplate();
const dynComponent = {
template,
data() { return context.props.refobj }
}
const component = template ? dynComponent : Loading;
return h(component);
}
};
//...