Skip to content

Instantly share code, notes, and snippets.

@valex
Created October 26, 2020 20:43
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 valex/684386b7373d7015a241001ca8b1d1be to your computer and use it in GitHub Desktop.
Save valex/684386b7373d7015a241001ca8b1d1be to your computer and use it in GitHub Desktop.
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div style="display: flex;
flex-direction: row; justify-content: space-between;">
<div id="chart"></div>
<div id="chart_right"></div>
</div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js" ></script>
<script src="scripts.js"></script>
</html>
function CHART_1_class(id, selector){
this.options = {
selector: selector,
viewBox: [400, 300],
bands: {
left: ["pinky", "ring", "middle", "pointing"],
right: ["pointing", "middle", "ring", "pinky"]
},
colors: {
black: '#1f2c37',
background: '#d7e5ec',
better: '#4bc774',
better_hover: '#76e582',
worse: '#d63a31',
worse_hover: '#eb4a41',
},
groups: ['onPeriodStart', 'onPeriodEnd'],
yScaleDomain: [0, 160],
barStrokeWidth: 2,
paddings: {
main: {
left: 0.2,
bottom: 0.3
}
},
headerHeight: 0.18
}
this.id = id,
this.el = null,
this.aspect = null,
this.onPeriodStartDate = null,
this.originalData = null,
this.data = null,
this.vis = {
svg: null,
defs: null,
background:null,
legends: null,
hand_legends: null,
yAxis: null,
markers:null,
bars: null,
mainRect: { // init values
x: 0,
y: 0,
width: this.options.viewBox[0],
height: this.options.viewBox[1]
},
headerRect: {
x: null,
y: null,
width: null,
height: null,
center: {
x: null,
y: null
}
},
xScale: null,
yScale: null
}
this.el = d3.select(this.options.selector);
this.aspect = this.options.viewBox[0] / this.options.viewBox[1];
window.addEventListener("resize", this.onResize.bind(this), false);
};
CHART_1_class.prototype = {
setData: function(data){
this.originalData = Object.assign({}, data);
this.data = null;
this.prepareData();
},
setOnPeriodStartDate: function(onPeriodStartDate){
this.onPeriodStartDate = onPeriodStartDate;
},
prepareData: function() {
var that = this;
this.data = Object.assign({}, this.originalData);
// build diff
this.data['diff'] = {};
for (var prop in this.data[this.options.groups[1]]) {
if( ! this.data[this.options.groups[1]].hasOwnProperty( prop ) )
continue;
if( typeof this.data[this.options.groups[0]][prop] === 'undefined' )
continue;
this.data['diff'][prop] = this.data[this.options.groups[1]][prop] - this.data[this.options.groups[0]][prop];
}
var diff_entries = Object.entries(this.data['diff']);
this.data['diff_max_key'] = diff_entries[
d3.maxIndex(diff_entries, function(d){
return d[1];
})
][0];
this.data['diff_min_key'] = diff_entries[
d3.minIndex(diff_entries, function(d){
return d[1];
})
][0];
for(var i=0; i < this.options.groups.length; i++){
var group = this.options.groups[i];
// calculate min and max
for (var prop in this.data[group]) {
if( this.data[group].hasOwnProperty( prop ) ) {
if(typeof this.data['maxValue'] === 'undefined'){
this.data['maxValue'] = +this.data[group][prop];
}else{
if(+this.data[group][prop] > this.data['maxValue'])
this.data['maxValue'] = +this.data[group][prop];
}
if(typeof this.data['minValue'] === 'undefined'){
this.data['minValue'] = +this.data[group][prop];
}else{
if(+this.data[group][prop] < this.data['minValue'])
this.data['minValue'] = +this.data[group][prop];
}
}
}
// build entries
this.data[group]['entries'] = Object.entries(this.data[group])
}
},
buildVis: function(){
if( ! this.vis.svg ) this.buildUnchanged();
this.makeCalculations();
this.buildDefs();
this.buildSkeleton();
this.buildLegends();
this.buildAxes();
this.buildMarkers();
this.buildBars();
},
makeCalculations: function(){
var headerPlusMainHeigh = Math.ceil(this.options.viewBox[1] - (this.options.paddings.main.bottom * this.options.viewBox[1]));
this.vis.headerRect.x = 1 + Math.round(this.options.paddings.main.left * this.options.viewBox[0]);
this.vis.headerRect.y = 1;
this.vis.headerRect.width = this.options.viewBox[0] - this.vis.headerRect.x -1;
this.vis.headerRect.height = Math.floor( this.options.headerHeight * headerPlusMainHeigh);
this.vis.headerRect.center.x = this.vis.headerRect.x + this.vis.headerRect.width / 2;
this.vis.headerRect.center.y = this.vis.headerRect.y + this.vis.headerRect.height / 2;
this.vis.mainRect.x = this.vis.headerRect.x;
this.vis.mainRect.y = this.vis.headerRect.y + this.vis.headerRect.height;
this.vis.mainRect.width = this.vis.headerRect.width;
this.vis.mainRect.height = Math.floor(headerPlusMainHeigh - this.vis.headerRect.height);
this.vis.xScale = d3.scaleBand()
.domain(this.options.bands[this.data['hand']])
.rangeRound([this.vis.mainRect.x, this.vis.mainRect.x+this.vis.mainRect.width])
.paddingInner(0.25)
.paddingOuter(0.5);
this.vis.yScale = d3.scaleLinear()
.domain(this.options.yScaleDomain)
.range([
this.vis.mainRect.y + this.vis.mainRect.height,
this.vis.mainRect.y
]);
},
buildMarkers:function(){
var that = this;
this.vis['markers']
.selectAll("g.end")
.data(this.options.bands[this.data['hand']])
.join('g')
.attr('class', function(fingerKey){ return fingerKey; })
.classed('end', true)
.style('opacity', '0')
.each(function(fingerKey){
// text
var text_bounding;
var text = d3.select(this)
.selectAll("text")
.data([ that.data[that.options.groups[1]][fingerKey] ])
.join("text")
.attr("x", function(){return 10})
.attr("y", function(value){return that.vis.yScale( value )})
.attr("dx", 10)
.attr("dy", 1)
.attr("font-size", "1rem")
.attr("fill", that.options.colors.black)
.attr("text-anchor", "start")
.style("alignment-baseline", "middle")
.style("font-weight", "normal")
.attr("class", "noselect")
.text(function(value, i) {
return value+"\u00B0";
})
.each(function(){
text_bounding = d3.select(this).node().getBBox();
})
//rect
var rect_padding = 4;
var rect_bounding;
d3.select(this)
.selectAll("rect")
.data( [ text_bounding ] )
.join("rect")
.attr('rx', 6)
.attr('ry', 6)
.attr('x', function(d){ return d.x - rect_padding })
.attr('y', function(d){ return d.y -rect_padding })
.attr('width', function(d){ return d.width + 2*rect_padding })
.attr('height', function(d){ return d.height +2*rect_padding })
.attr('fill', 'white')
.style('fill-opacity', "1")
.style('stroke-width', '1px')
.style('stroke', function(d, i){
if( that.data.diff[fingerKey] > 0)
return that.options.colors.better;
return that.options.colors.worse;
})
.each(function(){
rect_bounding = d3.select(this).node().getBBox();
})
text.raise();
//line
d3.select(this)
.selectAll('line')
.data([ that.data[that.options.groups[1]][fingerKey] ])
.join("line")
.attr('x1', function(d, i){
return that.vis.xScale(fingerKey) + that.vis.xScale.bandwidth() /2;
})
.attr('y1', function(d, i){
return that.vis.yScale( d )
})
.attr('x2', function(d, i){ return rect_bounding.x + rect_bounding.width })
.attr('y2', function(d, i){
return that.vis.yScale( d )
})
.style('stroke-width', '1px')
.style('stroke', function(d, i){
if( that.data.diff[fingerKey] > 0)
return that.options.colors.better;
return that.options.colors.worse;
})
});
this.vis['markers']
.selectAll("g.start")
.data(this.options.bands[this.data['hand']])
.join('g')
.attr('class', function(fingerKey){ return fingerKey; })
.classed('start', true)
.style('opacity', '0')
.each(function(fingerKey){
// text
var text_bounding;
var text = d3.select(this)
.selectAll("text")
.data([ that.data[that.options.groups[0]][fingerKey] ])
.join("text")
.attr("x", function(){return 10})
.attr("y", function(value){return that.vis.yScale( value )})
.attr("dx", 10)
.attr("dy", 1)
.attr("font-size", "1rem")
.attr("fill", that.options.colors.black)
.attr("text-anchor", "start")
.style("alignment-baseline", "middle")
.style("font-weight", "normal")
.attr("class", "noselect")
.text(function(value, i) {
return value+"\u00B0";
})
.each(function(){
text_bounding = d3.select(this).node().getBBox();
})
//rect
var rect_padding = 4;
var rect_bounding;
d3.select(this)
.selectAll("rect")
.data( [ text_bounding ] )
.join("rect")
.attr('rx', 6)
.attr('ry', 6)
.attr('x', function(d){ return d.x - rect_padding })
.attr('y', function(d){ return d.y -rect_padding })
.attr('width', function(d){ return d.width + 2*rect_padding })
.attr('height', function(d){ return d.height +2*rect_padding })
.attr('fill', 'white')
.style('fill-opacity', "1")
.style('stroke-width', '1px')
.style('stroke', function(d, i){
return that.options.colors.black;
})
.each(function(){
rect_bounding = d3.select(this).node().getBBox();
})
text.raise();
//line
d3.select(this)
.selectAll('line')
.data([ that.data[that.options.groups[0]][fingerKey] ])
.join("line")
.attr('x1', function(d, i){
return that.vis.xScale(fingerKey) + that.vis.xScale.bandwidth() /2;
})
.attr('y1', function(d, i){
return that.vis.yScale( d )
})
.attr('x2', function(d, i){ return rect_bounding.x + rect_bounding.width })
.attr('y2', function(d, i){
return that.vis.yScale( d )
})
.style('stroke-width', '1px')
.style('stroke', function(d, i){
return that.options.colors.black
})
});
},
buildLegends: function(){
var that = this;
var handMarker = this.vis.legends
.selectAll('text')
.data([that.data.hand])
.join("text")
.attr("x", function(){return that.vis.headerRect.x;})
.attr("y", function(){return that.vis.headerRect.center.y;})
.attr("dx", 10)
.attr("dy", 2)
.attr("font-size", "1rem")
.attr("fill", that.options.colors.black)
.attr("text-anchor", "start")
.style("alignment-baseline", "middle")
.style("font-weight", "bold")
.attr("class", "noselect")
.text(function(d) {
switch(d){
case 'left':
return "Левая рука"
break;
default:
return "Правая рука"
break;
}
});
var data = [1, 2];
if(that.onPeriodStartDate){
data = [0, 1, 2];
}
this.vis.legends
.selectAll('circle')
.data( data )
.enter()
.append("circle")
.attr("cx", function(d){
switch(d){
case 0:
return that.vis.headerRect.center.x - 40;
break;
case 1:
return that.vis.headerRect.center.x + 40;
break;
case 2:
return that.vis.headerRect.center.x + 110;
break;
}
})
.attr("cy", that.vis.headerRect.center.y)
.attr("r", function(){return 0.21 * that.vis.headerRect.height / 2})
.attr("fill", function(d){
switch(d){
case 0:
return 'white';
break;
case 1:
return that.options.colors.better;
break;
case 2:
return that.options.colors.worse;
break;
}
})
.style("stroke-width", "2px")
.style("stroke", function(d){
switch(d){
case 0:
return that.options.colors.black;
break;
case 1:
return that.options.colors.better;
break;
case 2:
return that.options.colors.worse;
break;
}
});
this.vis.legends
.selectAll('text.legend-text')
.data( data )
.enter()
.append('text')
.classed("legend-text", true)
.attr("x", function(d){
switch(d){
case 0:
return that.vis.headerRect.center.x-40;
break;
case 1:
return that.vis.headerRect.center.x + 40;
break;
case 2:
return that.vis.headerRect.center.x + 110;
break;
}
})
.attr("y", that.vis.headerRect.center.y)
.attr("dx", 10)
.attr("dy", 2)
.attr("font-size", "0.8rem")
.attr("fill", that.options.colors.black)
.attr("text-anchor", "start")
.style("alignment-baseline", "middle")
.text(function(d) {
switch(d){
case 0:
return that.onPeriodStartDate;
break;
case 1:
return "Лучше"
break;
case 2:
return "Хуже"
break;
}
});
},
buildSkeleton:function(){
var that = this;
this.vis['background'].append('rect')
.attr('rx', 6)
.attr('ry', 6)
.attr('x', this.vis.headerRect.x)
.attr('y', this.vis.headerRect.y)
.attr('width', this.vis.headerRect.width)
.attr('height', this.vis.headerRect.height + this.vis.mainRect.height)
.attr('fill', 'white')
.style('stroke-width', '1px')
.style('stroke', this.options.colors.background)
this.vis['background'].append('line')
.attr('x1', this.vis.mainRect.x)
.attr('y1', this.vis.mainRect.y)
.attr('x2', this.vis.mainRect.x + this.vis.mainRect.width)
.attr('y2', this.vis.mainRect.y)
.style('stroke-width', '1px')
.style('stroke', this.options.colors.background)
// hand labels
this.vis['background'].selectAll('g.label')
.data(this.options.bands[this.data.hand])
.join("g")
.classed('label', true)
.attr("transform",function(fingerKey,i) {
var bbox = that.el.select('#'+that.id+'-hand-left-middle').node().getBBox();
x = that.vis.xScale(fingerKey) + that.vis.xScale.bandwidth()/2 - bbox.width/2;
ymin = that.vis.mainRect.y+that.vis.mainRect.height;
ymax = that.options.viewBox[1];
y = ymin + ((ymax - ymin)/2) - bbox.height/2;
return "translate("+x+","+y+")";
})
.each(function(){
d3.select(this).selectAll("*").remove();
})
.append("use")
.attr("xlink:href",function(fingerKey,i){return "#"+that.id+"-hand-"+that.data.hand+"-"+fingerKey})
},
buildAxes: function(){
var yAxis = d3.axisLeft()
.ticks(5)
.tickSize(this.vis.mainRect.width)
.tickFormat(function(d){
return d + "\u00B0";
})
.scale(this.vis.yScale);
this.vis.yAxis.attr("transform", "translate("+(this.vis.mainRect.x+this.vis.mainRect.width)+",0)")
.call(yAxis)
.call(function(g){
g.select(".domain").remove();
})
.call(function(g){
g.selectAll(".tick:not(:first-of-type) line")
.attr("stroke-opacity", 0.5)
.attr("stroke-dasharray", "2,2")
g.selectAll(".tick:first-of-type line").remove();
})
.call(function(g){
g.selectAll(".tick text")
.style("text-anchor", "end")
.attr("dx", -6)
//.attr("dy", 0)
})
},
buildBars: function(){
var that = this;
var roundRadius = 7;
// clip paths
this.vis.bars.selectAll("clipPath")
.data(this.data[this.options.groups[0]]['entries'])
.join(
function(enter){
return enter
.append("clipPath")
.attr("id", function(d){ return that.id+"-clip-"+d[0]})
.append("path")
.attr("transform",function(d) {
var x = that.vis.xScale(d[0]) + that.options.barStrokeWidth/2;
var y = that.vis.yScale(d[1]) + that.options.barStrokeWidth/2;
return "translate("+x+","+y+")";
})
.attr("d", function(d){
var onEndValue = that.data[that.options.groups[1]][d[0]];
var worse = false;
if ((onEndValue - d[1]) < 0){
worse = true;
}
var width = that.vis.xScale.bandwidth() - that.options.barStrokeWidth;
var height = (that.vis.mainRect.y + that.vis.mainRect.height -1) - that.vis.yScale(d[1]);
this._current = d;
if(worse){
return that.fullRoundedRect( width, height, roundRadius - that.options.barStrokeWidth/2)
}
return that.bottomRoundedRect( width, height, roundRadius)
});
},
function(update){
return update
.call(function(update){
return update
.select("path")
.transition()
.duration(1000)
.attrTween("transform",function(d) {
var intrpl = d3.interpolate(this._current, d);
var x = that.vis.xScale(d[0]) + that.options.barStrokeWidth/2;
return function(t){
var y = that.vis.yScale(intrpl(t)[1]) + that.options.barStrokeWidth/2;
return "translate("+x+","+y+")";
}
})
.attrTween("d", function(d){
var intrpl = d3.interpolate(this._current, d);
this._current = intrpl(1);
return function(t){
var onEndValue = that.data[that.options.groups[1]][d[0]];
var worse = false;
if ((onEndValue - intrpl(t)[1]) < 0){
worse = true;
}
var width = that.vis.xScale.bandwidth() - that.options.barStrokeWidth;
var height = (that.vis.mainRect.y + that.vis.mainRect.height -1) - that.vis.yScale(intrpl(t)[1]);
if(worse){
return that.fullRoundedRect( width, height, roundRadius - that.options.barStrokeWidth/2)
}
return that.bottomRoundedRect( width, height, roundRadius)
}
})
});
},
function(exit){return exit.remove();}
)
this.vis.bars.selectAll("g")
.data(this.options.bands[this.data['hand']])
.join('g')
.each(function(fingerKey){
d3.select(this)
.selectAll("path.on-start")
.data([ that.data[that.options.groups[0]][fingerKey] ])
.join(
function(enter) {
return enter
.append("path")
.classed("on-start", true)
.style("fill", "white")
.style('stroke', that.options.colors.black)
.style('stroke-width', that.options.barStrokeWidth)
.attr("transform",function(value,i) {
var x = that.vis.xScale(fingerKey);
var y = that.vis.yScale(value);
return "translate("+x+","+y+")";
})
.attr("d", function(value){
var onEndValue = that.data[that.options.groups[1]][fingerKey];
var worse = false;
if ((onEndValue - value) < 0){
worse = true;
}
var width = that.vis.xScale.bandwidth()
var height = (that.vis.mainRect.y + that.vis.mainRect.height -1) - that.vis.yScale(value);
if(worse || onEndValue - value == 0){
return that.fullRoundedRect( width, height, roundRadius)
}
return that.bottomRoundedRect( width, height, roundRadius)
})
.attr("_current", function(d){return d})
.on("mouseenter", function(event, value){
that.el.select("g.markers g.start."+fingerKey)
.style('opacity', '1');
})
.on("mouseleave", function(event, value){
that.el.select("g.markers g.start."+fingerKey)
.style('opacity', '0');
});
},
function(update) {
return update
.call(function(update){
return update
.transition()
.duration(1000)
.attr("transform",function(value,i) {
var x = that.vis.xScale(fingerKey);
var y = that.vis.yScale(value);
return "translate("+x+","+y+")";
})
.attrTween("d", function(value){
var i = d3.interpolate(this.getAttribute("_current"), value);
d3.select(this)
.attr("_current", i(1));
return function(t) {
var onEndValue = that.data[that.options.groups[1]][fingerKey];
var worse = false;
if ((onEndValue - value) < 0){
worse = true;
}
var width = that.vis.xScale.bandwidth()
var height = (that.vis.mainRect.y + that.vis.mainRect.height -1) - that.vis.yScale(i(t));
if(worse || onEndValue - value == 0 ){
return that.fullRoundedRect(width, height, roundRadius)
}
return that.bottomRoundedRect(width, height, roundRadius)
};
});
})
},
)
// onPeriodEnd
d3.select(this)
.selectAll("path.on-end")
.data([ that.data[that.options.groups[1]][fingerKey] ])
.join(
function(enter){
return enter
.append("path")
.classed("on-end", true)
.attr("_current", function(d){return d})
.style("fill", function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse
}
return that.options.colors.better
})
.style('stroke', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse
}
return that.options.colors.better
})
.style('stroke-width', '0'/*that.options.barStrokeWidth*/)
.attr("clip-path",function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse) {
return "url(#"+that.id+"-clip-"+fingerKey+")"
}
return null;
})
.attr("d", function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if ((value - onStartValue) == 0){
return null;
}
var x = that.vis.xScale(fingerKey) - that.options.barStrokeWidth/2;
var y = that.vis.yScale(value);
var width = that.vis.xScale.bandwidth() + that.options.barStrokeWidth;
var height = that.vis.yScale(onStartValue) - that.vis.yScale(value);
if(height > that.options.barStrokeWidth/2)
{
height -= that.options.barStrokeWidth/2;
}
this._current_start = onStartValue;
if(worse) {
}
return that.figuredRect(x, y, width, height, roundRadius)
})
.on("mouseenter", function(event, value){
d3.select(this)
.style('stroke', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse_hover;
}
return that.options.colors.better_hover;
})
.style('fill', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse_hover;
}
return that.options.colors.better_hover;
})
that.el.select("g.markers g.end."+fingerKey)
.style('opacity', '1');
})
.on("mouseleave", function(event, value){
d3.select(this)
.style('stroke', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse;
}
return that.options.colors.better;
})
.style('fill', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse;
}
return that.options.colors.better;
})
that.el.select("g.markers g.end."+fingerKey)
.style('opacity', '0');
})
},
function (update){
return update
.style("fill", function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse
}
return that.options.colors.better
})
.style('stroke', function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse){
return that.options.colors.worse
}
return that.options.colors.better
})
.attr("clip-path",function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var worse = false;
if ((value - onStartValue) < 0){
worse = true;
}
if(worse) {
return "url(#"+that.id+"-clip-"+fingerKey+")"
}
return null;
})
.call(function(update){
return update
.transition()
.duration(1000)
.attrTween("d", function(value){
var onStartValue = that.data[that.options.groups[0]][fingerKey];
var intrpl = d3.interpolate(this.getAttribute("_current"), value);
var intrplStartValue = d3.interpolate(this._current_start, onStartValue);
d3.select(this)
.attr("_current", intrpl(1));
this._current_start = intrplStartValue(1);
return function(t){
var x = that.vis.xScale(fingerKey) - that.options.barStrokeWidth/2;
var y = that.vis.yScale(intrpl(t));
var width = that.vis.xScale.bandwidth() + that.options.barStrokeWidth;
var height = that.vis.yScale(intrplStartValue(t)) - that.vis.yScale(intrpl(t)) - that.options.barStrokeWidth/2;
return that.figuredRect(x, y, width, height, roundRadius)
}
});
})
},
function(exit){return exit.remove();}
)
})
.on("mouseenter", function(event, fingerKey){
})
.on("mouseleave", function(event, fingerKey){
})
},
buildDefs: function(){
var that = this;
var active_fingers = [
'left-thumb',
'left-pointing',
'left-middle',
'left-ring',
'left-pinky',
'right-thumb',
'right-pointing',
'right-middle',
'right-ring',
'right-pinky',
];
var fingers = {
left: [
{
x1: 0,
y1: 14,
x2: 0,
y2: 32,
hand: 'left',
finger: 'pinky'
},
{
x1: 6,
y1: 6,
x2: 6,
y2: 32,
hand: 'left',
finger: 'ring'
},
{
x1: 12,
y1: 0,
x2: 12,
y2: 32,
hand: 'left',
finger: 'middle'
},
{
x1: 18,
y1: 5,
x2: 18,
y2: 32,
hand: 'left',
finger: 'pointing'
},
{
x1: 24,
y1: 20,
x2: 24,
y2: 32,
hand: 'left',
finger: 'thumb'
},
],
right: [
{
x1: 24,
y1: 14,
x2: 24,
y2: 32,
hand: 'right',
finger: 'pinky'
},
{
x1: 18,
y1: 6,
x2: 18,
y2: 32,
hand: 'right',
finger: 'ring'
},
{
x1: 12,
y1: 0,
x2: 12,
y2: 32,
hand: 'right',
finger: 'middle'
},
{
x1: 6,
y1: 5,
x2: 6,
y2: 32,
hand: 'right',
finger: 'pointing'
},
{
x1: 0,
y1: 20,
x2: 0,
y2: 32,
hand: 'right',
finger: 'thumb'
},
]
};
this.vis['defs'].selectAll('g')
.data(active_fingers)
.enter()
.append('g')
.attr("id", function(d,i){return that.id+'-hand-'+d})
.each(function(active_finger,i){
d3.select(this).selectAll("line").data(function(){
if(active_finger.indexOf('left') !== -1)
return fingers.left;
else
return fingers.right;
}).enter()
.append("line")
.attr("x1", function(d){return d.x1})
.attr("y1", function(d){return d.y1})
.attr("x2", function(d){return d.x2})
.attr("y2", function(d){return d.y2})
.style("stroke", function(d, i){
if(active_finger == d.hand+'-'+d.finger)
return that.options.colors.better;
else
return that.options.colors.background;
})
.style("stroke-linecap", "round")
.style("stroke-width", "4")
})
},
buildUnchanged: function(){
var that = this;
// create main vis svg
this.vis['svg'] = this.el
.append("svg")
.classed("svg-vis", true)
.attr('xmlns', 'http://www.w3.org/2000/svg')
.attr("viewBox", "0 0 "+this.options.viewBox[0]+" "+this.options.viewBox[1])
.attr("perserveAspectRatio", "xMinYMid")
.on("click", function(event, d){
that.deselectAllAndHide();
})
.append("svg:g")
this.vis['defs'] = this.vis['svg']
.append("defs");
this.vis.background = this.vis['svg'].append("svg:g")
.classed('background', true);
this.vis.legends = this.vis['svg'].append("svg:g")
.classed('legends', true);
this.vis.hand_legends = this.vis['svg'].append("svg:g")
.classed('hand_legends', true);
this.vis.yAxis = this.vis['svg'].append("svg:g")
.classed('y axis', true);
this.vis.markers = this.vis['svg'].append("svg:g")
.classed('markers', true);
this.vis.bars = this.vis['svg'].append("svg:g")
.classed('bars', true);
},
figuredRect: function(x, y, width, height, radius){
if(Math.abs(height) < radius)
radius = Math.floor(Math.abs(height) / 2);
var arcRadius = 6;
var hLength = (width - 2 * radius - 2 * arcRadius) / 2;
if( hLength < 0){
hLength = 0;
arcRadius = (width - 2 * radius) / 2;
if(arcRadius < 0)
arcRadius = 0;
}
if(height < 0){
return "M" + (x ) + "," + y
+ "h" + ((width - 2 * arcRadius) / 2)
+ "a" + arcRadius + "," + arcRadius + " 0 0 1 " + arcRadius + "," + arcRadius
+ "a" + arcRadius + "," + arcRadius + " 0 0 1 " + arcRadius + "," + -arcRadius
+ "h" + ((width - 2 * arcRadius) / 2)
+ "v" + (height)
+ "h" + -width
+ "z"
}
return "M" + (x + radius) + "," + y
+ "h" + (hLength)
+ "a" + arcRadius + "," + arcRadius + " 0 0 0 " + arcRadius + "," + -arcRadius
+ "a" + arcRadius + "," + arcRadius + " 0 0 0 " + arcRadius + "," + arcRadius
+ "h" + (hLength)
+ "a" + radius + "," + radius + " 0 0 1 " + radius + "," + radius
+ "v" + (height - radius)
+ "h" + (-width)
+ "v" + (radius - height)
+ "a" + radius + "," + radius + " 0 0 1 " + radius + "," + -radius;
},
fullRoundedRect: function(width, height, radius){
if(2 * radius > height){
radius = height/2;
}
var path = d3.path();
path.moveTo(radius, 0);
path.lineTo(width - radius, 0);
path.arc(width - radius, radius, radius, -Math.PI / 2, 0 );
path.lineTo(width, height - radius);
path.arc( width - radius, height - radius, radius, 0, Math.PI / 2);
path.lineTo( radius, height);
path.arc( radius, height - radius, radius, Math.PI / 2, Math.PI );
path.lineTo(0, radius);
path.arc(radius, radius, radius, Math.PI , -Math.PI / 2 );
path.closePath();
return path;
},
bottomRoundedRect: function(width, height, radius){
if(radius > height){
radius = height;
}
var path = d3.path();
path.moveTo(0, 0);
path.lineTo( width, 0);
path.lineTo( width, height - radius);
path.arc( width - radius, height - radius, radius, 0, Math.PI / 2);
path.lineTo( radius, height);
path.arc( radius, height - radius, radius, Math.PI / 2, Math.PI );
path.closePath();
return path;
},
deselectAllAndHide: function(){
},
onResize: function (){
this.deselectAllAndHide();
// this.updateSvgWidthAndHeight();
},
updateSvgWidthAndHeight: function (){
var chartElContainer = d3.select(this.options.selector);
var chartEl = d3.select(this.options.selector + " > svg");
var chartContainerBounding = chartElContainer.node().getBoundingClientRect();
var targetWidth = chartContainerBounding.width;
chartEl.attr("width", targetWidth);
chartEl.attr("height", Math.round(targetWidth / this.aspect));
},
};
var id1_data = {
"hand": "left",
"onPeriodStart": {
"pointing": 72.13,
"middle": 75.3,
"ring": 70.5,
"pinky": 76.9
},
"onPeriodEnd": {
"pointing": 79.9,
"middle": 75.4,
"ring": 72.5,
"pinky": 65.6
}
};
var chart_left = new CHART_1_class('id1', '#chart');
chart_left.setOnPeriodStartDate('20.02.20');
chart_left.setData(id1_data);
chart_left.buildVis();
var id2_data = {
"hand": "right",
"onPeriodStart": {
"pointing": 72.13,
"middle": 72.5,
"ring": 70.5,
"pinky": 76.9
},
"onPeriodEnd": {
"pointing": 79.9,
"middle": 72.8,
"ring": 80.5,
"pinky": 75.6
}
};
var chart_right = new CHART_1_class('id2', '#chart_right');
chart_right.setData(id2_data);
chart_right.buildVis();
var newData = {
"hand": "left",
"onPeriodStart": {
"pointing": 62.13,
"middle": 55.3,
"ring": 40.5,
"pinky": 36.9
},
"onPeriodEnd": {
"pointing": 87.9,
"middle": 79.2,
"ring": 23.5,
"pinky": 46.6
}
};
setTimeout(function(){
chart_left.setData(newData);
chart_left.buildVis();
}, 5000);
var newData2 = {
"hand": "left",
"onPeriodStart": {
"pointing": 87.13,
"middle": 83.3,
"ring": 79.5,
"pinky": 99.9
},
"onPeriodEnd": {
"pointing": 95.9,
"middle": 89.2,
"ring": 99.5,
"pinky": 120.6
}
};
setTimeout(function(){
chart_left.setData(newData2);
chart_left.buildVis();
}, 12000)
var newData3 = {
"hand": "left",
"onPeriodStart": {
"pointing": 95.9,
"middle": 89.2,
"ring": 99.5,
"pinky": 120.6
},
"onPeriodEnd": {
"pointing": 87.13,
"middle": 63.3,
"ring": 49.5,
"pinky": 39.9
}
}
setTimeout(function(){
chart_left.setData(newData3);
chart_left.buildVis();
}, 19000)
var newData4 = {
"hand": "left",
"onPeriodStart": {
"pointing": 25.9,
"middle": 134.2,
"ring": 29.5,
"pinky": 32.6
},
"onPeriodEnd": {
"pointing": 97.13,
"middle": 45.3,
"ring": 109.5,
"pinky": 98.9
}
}
setTimeout(function(){
chart_left.setData(newData4);
chart_left.buildVis();
}, 25000)
#chart {
width: 45%;
background-color: #ffffff;
}
#chart_right {
width: 40%;
background-color: #ffffff;
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
.y.axis line{
stroke: #d7e5ec;
}
.y.axis path{
stroke: #d7e5ec;
}
.y.axis text{
fill: #487e98;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment