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);
  }
};

//...