Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vue.js and SVG

Vue.js and SVG

Callum Macrae

April 09, 2020
Tweet

More Decks by Callum Macrae

Other Decks in Technology

Transcript

  1. Building a bar chart const randomData = () => new

    Array(6).fill('') .map(() => 1 + Math.floor(Math.random() * 20)); new Vue({ el: '#chart', data: { chartData: randomData(), } }); @callumacrae
  2. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <div id="chart"> <div v-for="value in chartData" class="bar" :style="{ height: '60px', width: `${value * 30}px` }" ></div> </div> @callumacrae
  3. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <div id="chart"> <div v-for="value in chartData" class="bar" :style="{ height: '60px', width: `${value * 30}px` }" ></div> </div> @callumacrae
  4. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <svg id="chart" width="600" height="410"> <rect v-for="(value, i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" ></rect> </svg> @callumacrae
  5. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <svg id="chart" width="600" height="410"> <rect v-for="(value, i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" ></rect> </svg> @callumacrae
  6. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <svg id="chart" width="600" height="410"> <rect v-for="(value, i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" ></rect> </svg> #chart rect { fill: hsl(10, 80%, 70%); } @callumacrae
  7. Building a bar chart new Vue({ el: '#chart', data: {

    chartData: randomData(), } }); <svg id="chart" width="600" height="410"> <rect v-for="(value, i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" fill="hsl(10, 80%, 70%)" ></rect> </svg> #chart rect { fill: hsl(10, 80%, 70%); } @callumacrae
  8. Building a bar chart <svg id="chart" width="600" height="410"> <rect v-for="(value,

    i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" ></rect> </svg> @callumacrae
  9. Building a bar chart <svg id="chart" width="600" height="410"> <rect v-for="(value,

    i) in chartData" x="0" :y="i * 70" height="60" :width="value * 30" ></rect> </svg> <svg id="chart" width="600" height="410"> <g v-for="(value, i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> </g> </svg> @callumacrae
  10. Building a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> </g> </svg> @callumacrae
  11. Building a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> </svg> @callumacrae
  12. Building a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> </svg> @callumacrae
  13. Building a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> </svg> #chart text { fill: white; font: 20px sans-serif; text-anchor: end; alignment-baseline: middle; } @callumacrae
  14. /rect> lue }}</text> #chart text { fill: white; font: 20px

    sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning text-anchor: start; Text @callumacrae
  15. /rect> lue }}</text> #chart text { fill: white; font: 20px

    sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning text-anchor: middle; Text
  16. /rect> lue }}</text> #chart text { fill: white; font: 20px

    sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning text-anchor: end; Text
  17. #chart text { fill: white; font: 20px sans-serif; text-anchor: end;

    alignment-baseline: middle; } SVG text positioning alignment-baseline: baseline; Text /rect> lue }}</text>
  18. /rect> lue }}</text> #chart text { fill: white; font: 20px

    sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning alignment-baseline: hanging; Text
  19. /rect> lue }}</text> #chart text { fill: white; font: 20px

    sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning alignment-baseline: middle; Text @callumacrae
  20. #chart text { fill: white; font: 20px sans-serif; text-anchor: end;

    alignment-baseline: middle; } Building a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value, i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> </svg> @callumacrae
  21. Not really • We can use enter transitions to add

    new items • We can use list move transitions if the order were changing • Vue doesn't really help us transition state @callumacrae
  22. Animating a bar chart <svg id="chart" width="600" height="410"> <g v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`"> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> </svg> @callumacrae
  23. Animating a bar chart <svg id="chart" width="600" height="410"> <animated-bar v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`" :value="value"></animated-bar> </svg> Vue.component("animated-bar", { props: ["value"], template: ` <g> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> `, }); @callumacrae
  24. art ="410"> " * 70})`" lue * 30"></rect> - 10">{{

    value }}</text> Tweening with GSAP new Vue({ el: "#app", data: { number: 0 }, mounted() { gsap.to(this.$data, { duration: 4, number: 1000 }); }, }); @callumacrae
  25. art ="410"> " * 70})`" lue * 30"></rect> - 10">{{

    value }}</text> Tweening with GSAP new Vue({ el: "#app", data: { number: 0 }, mounted() { gsap.to(this.$data, { duration: 4, number: 1000 }); }, }); @callumacrae
  26. Animating a bar chart <svg id="chart" width="600" height="410"> <animated-bar v-for="(value,

    i) in chartData" :transform="`translate(0, ${i * 70})`" :value="value"></animated-bar> </svg> Vue.component("animated-bar", { props: ["value"], template: ` <g> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> `, }); @callumacrae
  27. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> `, }); @callumacrae
  28. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="value * 30"></rect> <text y="30" :x="value * 30 - 10">{{ value }}</text> </g> `, computed: { width() { return this.value * 30; }, }, }); @callumacrae
  29. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="width"></rect> <text y="30" :x="width - 10">{{ value }}</text> </g> `, computed: { width() { return this.value * 30; }, }, }); @callumacrae
  30. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="width"></rect> <text y="30" :x="width - 10">{{ value }}</text> </g> `, data: () => ({ tweenedValue: 0 }), computed: { width() { return this.value * 30; }, }, }); @callumacrae
  31. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="width"></rect> <text y="30" :x="width - 10">{{ value }}</text> </g> `, data: () => ({ tweenedValue: 0 }), computed: { width() { return this.value * 30; }, }, watch: { value() { gsap.to(this.$data, { duration: 0.6, tweenedValue: this.value }); }, }, }); @callumacrae
  32. Animating a bar chart Vue.component("animated-bar", { props: ["value"], template: `

    <g> <rect height="60" :width="width"></rect> <text y="30" :x="width - 10">{{ value }}</text> </g> `, data: () => ({ tweenedValue: 0 }), computed: { width() { return this.tweenedValue * 30; }, }, watch: { value() { gsap.to(this.$data, { duration: 0.6, tweenedValue: this.value }); }, }, }); @callumacrae
  33. Vue.component("animated-bar", { props: ["value"], template: ` <g> <rect height="60" :width="width"></rect>

    <text y="30" :x="width - 10">{{ value }}</text> </g> `, data: () => ({ tweenedValue: 0 }), computed: { width() { return this.tweenedValue * 30; }, }, watch: { value() { gsap.to(this.$data, { duration: 0.6, tweenedValue: this.value }); }, }, }); Animating a bar chart @callumacrae
  34. Vue.component("animated-bar", { props: ["value"], template: ` <g> <rect height="60" :width="width"></rect>

    <text y="30" :x="width - 10">{{ Math.round(tweenedValue) }}</text> </g> `, data: () => ({ tweenedValue: 0 }), computed: { width() { return this.tweenedValue * 30; }, }, watch: { value() { gsap.to(this.$data, { duration: 0.6, tweenedValue: this.value }); }, }, }); Animating a bar chart @callumacrae
  35. <path d="M 10,10 L 50,100 L 200,50 L 240,30 L

    300,60"></path> SVG paths - Vue?
  36. SVG paths - d3! Vue.component("chart-line", { props: ["data"], template: `<path

    :d="pathString"></path>`, computed: { pathString() { return d3.line()(this.data); }, }, }); <chart-line :data="[[0, 50], [100, 80], [200, 40], [300, 60], [400, 30]]" ></chart-line>
  37. SVG paths - d3! Vue.component("chart-line", { props: ["data"], template: `<path

    :d="pathString"></path>`, computed: { pathString() { return d3.line()(this.data); }, }, }); <chart-line :data="[[0, 50], [100, 80], [200, 40], [300, 60], [400, 30]]" ></chart-line>