@rcsb/rcsb-saguaro
Version:
RCSB 1D Feature Viewer
114 lines (113 loc) • 4.94 kB
JavaScript
import { select } from "d3-selection";
import { RcsbD3Constants } from "../RcsbD3Constants";
import { asyncScheduler } from "rxjs";
export class RcsbD3FastSequenceManager {
constructor() {
this.textElements = select(RcsbD3Constants.EMPTY);
this.MONOSPACE_BEGIN = 2.5;
this.FONT_FAMILY = "Monaco, Menlo, Lucida, monospace";
}
plot(config) {
var _a;
const xScale = config.xScale;
const yScale = config.yScale;
this.textElements = config.elements.select(RcsbD3Constants.TEXT);
this.textElements
.attr(RcsbD3Constants.X, (d) => {
return this.textBegin(xScale, d);
})
.attr(RcsbD3Constants.TEXT_LENGTH, (d) => {
return this.textLength(xScale, d);
})
.attr(RcsbD3Constants.Y, (_a = yScale(Math.floor(config.height * 0.5) + 4)) !== null && _a !== void 0 ? _a : 0)
.attr(RcsbD3Constants.FONT_SIZE, "10")
.attr(RcsbD3Constants.FONT_FAMILY, this.FONT_FAMILY)
.attr(RcsbD3Constants.TEXT_ANCHOR, "start")
.attr(RcsbD3Constants.FILL, (d) => {
if (typeof d.color === "string") {
return d.color;
}
else if (typeof config.color === "string") {
return config.color;
}
else {
console.warn("Config color noy found");
return "#CCCCCC";
}
})
.text((d) => {
return d.label || "";
})
.attr(RcsbD3Constants.FILL_OPACITY, () => {
return RcsbD3FastSequenceManager.opacity(xScale, config.intervalRatio);
});
addSequenceEvents(this.textElements, config);
}
static plotSequenceLine(config) {
var _a, _b;
RcsbD3FastSequenceManager.clearLine(config);
config.trackG.append(RcsbD3Constants.LINE)
.style(RcsbD3Constants.STROKE_WIDTH, 2)
.style(RcsbD3Constants.STROKE, "#DDDDDD")
.attr(RcsbD3Constants.STROKE_DASH, "2")
.attr(RcsbD3Constants.X1, config.xScale.range()[0])
.attr(RcsbD3Constants.Y1, (_a = config.yScale(config.height * 0.5)) !== null && _a !== void 0 ? _a : 0)
.attr(RcsbD3Constants.X2, config.xScale.range()[1])
.attr(RcsbD3Constants.Y2, (_b = config.yScale(config.height * 0.5)) !== null && _b !== void 0 ? _b : 0);
const rect = config.trackG.append(RcsbD3Constants.RECT);
rect.attr(RcsbD3Constants.ID, RcsbD3FastSequenceManager.RECT_ID)
.attr(RcsbD3Constants.X, config.xScale.range()[0])
.attr(RcsbD3Constants.Y, config.yScale.range()[0])
.attr(RcsbD3Constants.WIDTH, config.xScale.range()[1] - config.xScale.range()[0])
.attr(RcsbD3Constants.HEIGHT, config.height)
.attr(RcsbD3Constants.FILL_OPACITY, 0);
addSequenceEvents(rect, config);
}
static clearLine(config) {
config.trackG.select(RcsbD3Constants.LINE).remove();
config.trackG.select(`${RcsbD3Constants.RECT}#${RcsbD3FastSequenceManager.RECT_ID}`).remove();
}
move(config) {
asyncScheduler.schedule(() => {
const xScale = config.xScale;
this.textElements
.attr(RcsbD3Constants.X, (d) => {
return this.textBegin(xScale, d);
})
.attr(RcsbD3Constants.TEXT_LENGTH, (d) => {
return this.textLength(xScale, d);
})
.attr(RcsbD3Constants.FILL_OPACITY, () => {
return RcsbD3FastSequenceManager.opacity(xScale, config.intervalRatio);
});
});
}
static opacity(xScale, intervalRatio) {
const r = (xScale.range()[1] - xScale.range()[0]) / (xScale.domain()[1] - xScale.domain()[0]);
const o_min = 0.2;
const a = intervalRatio[0];
const b = intervalRatio[1];
if (r < b) {
return (1 - o_min) / (b - a) * (r - a) + o_min;
}
else {
return 1;
}
}
textLength(xScale, d) {
//TODO Not cool but I did not found any other way.
// It seems that svg > text > textLength attribute behaves slightly different in safari
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent))
return xScale(d.begin + d.label.length) - xScale(d.begin);
return xScale(d.begin + d.label.length - 1) - xScale(d.begin) + 2 * this.MONOSPACE_BEGIN;
}
textBegin(xScale, d) {
return xScale(d.begin) - this.MONOSPACE_BEGIN;
}
}
RcsbD3FastSequenceManager.RECT_ID = "line-rect";
function addSequenceEvents(element, config) {
element.on(RcsbD3Constants.CLICK, event => config.mouseclick(event));
element.on(RcsbD3Constants.MOUSE_MOVE, event => config.mousemove(event));
element.on(RcsbD3Constants.MOUSE_OUT, event => config.mouseleave(event));
}