Vue bind to SVG Elements

by Ben Clayton

HTML

<script src="//unpkg.com/vue"></script>
<script type="text/x-template" id="mycircle-template">
<!-- <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> -->
  <circle :cx="prop('x')" :cy="prop('y')" :r="prop('r')" :stroke="prop('stroke')" :fill="color()" stroke-width="1" />
</script>

<!-- demo root element -->
<div id="demo">
  <!-- SVG Elements -->
	<svg width="500" height="300">
		<g v-for="stat in stats">
			<mycircle :stat="stat"></mycircle>
		</g>
  </svg>

	<!-- controls -->
  <div v-for="stat in stats">
    <label>{{stat.label}} (radius)</label>
    <input type="range" v-model="stat.r" min="0" max="100">
		<label>(colour)</label>
		<input type="checkbox" v-model="stat.state" value=0>
  </div>

</div>

JavaScript

// The raw data to observe
var stats = [{
    label: 'C1',
    r: 10,
    fill: "gray",
    x: 50,
    y: 123,
    stroke: "black"
  },
  {
    label: 'C2',
    r: 10,
    fill: "gray",
    x: 100,
    y: 123,
    stroke: "black"
  },
  {
    label: 'C3',
    r: 10,
    fill: "gray",
    x: 150,
    yd: 123,
    stroke: "black"
  },
  {
    label: 'C4',
    r: 10,
    fill: "gray",
    x: 200,
    y: 123,
    stroke: "black"
  }
  /* ,{ label: 'C2', r: 100 },
  { label: 'C3', r: 100 },
  { label: 'C4', r: 50 } */
]




Vue.component('mycircle', {
  props: ['stat'],
  template: '#mycircle-template',
  // components data must be a function
	// used here as default if 'stat' doesn't provide property
  data: function() {
    return {}
  },
  methods: {
    color: function() {
      return this.stat.state ? "red" : "green"
    },
		prop: function(nm) {
      return this.stat[nm] || this[nm];
    }
  }
})

// bootstrap the demo
new Vue({
  el: '#demo',
  data: {
    newLabel: '',
    stats: stats
  },
  methods: {
    add: function(e) {
      e.preventDefault()
      if (!this.newLabel) return
      this.stats.push({
        label: this.newLabel,
        value: 100
      })
      this.newLabel = ''
    },
    remove: function(stat) {
      if (this.stats.length > 3) {
        this.stats.splice(this.stats.indexOf(stat), 1)
      } else {
        alert('Can\'t delete more!')
      }
    }
  }
})