Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Vue.js and SVG
Search
Callum Macrae
April 09, 2020
Technology
0
88
Vue.js and SVG
https://codepen.io/callumacrae/pen/oyXXWR
Callum Macrae
April 09, 2020
Tweet
Share
More Decks by Callum Macrae
See All by Callum Macrae
Climate change and the tech community
callumacrae
0
730
Data Visualisation With Vue.js
callumacrae
0
250
Building with Gulp
callumacrae
1
240
Other Decks in Technology
See All in Technology
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
15
93k
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
3k
[CV勉強会@関東 World Model 読み会] Orbis: Overcoming Challenges of Long-Horizon Prediction in Driving World Models (Mousakhan+, NeurIPS 2025)
abemii
0
140
StrandsとNeptuneを使ってナレッジグラフを構築する
yakumo
1
120
Bill One 開発エンジニア 紹介資料
sansan33
PRO
5
17k
データの整合性を保ちたいだけなんだ
shoheimitani
8
3.2k
Introduction to Sansan for Engineers / エンジニア向け会社紹介
sansan33
PRO
6
68k
外部キー制約の知っておいて欲しいこと - RDBMSを正しく使うために必要なこと / FOREIGN KEY Night
soudai
PRO
12
5.6k
Claude_CodeでSEOを最適化する_AI_Ops_Community_Vol.2__マーケティングx_AIはここまで進化した.pdf
riku_423
2
600
【Ubie】AIを活用した広告アセット「爆速」生成事例 | AI_Ops_Community_Vol.2
yoshiki_0316
1
110
コンテナセキュリティの最新事情 ~ 2026年版 ~
kyohmizu
2
230
ClickHouseはどのように大規模データを活用したAIエージェントを全社展開しているのか
mikimatsumoto
0
260
Featured
See All Featured
Measuring & Analyzing Core Web Vitals
bluesmoon
9
760
Agile that works and the tools we love
rasmusluckow
331
21k
Statistics for Hackers
jakevdp
799
230k
AI: The stuff that nobody shows you
jnunemaker
PRO
2
270
Code Reviewing Like a Champion
maltzj
527
40k
Utilizing Notion as your number one productivity tool
mfonobong
3
220
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
78
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
290
The Curse of the Amulet
leimatthew05
1
8.7k
Building Applications with DynamoDB
mza
96
6.9k
Context Engineering - Making Every Token Count
addyosmani
9
660
From π to Pie charts
rasagy
0
120
Transcript
Vue.js and SVG @callumacrae
Hi, I’m Callum @callumacrae Things I love: • SVG •
Animation • Vue.js
Building a bar chart @callumacrae
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
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
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
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
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
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
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
Building a bar chart @callumacrae
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
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
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
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
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
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
/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
/rect> lue }}</text> #chart text { fill: white; font: 20px
sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning text-anchor: middle; Text
/rect> lue }}</text> #chart text { fill: white; font: 20px
sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning text-anchor: end; Text
#chart text { fill: white; font: 20px sans-serif; text-anchor: end;
alignment-baseline: middle; } SVG text positioning alignment-baseline: baseline; Text /rect> lue }}</text>
/rect> lue }}</text> #chart text { fill: white; font: 20px
sans-serif; text-anchor: end; alignment-baseline: middle; } SVG text positioning alignment-baseline: hanging; Text
/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
#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
Animating a bar chart @callumacrae
No @callumacrae
Not really @callumacrae
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
@callumacrae
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
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
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
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
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
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
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
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
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
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
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
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
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
So what else can we do? @callumacrae
https://www.reddit.com/r/dataisbeautiful/comments/fxe484/oc_rating_of_the_office_episodes_according_to/
https://www.reddit.com/r/dataisbeautiful/comments/fwy7dj/oc_the_remarkable_decline_in_child_mortality/
https://www.reddit.com/r/dataisbeautiful/comments/fqqzki/worst_episode_ever_the_most_commonly_rated_shows/
<path d="M 10,10 L 50,100 L 200,50 L 240,30 L
300,60"></path> SVG paths - Vue?
SVG paths - Vue? https://medium.com/@mbostock/introducing-d3-shape-73f8367e6d12
SVG paths - Vue? https://medium.com/@mbostock/introducing-d3-shape-73f8367e6d12
SVG paths - d3!
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>
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>
Thank you @callumacrae