Skip to content

Instantly share code, notes, and snippets.

@IbrahimTanyalcin
Last active September 30, 2019 23:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save IbrahimTanyalcin/808237e5729ba4720f437fda4eab8085 to your computer and use it in GitHub Desktop.
Save IbrahimTanyalcin/808237e5729ba4720f437fda4eab8085 to your computer and use it in GitHub Desktop.
lexicon-dash
height: 800
width: 800
scrolling: yes

An example of the lexicon dash library. Click on the slider to transform it into a more detailed view. Click one more time on the odometer to transform it back to a slider. The 2 instances have similar input objects. The second one specifies a range function instead of an array. In general each dash input object has:

  • points array of name and value keys
  • range key which might point to an array [x,y] (default [0,1]) or a function
  • an overall value that is between 0 - 1
  • threshold value which is between 0 - 1 (configures the red part on the odometer)
  • categories which names the ends of the slider/odometer

Note: This tool is free to use for Academics and non-commercial purposes as long as the lexicon-component and the white paper is acknowledged and credited.

<!--Copyright Ibrahim Tanyalcin 2013-2017-->
<!DOCTYPE html>
<head>
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1">
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="./lexiconDash.js"></script>
<style type ="text/css">
svg text {
font-family: Helvetica, Arial, "sans-serif";
}
.global_lexMainAxes .tick line,
.global_lexMainAxes path,
.global_lexMainAxes .tick text,
.global_lexMainAxes text{
font: 10px sans-serif;
fill: Black;
stroke: Black;
opacity:0.6;
shape-rendering: crispEdges;
stroke-width: 1px;
}
</style>
</head>
<body>
<div id="containerDiv" style="margin:auto;"></div>
<script type="text/javascript">
!function(){
////////////////////////////////////////////////////////////////////
/////////////////////////A MINIMAL DATASET//////////////////////////
////////////////////////////////////////////////////////////////////
var inputObj = {
points:[
{name:"Charge",value:2},
{name:"Size",value:4},
{name:"Hydrophobicity",value:1},
{name:"SideChain",value:3},
{name:"Blosum62",value:0.5}
],
range:[0,10],
overall:0.7,
threshold:0.7,
categories:["Low","High"]
};
var inputObj2 = {
points:[
{name:"Charge",value:2},
{name:"Size",value:4},
{name:"Hydrophobicity",value:1},
{name:"SideChain",value:3},
{name:"Blosum62",value:0.5}
],
range:function(point,overall){return point.value*point.value},
overall:0.7,
threshold:0.7,
categories:["Low","High"]
};
////////////////////////////////////////////////////////////////////
/////////////////////////CREATE AN INSTANCE/////////////////////////
////////////////////////////////////////////////////////////////////
[inputObj,inputObj2].forEach(function(d,i){
/* An instance is automatically exported
For the second applet create a new instance
from the previous ones constructor*/
(!i
? lexiconDash
: new lexiconDash.constructor
)
// a css selector for the container
.container("#containerDiv")
/* The input data here are inputObj and
inputObj2. The second one has a range
function to transform the values
on the fly. Input method takes 4
arguments: the data object which
has points, range, overall,
threshold and categories keys, the
remaining 3 are optional with the order:
range, categories and threshold. If these
arguments are specified, then they have
priority over same keys inside the input
object. Normally you don't need them.*/
.input(d)
// width in userSpaceOnUse
.w(500)
// height in userSpaceOnUse
.h(300)
// width in pixels
.sW("350px")
// height in pixels
.sH("210px")
// css margin
.sMargin("100px auto")
// give an id string
.lexID(!i ? "lexicon_Applet" : "lexicon_Applet_2")
// color of the applet background
.color("Black")
// opacity of the applet background
.opacity(0)
// set the internal variables
.append()
// render first scene and initialize
.render();
});
}()
</script>
</body>
</html>
<!--Copyright Ibrahim Tanyalcin 2013-2017-->
<!--Lexicon-->
/*Copyright Ibrahim Tanyalcin 2014-2017
Free for academic use.*/
(function (){
function lexiconDashF () {
var ID = ID || "lexicon_"+Math.round(Math.random()*100);
var viewport = undefined;
var viewport_layer0 = undefined;
var viewport_layer1 = undefined;
var viewport_layer2 = undefined;
var gRotateCenter = undefined;
var _input_ = undefined;
var _values_ = [];
var _range_ = undefined;
var _overall_ = undefined;
var _barColor_ = ["Black","DimGray"];
var _colorScale_ = (function(){var interpolator = d3.interpolateRgb("blue","red");return d3.range(10).map(function(d,i){return interpolator(i/9);})})();
var _textColor_ = "DimGray";
var _colorScheme_ = ["Black","Gray"];//fill colors of the flask
var _fillUps_ = undefined;
var _pitchforker_ = undefined;
var _highlight_ = "Orange";
var _threshold_ = 0;
var _categories_ = undefined;
var marker;
var _strokeWidth_ = 10;
var attrX = attrX || 0;
var attrY = attrY || 0;
var attrW = attrW || 100;
var attrH = attrH || 100;
var _refLine_ = [[-50,0],[50,0]];
var styleW = styleW || "100px";
var styleH = styleH || "100px";
var styleMargin = styleMargin || "0px";
var bColor = bColor || "DimGray";
var bOpacity = bOpacity || 0.25;
var _container_ = _container_ || document.body;
var position = position || "relative"
var top = top || "0px";
var left = left || "0px";
var line = d3.svg.line();
var padding = 0.1*attrW;
var onmouse = undefined;
var _this_ = this;
this.configFillUp = function(points){
var total = 0;
var result = [];
var rescaled = [];
for(var i = 0;i<points.length;++i){
var scaled = typeof _range_ === "function" ? _range_(points[i],_overall_) : (points[i].value-_range_[0])/(_range_[1]-_range_[0]);
rescaled.push(scaled);
total+= scaled;
}
for(var i = 0, j = 0;i<points.length;++i){
var by = rescaled[i]/total*_overall_;
result.push({name:points[i].name,_from_:j,by:by});
j += by;
}
return result;
};
this.lexID = function (u){if(arguments.length !== 0){ID=u; return this;}else{return ID;}}
this.x = function (u){attrX=u; return this;}
this.y = function (u){attrY=u; return this;}
this.w = function (u){attrW=u; padding = 0.1*attrW; return this;}
this.h = function (u){attrH=u; padding = 0.1*attrH; return this;}
this.sW = function (u){styleW=u; return this;}
this.sH = function (u){styleH=u; return this;}
this.position = function (u){position=u; return this;}
this.color = function(u){bColor=u;return this;}
this.opacity = function(u){bOpacity=u;return this;}
this.colorScheme = function(u){_colorScheme_ = u;return this;}
this.barColor = function(u){_barColor_ = u;return this;}
this.colorScale = function(w){var args = Array.prototype.slice.call(arguments);args.shift();_colorScale_ = w.apply(_this_,args);return this;}
this.textColor = function(u){_textColor_ = u;return this;}
this.container = function(u){_container_ = u;return this;}
this.sTop = function(u){top = u; return this;}
this.sLeft = function(u){left = u; return this;}
this.sMargin = function(u){styleMargin = u; return this;}
this.input = function(input,range,categories,threshold){if(arguments.length !== 0){_input_ = input; _values_ = input.points; _overall_ = Math.min(Number(input.overall),1); _range_ = range !== undefined ? range : (input.range || [0,1]); _fillUps_ = this.configFillUp(_values_); _categories_ = categories !== undefined ? categories : (input.categories || ["Benign","Deleterious"]); _threshold_ = threshold !== undefined ? threshold : (input.threshold || 0.75); return this;}else{return _input_;}}
var _objSync_ = [];//needed because synctor recursively checks
this.sync = function(){return _objSync_;}////needed because synctor recursively checks
this.onmouse = function(f){if(arguments.length !== 0){onmouse = f.bind(this); return this;}else{return onmouse;}}
this.fillUps = function(){return _fillUps_.slice()}
this.isAppended = false;
this.append = function () {
var svg = d3.select(_container_).append("svg").attr("preserveAspectRatio","none").attr("id",ID).attr("viewBox",attrX+" "+attrY+" "+(attrX+attrW)+" "+(attrY+attrH)).style("width",styleW).style("height",styleH).style("padding","0px").style("display","block").style("position",position).style("top",top).style("left",left).style("overflow","visible").style("line-height","normal").style("margin",styleMargin);
d3.select("#"+ID).append("svg:rect").attr("id",function(){return ID+"_rect";}).attr("x",function(){return (attrX+attrW)/2;}).attr("y",function(){return (attrY+attrH)/2;}).attr("width",0).attr("height",0).attr("rx",15).attr("ry",15).attr("fill-opacity",bOpacity).attr("fill",bColor);
warp(ID+"_rect",attrW,attrH);
//***Defs***
//***Defs***
_refLine_ = [[-attrW/2+padding,0],[attrW/2-padding,0]];
_strokeWidth_ = Math.max(Math.min(attrW,attrH)/20,4);
viewport = d3.select("#"+ID).append("g").attr("transform",function(){return "translate("+(attrW/2)+","+(attrH/2)+")"}).on("click",function(){_this_.render();}); //items in front because they will be below the layer g elements.
viewport.append("g").append("rect").attr("x",-attrW/2).attr("y",-attrH/2).attr("width",attrW).attr("height",attrH).attr("fill-opacity",0).on("click",function(){viewport.on("click")();}); //background rect for ease of interactivity
viewport_layer0 = viewport.append("g");
viewport_layer1 = viewport.append("g");
viewport_layer2 = viewport.append("g");
gRotateCenter = viewport.append("g").attr("transform","translate(0,"+(padding-attrW/2)+") rotate(180)");
marker = new markerObj;
_pitchforker_ = new pitchfork(_refLine_,0,0,1,-2,1.25,0.25,0.2);
beginBar();
this.isAppended = true;
return this;
}
//resusable arrays for AA reference
var aaSymbols = {Nonpolar:"Gray",Polar:"DeepPink",Positive:"Red",Negative:"Blue",Aromatic:"Green",Stop:"Orange"};
var aminoacidsX = {"A":["Alanine","Nonpolar"],"R":["Arginine","Positive"],"N":["Asparagine","Polar"],"D":["Aspartic-Acid","Negative"],"C":["Cysteine","Polar"],"Q":["Glutamine","Polar"],"E":["Glutamic-Acid","Negative"],"G":["Glycine","Nonpolar"],"H":["Histidine","Positive"],"I":["Isoleucine","Nonpolar"],"L":["Leucine","Nonpolar"],"K":["Lysine","Positive"],"M":["Methionine","Nonpolar"],"F":["Phenylalanine","Aromatic"],"P":["Proline","Nonpolar"],"S":["Serine","Polar"],"T":["Threonine","Polar"],"W":["Tryptophan","Aromatic"],"Y":["Tyrosine","Aromatic"],"V":["Valine","Nonpolar"],"X":["Stop","Stop"]};
var aminoacids_OtherProperties = {"A":["Hydrophobic","Aliphatic"],"R":["Hydrophilic","H-bonding","Basic","Ionizable"],"N":["Hydrophilic"],"D":["Hydrophilic","H-bonding","Acidic","Ionizable"],"C":["Hydrophilic","H-bonding","Sulfur-containing","Acidic","Ionizable","Disulfide-bond"],"Q":["Hydrophilic","H-bonding"],"E":["Hydrophilic","H-bonding","Acidic","Ionizable"],"G":["Hydrophobic","Aliphatic"],"H":["Hydrophilic","H-bonding","Basic","Ionizable","All-aromatic"],"I":["Hydrophobic","Aliphatic"],"L":["Hydrophobic","Aliphatic"],"K":["Hydrophilic","H-bonding","Basic","Ionizable"],"M":["Hydrophobic","Sulfur-containing"],"F":["Hydrophobic","All-aromatic"],"P":["Hydrophobic","Aliphatic","Cyclic"],"S":["Hydrophilic","H-bonding"],"T":["Hydrophilic","H-bonding"],"W":["Hydrophobic","H-bonding","All-aromatic"],"Y":["Hydrophobic","H-bonding","Ionizable","All-aromatic"],"V":["Hydrophobic","Aliphatic"]};
this.renderFlask = function () {
this.animComplete = false;
var r = _refLine_[1][0];
var rCoef = 0.6;
var odometer = undefined;
var transitionMaster = d3.select("#"+ID).transition("master").delay(0).duration(500); //WATCH OUT, chained transitions loose the pointer to varibles, I will have to use absolute string selectors here. Tried var.node(), did not work.
transitionMaster.select("#"+ID+"_lexDashMarker").attr("fill-opacity",0).each("end",function(){d3.select(this).attr("visibility","hidden");});
transitionMaster.selectAll("."+ID+"_segments").transition().duration(0).transition().each("start",function(){var property = this.__data__; d3.select(this).transition().each("end",function(){d3.select(this).attr("visibility","hidden");_colorScale_.indexOf(property) === 0?(d3.select("#"+ID+"_lexDashBar").transition().delay(0).duration(1000).call(bend),odometer = new odometerObj):void(0);}).attr("width",0).delay(function(){return (9-_colorScale_.indexOf(property))*50;}).duration(100)}).duration(0);
transitionMaster.selectAll("."+ID+"_indicators").attr("fill-opacity",0).each("end",function(){d3.select(this).attr("visibility","hidden");});
function bend(transition) {
transition
.ease("cubic-out")
.attr("stroke-width",_strokeWidth_*rCoef)
.attr("stroke",_barColor_[1])
.attrTween("d",function(){return function(t){return barToCircle(_refLine_,t,0.5,1,rCoef);}})
.attrTween("transform",function(){return function(t){return t<=0.5?"translate(0,0) rotate(0)":"translate(0,"+(-_refLine_[1][0]*rCoef*2*(t-0.5))+") rotate("+(180*2*(t-0.5))+")";}})
.each("end",function(){_fillUp_();});
}
function odometerObj () {
this.a = 3;
//var _lineHeight_ = 2*(attrH-2*padding)/_fillUps_.length/(rCoef);
var _lineHeight_ = attrH*0.20; //fixed lineHeight
//var _fontSize_ = Math.max(20,Math.min(_lineHeight_/2,40));
var _fontSize_ = r/5;//fixed font-size
var meter = 0;
this.meter = viewport_layer2.append("text")
.text(meter*100+"%")
.attr("x",0)
.attr("y",-r*rCoef-_lineHeight_/4)
.attr("text-anchor","middle")
.attr("font-size",_fontSize_)
.attr("font-family","advent-pro")
.attr("fill",_textColor_)
.attr("fill-opacity",0)
.attr("stroke","none")
.attr("class",ID+"_annotations");
this.meter
.transition()
.ease("cubic-out")
.attr("fill-opacity",0.6)
.delay(0)
.duration(1000);
this.indicators = viewport_layer2.selectAll().data(d3.range(2)).enter().append("text")
.text(function(d,i){return _categories_[d]})
.attr("x",0)
.attr("y",-r*rCoef-_lineHeight_/4)
.attr("dx",function(d,i){return d === 0 ? -r/3 - _strokeWidth_ : r/3 + _strokeWidth_})
.attr("text-anchor",function(d,i){return d === 0 ? "end" : "start"})
.attr("font-size",_fontSize_/2)
.attr("font-family","advent-pro")
.attr("fill",function(d,i){return d===0?_barColor_[1]:"Red"})
.attr("fill-opacity",0)
.attr("stroke","none")
.attr("class",ID+"_annotations");
this.indicators
.transition()
.ease("cubic-out")
.attr("fill-opacity",0.9)
.delay(0)
.duration(1000);
viewport_layer1.selectAll("."+ID+"_gauges").data(d3.range(2))
.enter()
.append("path")
.attr("d",barToCircle([[-r/3,0],[r/3,0]],0))
.attr("stroke",function(d,i){return i===0?_barColor_[1]:"Red"})
.attr("stroke-opacity",0)
.attr("stroke-linecap","butt")
.attr("stroke-dasharray",function(d,i){return i===0?"none":"0 "+(Math.PI*r/3)+" 0"})
.attr("transform","translate(0,"+(-r*rCoef-_lineHeight_/4)+")")
.attr("fill","none")
.attr("stroke-width",function(d,i){return i===0?_strokeWidth_/3:_strokeWidth_/1.5})
.attr("class",ID+"_gauges "+ID+"_annotations")
.transition()
.attrTween("d",function(){return function(t){return barToCircle([[-r/3,0],[r/3,0]],t,1);}})
.attr("stroke-dasharray",function(d,i){return i===0?void(0):"0 "+(Math.PI*r/3*_threshold_)+" "+(Math.PI*r/3*(1-_threshold_))})
.attr("stroke-opacity",1)
.delay(0)
.duration(1000);
this.odometer = viewport_layer1.append("path")
.attr("d","M0,"+(r/50)+" L"+(-r/3)+",0 L0,"+(-r/50)+"Z")
.attr("stroke","none")
.attr("stroke-linejoin","round")
.attr("fill","DodgerBlue")
.attr("fill-opacity",0)
.attr("transform","translate(0,"+(-r*rCoef-_lineHeight_/4)+") rotate(0)")
.attr("class",ID+"_annotations");
this.odometer
.transition()
.attr("fill-opacity",0.9)
.delay(0)
.duration(1000);
this.increaseBy = function (value) {
var interpolatorRotate = d3.interpolate(meter*180,(meter+value)*180);
var interpolatorMeter = d3.interpolate(meter*100,(meter+value)*100);
meter += value;
this.meter.transition().tween("text",function(){return function(t){d3.select(this).text(String(interpolatorMeter(t)).slice(0,4)+"%");}}).delay(0).duration(500);
this.odometer.transition().attrTween("transform",function(){return function(t){return "translate(0,"+(-r*rCoef-_lineHeight_/4)+") rotate("+interpolatorRotate(t)+")"}}).delay(0).duration(500);
}
}
function _fillUp_() {
var fillUps = viewport_layer0.selectAll("."+ID+"_fillUps").data(_values_);
//enter
fillUps
.enter()
.append("path")
.attr("d",function(d,i){return fillUp(_refLine_,0,_fillUps_[i].by,_fillUps_[i]._from_,rCoef)})
.attr("transform","translate(0,"+(-_refLine_[1][0]*rCoef)+") rotate(180)")
.attr("fill",function(d,i){return _colorScheme_[i%_colorScheme_.length]})
.attr("fill-opacity",0.75)
.attr("stroke","none")
.attr("stroke-width",2)
.attr("id",function(d,i){return ID+"_fillUp"+i;})
.attr("class",ID+"_fillUps")
.on("click",function(d,i){d3.event.preventDefault();d3.event.stopPropagation();})
.on("touchstart",function(d,i){/*d3.event.preventDefault();*/d3.event.stopPropagation();})
.on("touchmove",function(d,i){d3.event.preventDefault();d3.event.stopPropagation();})
.on("mouseover",function(d,i){d3.select(this).attr("stroke",_highlight_);d3.select("#"+ID+"_annotationText"+i).node()?d3.select("#"+ID+"_annotationText"+i).attr("fill",_highlight_):void(0);onmouse ? onmouse(d3.event,d,i) : void(0);})
.on("mouseout",function(d,i){d3.select(this).attr("stroke","none");d3.select("#"+ID+"_annotationText"+i).node()?d3.select("#"+ID+"_annotationText"+i).attr("fill",_textColor_):void(0);onmouse ? onmouse(d3.event,d,i) : void(0);})
.transition()
.each("end",function(d,i){i===0?annotate():void(0);odometer.increaseBy(_fillUps_[i].by)})
.attrTween("d",function(d,i){return function(t){return fillUp(_refLine_,t,_fillUps_[i].by,_fillUps_[i]._from_,rCoef)}})
.delay(function(d,i){return i*500;})
.duration(500);
//update
fillUps
.attr("visibility","visible")
.attr("d",function(d,i){return fillUp(_refLine_,0,_fillUps_[i].by,_fillUps_[i]._from_,rCoef)})
.transition()
.each("end",function(d,i){i===0?annotate():void(0);odometer.increaseBy(_fillUps_[i].by)})
.attrTween("d",function(d,i){return function(t){return fillUp(_refLine_,t,_fillUps_[i].by,_fillUps_[i]._from_,rCoef)}})
.delay(function(d,i){return i*500;})
.duration(500);
}
function annotate() {
var _lineHeight_ = 2*(attrH-2*padding)/_fillUps_.length/(r*rCoef);
var base = -((attrH-2*padding)/(r*rCoef)/2+1);
_pitchforker_.reset().lineHeight(_lineHeight_).vBase(base).rCoef(rCoef).points(_refLine_);
var anotLines = viewport_layer2.selectAll("."+ID+"_annotationLines").data(_values_);
//enter only
anotLines
.enter()
.append("path")
.attr("d",null)
.attr("transform","translate(0,"+(-_refLine_[1][0]*rCoef)+") rotate(180)")
.attr("stroke",_textColor_)
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round")
.attr("stroke-dasharray","5 5")
.attr("fill","none")
.attr("stroke-opacity",0.4)
.attr("stroke-width",2)
.attr("class",ID+"_annotationLines "+ID+"_annotations")
.transition()
.attrTween("d",function(d,i){var trajectory = _pitchforker_.from(_fillUps_[i]._from_).height(_fillUps_[i].by).calculate();addText.call(_this_,d,i,trajectory);_pitchforker_.flip();i!==0?_pitchforker_.lever():void(0);return function(t){return labelLine(trajectory,t);}})
.delay(function(d,i){return i*500;})
.duration(450);//important if duration is equal or longer than delay, than pitchfork will get out of sync
}
function addText(data,i,trajectory) {
var _lineHeight_ = 2*(attrH-2*padding)/_fillUps_.length/(rCoef);
var _fontSize_ = Math.max(20,Math.min(_lineHeight_/8,40));
viewport_layer2
.append("text")
.attr("font-size",_fontSize_)
.attr("font-family","advent-pro")
.attr("fill",_textColor_)
.attr("stroke","none")
.attr("id",function(){return ID+"_annotationText"+i;})
.attr("class",ID+"_annotationTexts "+ID+"_annotations")
.on("click",function(d,i){d3.event.preventDefault();d3.event.stopPropagation();})
.on("touchstart",function(d,i){/*d3.event.preventDefault();*/d3.event.stopPropagation();})
.on("touchmove",function(d,i){d3.event.preventDefault();d3.event.stopPropagation();})
.on("mouseover",function(){d3.select(this).attr("stroke",_highlight_);d3.select("#"+ID+"_fillUp"+i).node()?d3.select("#"+ID+"_fillUp"+i).attr("fill",_highlight_):void(0);onmouse ? onmouse(d3.event,data,i) : void(0);})
.on("mouseout",function(){d3.select(this).attr("stroke","none");d3.select("#"+ID+"_fillUp"+i).node()?d3.select("#"+ID+"_fillUp"+i).attr("fill",_colorScheme_[i%_colorScheme_.length]):void(0);onmouse ? onmouse(d3.event,data,i) : void(0);})
.transition()
.each("end",function(){i===_values_.length-1 ? _this_.animComplete = _this_.renderBar : void(0);})
.tween("keyboard",function(){var selection = d3.select(this);/*var trajectory = _pitchforker_.calculate();_pitchforker_.flip();i!==0?_pitchforker_.lever():void(0);*/return function(t){selection.call(labelText,trajectory,t,data.name,_fillUps_[i].by*100,(-r*rCoef))}})
.delay(450)
.duration(500);
}
}
this.renderBar = function abc() {
//console.log("hehe");
this.animComplete = false;
var r = _refLine_[1][0];
var rCoef = 0.6;
var length = _values_.length;
var barPadding = 0.05;
var barWidth = 2*r/((1+barPadding)*10+barPadding);
var transitionMaster = d3.select("#"+ID).transition("master").delay(0).duration(500);
transitionMaster.selectAll("."+ID+"_annotations").attr("fill-opacity",0).attr("stroke-opacity",0).each("end",function(){d3.select(this).remove()});
transitionMaster.selectAll("."+ID+"_fillUps").transition().duration(0).transition().each("start",function(d,i){
d3.select(this)
.transition()
.ease("linear")
.each("end",function(){
d3.select(this).attr("visibility","hidden");
i === 0 ? d3.select("#"+ID+"_lexDashBar").transition().delay(0).duration(1000).call(unbend): void(0);
})
.attrTween("d",function(){return function(t){return fillUp(_refLine_,(1-t),_fillUps_[i].by,_fillUps_[i]._from_,rCoef)}})
.delay(function(){return (length-1-i)*100})
.duration(100)
}).duration(0);
function unbend(transition) {
transition
.ease("cubic-in")
.attr("stroke-width",_strokeWidth_)
.attr("stroke",_barColor_[0])
.attrTween("d",function(){return function(t){return circleToBar(_refLine_,t,0.5,rCoef,1);}})
//.attrTween("transform",function(){return function(t){return t<=0.5?"translate(0,0) rotate(0)":"translate(0,"+(-_refLine_[1][0]*rCoef*2*(t-0.5))+") rotate("+(180*2*(t-0.5))+")";}})
.attrTween("transform",function(){return function(t){return t<=0.5?"translate(0,"+(-_refLine_[1][0]*rCoef*2*(0.5-t))+") rotate("+(180*2*(0.5-t))+")" : "translate(0,0) rotate(0)";}})
.each("end",function(){
d3.select("#"+ID+"_lexDashMarker").transition().attr("fill-opacity",1).each("start",function(){d3.select(this).attr("visibility","visible");}).delay(0).duration(500);
d3.selectAll("."+ID+"_segments").transition().each("end",function(d,i){i === _colorScale_.length-1 ? _this_.animComplete = _this_.renderFlask : void(0);}).attr("width",barWidth).attr("visibility","visible").delay(function(d,i){return i*50;}).duration(100);
d3.selectAll("."+ID+"_indicators").transition().attr("fill-opacity",0.9).each("start",function(){d3.select(this).attr("visibility","visible");}).delay(0).duration(500);
});
}
}
this.animComplete = false;
this.render = function () {
this.animComplete ? this.animComplete() : void(0);
}
//###############################################################INVOKED WITHIN APPEND###############################################################
function beginBar () {
var r = _refLine_[1][0];
var transitionMaster = d3.select("#"+ID).transition("master").delay(0).duration(1500); //WATCH OUT, chained transitions loose the pointer to varibles, I will have to use absolute string selectors here. Tried var.node(), did not work.
var barPadding = 0.05;
var barWidth = 2*r/((1+barPadding)*10+barPadding);
var segments = viewport_layer1.selectAll("."+ID+"_segments").data(_colorScale_);
viewport_layer1.append("path").attr("id",ID+"_lexDashBar").attr("d",barToCircle([[0,0],[0,0]],0)).attr("stroke",_barColor_[0]).attr("stroke-opacity",0.9).attr("stroke-linecap","round").attr("fill","none").attr("stroke-width",_strokeWidth_);
segments
.enter()
.append("rect")
.attr("width",0)
.attr("height",_strokeWidth_*0.75)
.attr("x",function(d,i){return barWidth*(i*(1+barPadding)+barPadding)-r;})
.attr("y",-_strokeWidth_*0.45)
.attr("rx","1%")
.attr("ry","1%")
.attr("stroke","none")
.attr("class",ID+"_segments")
.attr("fill",function(d,i){return _colorScale_[i]});
viewport_layer1.selectAll("."+ID+"_indicators").data(d3.range(5)).enter().append("text")
.text(function(d,i){
if (d<2) {
return _categories_[d];
} else if (d>=2 && d<4) {
return ["0%","100%"][d-2];
} else {
return String(_overall_*100).slice(0,4)+"%";
}
})
.attr("x",function(d,i){
if (d % 2 === 0 && d<4) {
return barWidth*(barPadding)-r;
} else if (d % 2 === 1 && d<4) {
return barWidth*((_colorScale_.length)*(1+barPadding)+barPadding)-r;
} else {
return 2*r*_overall_-r;
}
})
.attr("y",function(d,i){
if (d < 2) {
return _strokeWidth_*3;
} else if (d>=2 && d<4) {
return _strokeWidth_*5;
} else {
return _strokeWidth_*-3;
}
})
.attr("text-anchor",function(d,i){return d === 0 ? "middle" : "middle"})
.attr("font-size",r/10)
.attr("font-family","advent-pro")
.attr("fill",function(d,i){
if (d % 2 === 0 && d<4) {
return _barColor_[1];
} else if (d % 2 === 1 && d<4) {
return "Red";
} else {
return _colorScale_[Math.max(0,Math.min(_colorScale_.length-1,~~(_colorScale_.length*_overall_)))];
}
return d===0?_barColor_[1]:"Red"
})
.attr("fill-opacity",0)
.attr("stroke","none")
.attr("class",ID+"_indicators")
.attr("visibility","hidden");
transitionMaster.select("#"+ID+"_lexDashBar").ease("cubic-out").attrTween("d",function(){ var interpolator = d3.interpolateArray([[0,0],[0,0]],_refLine_);return function(t){return barToCircle(interpolator(t),0);}});
transitionMaster.select("#"+ID+"_lexDashMarker").transition().duration(0).transition().each("start",function(){d3.select(this).attr("visibility","visible");}).attr("transform", function(){return "translate("+(2*r*_overall_-r)+",0)"+" scale("+(_strokeWidth_*1.25)+","+(_strokeWidth_*1.25)+")"}).duration(500);
transitionMaster.selectAll("."+ID+"_segments").transition().duration(0).transition().each("start",function(){var property = this.__data__; d3.select(this).transition().each("end",function(){_colorScale_.indexOf(property) === _colorScale_.length-1?_this_.animComplete = _this_.renderFlask:void(0);}).attr("width",barWidth).delay(function(){return _colorScale_.indexOf(property)*50;}).duration(100)}).duration(0);
transitionMaster.selectAll("."+ID+"_indicators").transition().duration(0).transition().ease("cubic-out").each("start",function(){d3.select(this).attr("visibility","visible");}).attr("fill-opacity",0.9).duration(500);
}
function markerObj () {
this.unit = 1;
var sqrt3 = Math.sqrt(3);
var markerString = this.markerString = (function(){return "M"+-(this.unit)/4+","+((this.unit*0.75)*sqrt3)+"L"+-(this.unit)+","+0+"A"+(2*this.unit/sqrt3)+","+(2*this.unit/sqrt3)+" 0 1,1 "+(this.unit)+",0 L"+(this.unit)/4+","+((this.unit*0.75)*sqrt3)+"L"+(this.unit)/4+","+((this.unit*0.25)*sqrt3)+"A"+(this.unit)/2+","+(this.unit)/2+" 0 1,0 "+-(this.unit)/4+","+((this.unit*0.25)*sqrt3)+"Z"}).bind(this)();
this.marker = viewport.append("path").attr("id",ID+"_lexDashMarker").attr("d",markerString).attr("transform",function(){return "scale("+(_strokeWidth_*1.25)+","+(_strokeWidth_*1.25)+")"}).attr("fill","Red").attr("fill-opacity",0.8).attr("visibility","hidden");
this.node = this.marker.node();
}
//###############################################################INVOKED WITHIN APPEND###############################################################
//subs for animation
function barToCircle (points,t,bendDur,rCoefStart,rCoefEnd) {
rCoefStart = rCoefStart || 1;
rCoefEnd = (rCoefEnd * 1/rCoefStart) || 1/rCoefStart;
bendDur = bendDur || 0.5;
var dx = 0.0001;
var r = (points[1][0]-points[0][0])/2*rCoefStart;
var R = 100*r;
if (t<=bendDur) {
return "M"+(-r)+","+points[0][1]+" A"+(R-(R-r)*1/bendDur*t)+","+(R-(R-r)*1/bendDur*t)+" 0 0,1 "+(r)+","+points[1][1];
} else {
return "M"+(-r+1/(1-bendDur)*r*(t-bendDur)-dx)+","+points[0][1]+" A"+(r-(r*(1-rCoefEnd))*(t-bendDur)/(1-bendDur))+","+(r-(r*(1-rCoefEnd))*(t-bendDur)/(1-bendDur))+" 0 1,1 "+(r-1/(1-bendDur)*r*(t-bendDur)+dx)+","+points[1][1];
}
}
function circleToBar (points,t,ungripDur,rCoefStart,rCoefEnd) {
rCoefStart = rCoefStart || 1;
rCoefEnd = (rCoefEnd * 1/rCoefStart) || 1/rCoefStart;
ungripDur = ungripDur || 0.5;
var dx = 0.0001;
var r = (points[1][0]-points[0][0])/2*rCoefStart;
var R = 100*r;
if (t<=ungripDur) {
//return "M"+(-1/ungripDur*r*rCoefEnd*t+dx)+","+points[0][1]+" A"+(r-(r*(1-rCoefEnd))*t/(ungripDur))+","+(r-(r*(1-rCoefEnd))*t/(ungripDur))+" 0 1,1 "+(1/(ungripDur)*r*rCoefEnd*t-dx)+","+points[1][1];
return "M"+(-1/ungripDur*r*rCoefEnd*t-dx)+","+points[0][1]+" A"+(r-(r*(1-rCoefEnd))*t/(ungripDur))+","+(r-(r*(1-rCoefEnd))*t/(ungripDur))+" 0 1,1 "+(1/(ungripDur)*r*rCoefEnd*t+dx)+","+points[1][1];
} else {
r *= rCoefEnd;
R *= rCoefEnd;
return "M"+(-r)+","+points[0][1]+" A"+(r+(R-r)*1/(1-ungripDur)*(t-ungripDur))+","+(r+(R-r)*1/(1-ungripDur)*(t-ungripDur))+" 0 0,1 "+(r)+","+points[1][1];
}
}
function fillUp (points,t,height,_from_,rCoef) {
_from_ = _from_ || 0;
rCoef = rCoef || 1;
var totalHeight = (points[1][0]-points[0][0])*rCoef;
var r = totalHeight/2;
height *= t;
var A = [-Math.sqrt(r*r-r*r*Math.pow((1-2*_from_),2)),-2*r*(1-_from_)];
var B = [Math.sqrt(r*r-r*r*Math.pow((1-2*_from_),2)),-2*r*(1-_from_)];
var D = [-Math.sqrt(r*r-r*r*Math.pow((1-2*_from_-2*height),2)),-2*r*(1-_from_-height)];
var C = [Math.sqrt(r*r-r*r*Math.pow((1-2*_from_-2*height),2)),-2*r*(1-_from_-height)];
return "M"+A.toString()+" L"+B.toString()+" A"+r+","+r+" 0 0,1 "+C.toString()+" L"+D.toString()+" A"+r+","+r+" 0 0,1 "+A.toString()+"Z";
}
function pitchfork (points,height,_from_,rCoef,vBaselineInR,hBaselineInR,tickLengthInR,lineHeight) {
rCoef = rCoef || 1;
var countR = 0;
var countL = 0;
var totalHeight = (points[1][0]-points[0][0])*rCoef;
var r = totalHeight/2;
var flip = -1;
_from_ = _from_ || 0;
vBaselineInR = vBaselineInR || -2;
hBaselineInR = hBaselineInR || -1.6;
tickLengthInR = tickLengthInR || 0.1;
lineHeight = lineHeight || 0.1;
this.from = function(u){if(u !== undefined){_from_ = u;return this;}else{return _from_;}};
this.rCoef = function(u){if(u !== undefined){rCoef = u;return this;}else{return rCoef;}};
this.points = function(u){if(u !== undefined){points = u;totalHeight = (points[1][0]-points[0][0])*rCoef;r = totalHeight/2;return this;}else{return points;}};
this.vBase = function(u){if(u !== undefined){vBaselineInR = u;return this;}else{return vBaselineInR;}};
this.hBase = function(u){if(u !== undefined){hBaselineInR = u;return this;}else{return hBaselineInR;}};
this.tick = function(u){if(u !== undefined){tickLengthInR = u;return this;}else{return tickLengthInR;}};
this.lineHeight = function(u){if(u !== undefined){lineHeight = u;return this;}else{return lineHeight;}};
this.height = function(u){if(u !== undefined){height = u;return this;}else{return height;}};
this.from = function(u){if(u !== undefined){_from_ = u;return this;}else{return _from_;}};
this.flip = function(){flip *= -1;return this;};
this.lever = function(){flip === -1?countR++:countL++;return this;};
this.reset = function(){flip = -1;countR = 0;countL=0;return this;}
this.calculate = function() {
var count = flip === -1?countR:countL;
var horizontalDev = Math.sqrt(0.5*0.5-Math.pow((0.5-(_from_+height/2)),2))*0.8;//0.8 or any other coef is 'insidedness'
var start = [2*r*horizontalDev*flip,-2*r*(1-height/2-_from_)];
var joint = [r*hBaselineInR*flip,r*vBaselineInR+count*lineHeight*r];
var end = [joint[0]+tickLengthInR*r*flip,joint[1]];
return [start,joint,end];
}
}
function labelLine (pitchfork,t,tickDur) {
tickDur = tickDur || 0.1;
var startJointDuration = 1 - tickDur;
var start = pitchfork[0];
var joint = pitchfork[1];
var end = pitchfork[2];
if(t<= startJointDuration) {
return "M"+start.toString()+" L"+(start[0]+(joint[0]-start[0])*t/startJointDuration)+","+(start[1]+(joint[1]-start[1])*t/startJointDuration);
} else {
return "M"+start.toString()+" L"+joint.toString()+" L"+(joint[0]+(end[0]-joint[0])*(t-startJointDuration)/tickDur)+","+end[1];
}
}
function labelText (selection,pitchfork,t,text,percentage,ty) {
var length = text.length;
var mapped = pitchfork.map(function(d,i){return [-d[0],-d[1]+ty]});
selection.text(text.slice(0,Math.ceil(t*length))+": "+String(percentage*t).slice(0,4)+"%").attr("text-anchor",function(){if(mapped[2][0]<0){return "end";}else{return "start";}}).attr("x",mapped[2][0]).attr("y",mapped[2][1]);
}
function dashAnimateCircle(dataset,direction){
}
//subs, mostly from I-PV
function warp (ID,width,height) {
//console.log(ID+" "+width+" "+height+" !");
d3.select("#"+ID).transition("adjustX").attr("x",function(){var x = parseInt(d3.select(this).attr("x"));return x-width/2;}).delay(0).duration(500);
d3.select("#"+ID).transition("adjustY").attr("y",function(){var y = parseInt(d3.select(this).attr("y"));return y-height/2;}).delay(0).duration(500);
d3.select("#"+ID).transition("adjustW").attr("width",width).delay(0).duration(500);
d3.select("#"+ID).transition("adjustH").attr("height",height).delay(0).duration(500);
//d3.select("#"+ID).transition("adjustFO").attr("fill-opacity",0.6).delay(0).duration(1000);
}
//bound unwarp, anti-warp
this.unwarp = function (f) {
viewBox = d3.select("#"+ID).attr("viewBox");
viewBoxFinal = viewBox.split(" ").map(function(d,i){return d*100}).join(" ");
d3.select("#"+ID).transition("shrink").each("end",function(){d3.select(this).remove();if(typeof f === "function"){return f.bind(_this_)();}}).tween("unwarp",function(){var interpolator = d3.interpolate(viewBox,viewBoxFinal);return function(t){d3.select(this).attr("viewBox",interpolator(t))}}).delay(0).duration(3000);
d3.select("#"+ID).transition("fadeAway").style("opacity",0).delay(0).duration(1000);
}
}
window.lexiconDash = new lexiconDashF;
})();
<!--Lexicon-->
/*Copyright Ibrahim Tanyalcin 2014-2017
Free for academic use.*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment