Skip to content
Snippets Groups Projects
Commit 0dc5133c authored by Ibrahim Roshan Kunnakkattu's avatar Ibrahim Roshan Kunnakkattu
Browse files

:bug: fix scale, color and animation issues of highlighting circles

parent 6235d006
No related branches found
No related tags found
1 merge request!5Refactored code for diplaying aggregated ligand interactions
......@@ -136,10 +136,11 @@ class Depiction {
.attr('d', x => `M ${x.bgn.position.x},${x.bgn.position.y} ${x.end.position.x},${x.end.position.y}`)
.attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`)
}
}
}
/**
* Adds circles around atoms corresponding to the value of
* their weights.The size, color and number of crcles around
* their weights.The size, color and number of circles around
* atom indicates the strength of weight. Currently maximum of
* three circles are drawn
* @param {any} weights objects with atom names and value of weight
......@@ -147,31 +148,18 @@ class Depiction {
* @memberof Depiction
*/
public addCircles(weights: any, colorScheme: string): void {
public addCircles(weights: any): void {
this.atoms.forEach(x => {
/**
/**
* This has been changed so we can highlight every Atom
*/
let valueTo = weights.filter(y => y.atom == x.name).map(z => z.value)[0];
if (valueTo === undefined) valueTo = '0.00';
if (valueTo === undefined) valueTo = 0.00;
x.value = valueTo;
});
const data = this.atoms;
const intxWeights = weights.map(x => x.value);
const gradient = new Model.Gradient(intxWeights, colorScheme).getScales();
const q1 = d3.quantile(intxWeights, 0.25);
const q3 = d3.quantile(intxWeights, 0.75);
const firstScale = gradient.firstScale;
const secondScale = gradient.secondScale;
const thirdScale = gradient.thirdScale;
const colorScale = d3.scaleLinear(
[0, 0.01, d3.max(data.map(x => x.value))],
["#ffffff","#a0bb9e","#505d4f"]
);
const scales = this.getScale();
this.weight.selectAll("*").remove();
/**
* Here is your original weight drawing function
......@@ -211,26 +199,16 @@ class Depiction {
.attr("cx", x => x.position.x)
.attr("cy", x => x.position.y)
/**
* I've replaced the radiusScale to be the same as the first
* weight drawing function (not sure if this is the best)
*/
// .attr("r", x => firstScale.radiusScale(x.value))
.attr("r", (x) => {
if(x.value >= q1) return secondScale.radiusScale(x.value);
if(x.value >= q3) return thirdScale.radiusScale(x.value);
return firstScale.radiusScale(x.value);
})
/**
* Fill now uses the same colorScale of the heatmap component
* set a custom value of radius for values of zero
* to be able to highlight them
*/
// .attr("fill", x=> firstScale.colorScale(x.value))
.attr("fill", x=> colorScale(x.value))
.attr("r", x => x.value > 0 ? scales.radiusScale(x.value): 15)
.attr("fill", x=> x.value > 0 ? scales.colorScale(x.value): '#ffffff')
/**
* Since this is drawn below "structure" I've noticed fill-opacity
* does not change anything actually
*/
// .attr("fill-opacity", "0.5")
.attr("fill-opacity", "1.0")
.attr("fill-opacity", "1")
/**
* This is a fill-opacity function if we want to drawn "weight"
* on top of "structure"
......@@ -270,6 +248,36 @@ class Depiction {
// });
}
/**
* Generate scale of values for the radius and color
* of circles representing the weight of atoms
* @private
* @memberof Depiction
*/
private getScale() {
/**
* scales are generated for only non-zero values.
* keeping zero as the minimum value of domain will generate
* very small radius which cannot be highlighted, alternatively
* if the minimum value of range is increased, this will lead to
* very high value of maximum of the range, that is not suitable
*/
const weights = this.atoms.map(x => x.value).filter(x => x > 0)
const weightMax = d3.max(weights);
const weightMin = d3.min(weights);
const radiusScale = d3.scaleSqrt([weightMin, weightMax], [10,30]);
const colorScale = d3.scaleSqrt(
[weightMin, 0.01, weightMax],
["#f0fcf0","#a0bb9e","#505d50"]
);
return {
"radiusScale": radiusScale,
"colorScale": colorScale
}
}
/**
* Appends to a given selection the visual representation of
* bonds as svg:path elements.
......@@ -385,47 +393,55 @@ class Depiction {
private highlightAtom(element) {
this.removeHighlights();
const data = this.atoms;
const radiusScale = d3.scaleLinear(
[0, d3.max(data.map(x => x.value))],
[15, 30]
)
d3.select(element)
const scales = this.getScale()
const selectedCircle = d3.select(element)
.classed("selectedCircle", true)
.classed("isAnimating", true)
.style("stroke", "#FBBD1D")
.style("stroke-width", 5);
function animateStroke() {
if (d3.select('.selectedCircle').classed("isAnimating")) {
d3.select('.selectedCircle').transition()
.duration(500) // 500 milliseconds
.style("stroke-width", 10)
.attr("r", (d:Atom) => radiusScale(d.value)*1.3) // Double the size
.transition()
.duration(500) // 500 milliseconds
.style("stroke-width", 5)
.attr("r", (d:Atom) => radiusScale(d.value))// Revert to original size
.on("end", animateStroke)
}
if (selectedCircle.classed("selectedCircle")) {
selectedCircle.transition()
.duration(500) // 500 milliseconds
.style("stroke-width", 10)
.attr("r", () => {
const d = selectedCircle.datum() as Atom; // Access bound data
if(d.value > 0){
return scales.radiusScale(d.value)* 1.5; // Increase size
}
return 30
})
.transition()
.duration(500) // 500 milliseconds
.style("stroke-width", 5)
.attr("r", () => {
const d = selectedCircle.datum() as Atom;
if(d.value > 0){
return scales.radiusScale(d.value); // Revert to original size
}
return 15
})
.on("end", animateStroke) // Loop animation
}
}
animateStroke();
}
private removeHighlights(){
const data = this.atoms;
const radiusScale = d3.scaleLinear(
[0, d3.max(data.map(x => x.value))],
[15, 30]
)
d3.selectAll(".selectedCircle")
.classed("selectedCircle", false)
.classed("isAnimating", false)
const scales = this.getScale();
const selectedCircle = d3.selectAll(".selectedCircle");
selectedCircle.classed("selectedCircle", false)
.interrupt()
.attr("r", (d:Atom) => radiusScale(d.value))
.attr("r", () => {
const d = selectedCircle.datum() as Atom;
if(d.value > 0){
return scales.radiusScale(d.value); // Revert to original size
}
return 15
})
.style("stroke", null);
}
......@@ -445,7 +461,7 @@ class Depiction {
}
/**
* Mouse leave event handler for circlea round atoms
* Mouse leave event handler for circles around atoms
* depicting their weights
* @public
* @param {boolean} propagation if event should be triggered on external components
......@@ -470,7 +486,7 @@ class Depiction {
const e = new CustomEvent(eventName, {
bubbles: true,
detail: {
tooltip: atom.toTooltip(),
tooltip: atom.toTooltip("%"),
external: propagation
}
});
......@@ -500,11 +516,6 @@ class Depiction {
}
/**
* Atom from the depiction
*
......@@ -545,8 +556,8 @@ class Atom {
* @return {string} name of atom
* @memberof Atom
*/
public toTooltip(): string {
return `<span>${this.name} | ${this.value}</span>`;
public toTooltip(symbol: string): string {
return `<span>${this.name}: ${this.value.toFixed(2)}${symbol}</span>`;
}
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment