Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active February 3, 2017 15:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitaku/7fd3c55874fc889af14d69e0e13e95cb to your computer and use it in GitHub Desktop.
Save nitaku/7fd3c55874fc889af14d69e0e13e95cb to your computer and use it in GitHub Desktop.
Vue.js bar chart component

An exercise that displays three flexible bar chart components linked to the same data, using vue.js.

Vue.component 'bar-chart',
props:
data:
type: Array
required: true
padding:
type: Number
default: 1
color:
type: String
default: 'gray'
data: () ->
width: 200
height: 200
template: '''
<svg class="bar-chart">
<rect
class="bar"
v-for="d in layout"
:x="d.x"
:y="d.y"
:width="d.width"
:height="d.height"
:fill="color"
/>
</svg>
'''
created: () ->
@x = d3.scaleLinear()
@y = d3.scaleLinear()
mounted: () ->
@width = @$el.clientWidth
@height = @$el.clientHeight
computed:
layout: () ->
@x
.domain [0, @data.length]
.range [0, @width]
@y
.domain [0, d3.max @data, (d) -> d.v]
.range [0, @height]
return @data.map (d, i) => {
v: d.v,
x: @x(i),
y: @y.range()[1]-@y(d.v),
width: Math.max(1,@x(1)-@x(0)-@padding),
height: @y(d.v)
}
app = new Vue
el: '#app'
data:
values: [{v:10},{v:20},{v:30}]
methods:
add_random_datapoint: () ->
@values.push {v: Math.random()*300}
body, html {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
#app {
width: 100%;
height: 100%;
}
.horizontal {
display: flex;
flex-direction: row;
flex-grow: 1;
}
.vertical {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.bar-chart {
flex-grow: 1;
margin: 6px;
}
button {
height: 32px;
font-weight: bold;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue.js Bar Chart Component</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app" class="vertical">
<button id="button" v-on:click="add_random_datapoint">
Add random datapoint
</button>
<div class="horizontal">
<bar-chart
v-bind:data="values"
:padding="1"
/>
<div class="vertical">
<bar-chart
v-bind:data="values"
:padding="1"
color="orange"
/>
<bar-chart
v-bind:data="values"
:padding="3"
color="teal"
/>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
// Generated by CoffeeScript 1.10.0
(function() {
var app;
Vue.component('bar-chart', {
props: {
data: {
type: Array,
required: true
},
padding: {
type: Number,
"default": 1
},
color: {
type: String,
"default": 'gray'
}
},
data: function() {
return {
width: 200,
height: 200
};
},
template: '<svg class="bar-chart">\n <rect\n class="bar"\n v-for="d in layout"\n :x="d.x"\n :y="d.y"\n :width="d.width"\n :height="d.height"\n :fill="color"\n />\n</svg>',
created: function() {
this.x = d3.scaleLinear();
return this.y = d3.scaleLinear();
},
mounted: function() {
this.width = this.$el.clientWidth;
return this.height = this.$el.clientHeight;
},
computed: {
layout: function() {
this.x.domain([0, this.data.length]).range([0, this.width]);
this.y.domain([
0, d3.max(this.data, function(d) {
return d.v;
})
]).range([0, this.height]);
return this.data.map((function(_this) {
return function(d, i) {
return {
v: d.v,
x: _this.x(i),
y: _this.y.range()[1] - _this.y(d.v),
width: Math.max(1, _this.x(1) - _this.x(0) - _this.padding),
height: _this.y(d.v)
};
};
})(this));
}
}
});
app = new Vue({
el: '#app',
data: {
values: [
{
v: 10
}, {
v: 20
}, {
v: 30
}
]
},
methods: {
add_random_datapoint: function() {
return this.values.push({
v: Math.random() * 300
});
}
}
});
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment