An exercise that displays three flexible bar chart components linked to the same data, using vue.js.
// 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);
<!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>
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;
}