diff --git a/src/components/tree/phyloTree/change.js b/src/components/tree/phyloTree/change.js index 958e58035..8e80a16cb 100644 --- a/src/components/tree/phyloTree/change.js +++ b/src/components/tree/phyloTree/change.js @@ -35,8 +35,8 @@ const svgSetters = { attrs: { ".tip": { r: (d) => d.r, - cx: (d) => d.xTip, - cy: (d) => d.yTip + cx: (d) => Math.floor(d.xTip), + cy: (d) => Math.floor(d.yTip) }, ".branch": { }, diff --git a/src/components/tree/phyloTree/layouts.js b/src/components/tree/phyloTree/layouts.js index 4dca67b15..a875c7b50 100644 --- a/src/components/tree/phyloTree/layouts.js +++ b/src/components/tree/phyloTree/layouts.js @@ -375,7 +375,7 @@ export const mapToScreen = function mapToScreen() { // assign the branches as path to each node for the different layouts if (this.layout==="clock" || this.layout==="unrooted") { this.nodes.forEach((d) => { - d.branch = [" M "+d.xBase.toString()+","+d.yBase.toString()+" L "+d.xTip.toString()+","+d.yTip.toString(), ""]; + d.branch = [" M "+ Math.round(d.xBase).toString()+","+Math.round(d.yBase).toString()+" L "+Math.round(d.xTip).toString()+","+Math.round(d.yTip).toString(), ""]; }); } else if (this.layout==="rect") { this.nodes.forEach((d) => { @@ -385,8 +385,8 @@ export const mapToScreen = function mapToScreen() { // So we add a tiny amount of jitter (e.g 1/1000px) to the horizontal line (d.branch[0]) // see https://stackoverflow.com/questions/13223636/svg-gradient-for-perfectly-horizontal-path d.branch =[ - [` M ${d.xBase - stem_offset},${d.yBase} L ${d.xTip},${d.yTip+0.01}`], - [` M ${d.xTip},${childrenY[0]} L ${d.xTip},${childrenY[1]}`] + [` M ${Math.round(d.xBase - stem_offset)},${Math.round(d.yBase)} L ${Math.round(d.xTip)},${Math.round(d.yTip+0.01)}`], + [` M ${Math.round(d.xTip)},${Math.round(childrenY[0])} L ${Math.round(d.xTip)},${Math.round(childrenY[1])}`] ]; if (this.params.confidence) { d.confLine =` M ${this.xScale(d.conf[0])},${d.yBase} L ${this.xScale(d.conf[1])},${d.yTip}`; @@ -399,14 +399,14 @@ export const mapToScreen = function mapToScreen() { this.nodes.forEach((d) => {d.cBarEnd = this.yScale(d.yRange[1]);}); this.nodes.forEach((d, i) => { d.branch =[ - " M "+(d.xBase-stem_offset_radial[i]*Math.sin(d.angle)).toString() + - " "+(d.yBase-stem_offset_radial[i]*Math.cos(d.angle)).toString() + - " L "+d.xTip.toString()+" "+d.yTip.toString(), "" + " M "+Math.round((d.xBase-stem_offset_radial[i]*Math.sin(d.angle))).toString() + + " "+Math.round((d.yBase-stem_offset_radial[i]*Math.cos(d.angle))).toString() + + " L "+Math.round(d.xTip.toString())+" "+Math.round(d.yTip.toString()), "" ]; if (!d.terminal) { - d.branch[1] =[" M "+this.xScale(d.xCBarStart).toString()+" "+this.yScale(d.yCBarStart).toString()+ - " A "+(this.xScale(d.depth)-this.xScale(offset)).toString()+" "+ - (this.yScale(d.depth)-this.yScale(offset)).toString()+ + d.branch[1] =[" M "+Math.round(this.xScale(d.xCBarStart)).toString()+" "+Math.round(this.yScale(d.yCBarStart)).toString()+ + " A "+Math.round((this.xScale(d.depth)-this.xScale(offset))).toString()+" "+ + Math.round((this.yScale(d.depth)-this.yScale(offset))).toString()+ " 0 "+(d.smallBigArc?"1 ":"0 ") +" 1 "+ " "+this.xScale(d.xCBarEnd).toString()+","+this.yScale(d.yCBarEnd).toString()]; } diff --git a/src/components/tree/phyloTree/renderers.js b/src/components/tree/phyloTree/renderers.js index 4ff63897d..c1629300c 100644 --- a/src/components/tree/phyloTree/renderers.js +++ b/src/components/tree/phyloTree/renderers.js @@ -37,7 +37,7 @@ export const render = function render(svg, layout, distance, parameters, callbac d.tipStroke = tipStroke[i]; d.fill = tipFill[i]; d.visibility = visibility[i]; - d["stroke-width"] = branchThickness[i]; + d["stroke-width"] = Math.round(branchThickness[i]); d.r = tipRadii ? tipRadii[i] : this.params.tipRadius; }); @@ -95,6 +95,14 @@ export const drawTips = function drawTips() { timerStart("drawTips"); const params = this.params; + // Reduce the precision of cx and cy attributes. + // The xTip and yTip are full precision Javascript floats + // but when stored in the DOM in decimal text format + // they bloat the DOM and decimal to hex takes longer. + // This only matters when the number of tips is in 4 figures. + // So, need to do a Math.floor() + // Please test this on a Macbook, Apple does tricks with resolution + if (!("tips" in this.groups)) { this.groups.tips = this.svg.append("g").attr("id", "tips"); } @@ -105,17 +113,19 @@ export const drawTips = function drawTips() { .append("circle") .attr("class", "tip") .attr("id", (d) => getDomId("tip", d.n.name)) - .attr("cx", (d) => d.xTip) - .attr("cy", (d) => d.yTip) + .attr("cx", (d) => Math.floor(d.xTip)) + .attr("cy", (d) => Math.floor(d.yTip)) .attr("r", (d) => d.r) .on("mouseover", this.callbacks.onTipHover) .on("mouseout", this.callbacks.onTipLeave) .on("click", this.callbacks.onTipClick) - .style("pointer-events", "auto") - .style("visibility", (d) => d.visibility === NODE_VISIBLE ? "visible" : "hidden") + + /* .style("pointer-events", "auto") */ + .style("visibility", (d) => d.visibility === NODE_VISIBLE ? "" : "hidden") + .style("fill", (d) => d.fill || params.tipFill) .style("stroke", (d) => d.tipStroke || params.tipStroke) - .style("stroke-width", () => params.tipStrokeWidth) /* don't want branch thicknesses applied */ + /* .style("stroke-width", () => params.tipStrokeWidth) don't want branch thicknesses applied */ .style("cursor", "pointer"); timerEnd("drawTips"); @@ -138,7 +148,7 @@ export const getBranchVisibility = (d) => { ) { return "hidden"; } - return "visible"; + return ""; /* the css default is "visible" so just clear this setting */ }; /** Calculate the stroke for a given branch. May return a hex or a `url` referring to @@ -184,9 +194,9 @@ export const drawBranches = function drawBranches() { .attr("id", (d) => getDomId("branchT", d.n.name)) .attr("d", (d) => d.branch[1]) .style("stroke", (d) => d.branchStroke || params.branchStroke) - .style("stroke-width", (d) => d['stroke-width'] || params.branchStrokeWidth) + .style("stroke-width", (d) => Math.round(d['stroke-width'] || params.branchStrokeWidth)) .style("fill", "none") - .style("pointer-events", "auto") + /* .style("pointer-events", "auto") */ .on("mouseover", this.callbacks.onBranchHover) .on("mouseout", this.callbacks.onBranchLeave) .on("click", this.callbacks.onBranchClick); @@ -218,8 +228,8 @@ export const drawBranches = function drawBranches() { if (!d.branchStroke) return params.branchStroke; return strokeForBranch(d, "S"); }) - .style("stroke-linecap", "round") - .style("stroke-width", (d) => d['stroke-width'] || params.branchStrokeWidth) + /* .style("stroke-linecap", "round") */ + .style("stroke-width", (d) => Math.round(d['stroke-width'] || params.branchStrokeWidth)) .style("visibility", getBranchVisibility) .style("cursor", (d) => d.visibility === NODE_VISIBLE ? "pointer" : "default") .style("pointer-events", "auto") diff --git a/src/components/tree/tree.js b/src/components/tree/tree.js index b59ade05f..0a8fed7dc 100644 --- a/src/components/tree/tree.js +++ b/src/components/tree/tree.js @@ -113,7 +113,7 @@ class Tree extends React.Component { return ( {mainTree ? this.domRefs.mainTree = c : this.domRefs.secondTree = c;}}