Skip to content

Instantly share code, notes, and snippets.

@abueloshika
Last active February 28, 2018 13:42
Show Gist options
  • Save abueloshika/89609d5dcfc82804f894edde703f752b to your computer and use it in GitHub Desktop.
Save abueloshika/89609d5dcfc82804f894edde703f752b to your computer and use it in GitHub Desktop.
stack chart
import Ember from 'ember';
import {
computed
} from '@ember/object';
import Component from 'ember-component';
import {
select, mouse
} from 'd3-selection';
import {
scaleBand,
scaleLinear,
scaleOrdinal,
schemeCategory10
} from 'd3-scale';
import {
max,
median,
min
} from 'd3-array';
import {
stack,
stackOffsetExpand,
stackOffsetDiverging
} from 'd3-shape';
import {
transition
} from 'd3-transition';
import {
ease,
easeLinear
} from 'd3-ease';
import {
axisBottom,
axisLeft
} from 'd3-axis';
import {
or
} from '@ember/object/computed';
export default Component.extend({
data: [{label: "label1", count1: "10", count2: "15", count3: "9"},
{label: "label2", count1: "5", count2: "35", count3: "22"},
{label: "label3", count1: "43", count2: "23", count3: "13"}],
legend: null,
highlightedCount1: or('selectedCount1', 'hoveredCount'),
highlightedCount2: or('selectedCount2', 'hoveredCount'),
highlightedCount3: or('selectedCount3', 'hoveredCount'),
highlightedLabel: or('selectedLabel', 'hoveredLabel'),
didInsertElement() {
this.buildChart()
this.set('didRenderChart', true);
},
didUpdateAttrs() {
this.buildChart()
},
buildChart() {
let data = this.get('data')
let div = select('body')
.append("div")
.attr("class", "stack-tooltip")
let series = stack()
.keys(["count1", "count2", "count3"])
.offset(stackOffsetDiverging)
(data);
// svg = select(this.$('svg')[0])
// .selectAll("*")
// .remove()
let svg = select(this.$('svg')[0]),
margin = {
top: 20,
right: 30,
bottom: 30,
left: 60
},
width = +svg.attr("width"),
height = +svg.attr("height");
let x = scaleBand()
.domain(data.map(function(d) {
return d.label;
}))
.rangeRound([margin.left, width - margin.right])
.padding(0.1);
let y = scaleLinear()
.domain([min(series, stackMin), max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
let z = scaleOrdinal().range(['#DAEAF1', '#99CFE0', '#72BCD4']);
svg.append("g")
.selectAll("g")
.data(series)
.enter().append("g")
.attr("fill", function(d) {
return z(d.key);
})
.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("width", x.bandwidth)
.attr("x", function(d) {
return x(d.data.label);
})
.attr("y", function(d) {
return y(d[1]);
})
.attr("height", function(d) {
return y(d[0]) - y(d[1]);
})
.attr('opacity', d => {
let selected = this.get('selectedLabel');
return (selected && d.data.label !== selected) ? '0.5' : '1.0';
})
.on("mousemove", function(d) {
let mouseVal = mouse(this);
div
.html("Clerked within 1 Hour: " + d.data.count1 + "</br>" + "Clerked within 2 Hours: " + d.data.count2 + "</br>" +"Clerked within 3 Hours: " + d.data.count3 + "</br>")
.style("left", (event.pageX + 12) + "px")
.style("top", (event.pageY - 10) + "px")
.style("opacity", 1)
.style("display", "block");
})
.on("mouseout", function() {
div.html(" ").style("display", "none");
this.set('hoveredLabel', null);
this.set('hoveredCount', null);
})
.on('mouseover', d => {
this.set('hoveredLabel', d.data.label);
this.set('hoveredCount', d.data.count1);
})
.on('click', d => {
let clickedLabel = d.data.label;
let clickedCount1 = d.data.count1;
let clickedCount2 = d.data.count2;
let clickedCount3 = d.data.count3;
if (this.get('on-click')) {
this.get('on-click')(clickedLabel);
this.set('selectedCount1', clickedCount1);
this.set('selectedCount2', clickedCount2);
this.set('selectedCount3', clickedCount3);
} else {
if (clickedLabel === this.get('selectedLabel')) {
this.set('selectedLabel', '');
this.set('selectedCount', '');
} else {
this.set('selectedLabel', clickedLabel);
this.set('selectedCount1', clickedCount1);
this.set('selectedCount2', clickedCount2);
this.set('selectedCount3', clickedCount3);
}
this.buildChart();
}
})
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.attr("class", "axisWhite")
.call(axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.attr("class", "axisWhite")
.call(axisLeft(y));
function stackMin(h) {
return min(h, function(d) {
return d[0];
});
}
function stackMax(h) {
return max(h, function(d) {
return d[1];
});
}
if (legend != null){
var legend = svg.selectAll(".legend")
.data(series.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) {
return z(d.key);
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d.key;
});
}
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle'
});
<svg width='800' height="300"></svg>
<!-- <div id="tooltip"></div> -->
{{#if selectedLabel}}
{{highlightedLabel}} {{highlightedCount1}}/{{highlightedCount2}}/{{highlightedCount3}}
{{/if}}
import Ember from 'ember';
export default function destroyApp(application) {
Ember.run(application, 'destroy');
}
import Resolver from '../../resolver';
import config from '../../config/environment';
const resolver = Resolver.create();
resolver.namespace = {
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix
};
export default resolver;
import Ember from 'ember';
import Application from '../../app';
import config from '../../config/environment';
const { run } = Ember;
const assign = Ember.assign || Ember.merge;
export default function startApp(attrs) {
let application;
let attributes = assign({rootElement: "#test-root"}, config.APP);
attributes = assign(attributes, attrs); // use defaults, but you can override;
run(() => {
application = Application.create(attributes);
application.setupForTesting();
application.injectTestHelpers();
});
return application;
}
import resolver from './helpers/resolver';
import {
setResolver
} from 'ember-qunit';
setResolver(resolver);
{
"version": "0.13.0",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.16.2",
"ember-template-compiler": "2.16.2",
"ember-testing": "2.16.2"
},
"addons": {
"ember-data": "2.16.3"
"ember-d3": "^0.4.2",
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment