@jbrowse/plugin-wiggle
Version:
JBrowse 2 wiggle adapters, tracks, etc.
414 lines (413 loc) • 17.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stateModelFactory = stateModelFactory;
const react_1 = require("react");
const configuration_1 = require("@jbrowse/core/configuration");
const colors_1 = require("@jbrowse/core/ui/colors");
const util_1 = require("@jbrowse/core/util");
const stopToken_1 = require("@jbrowse/core/util/stopToken");
const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
const mobx_state_tree_1 = require("mobx-state-tree");
const react_d3_axis_mod_1 = require("react-d3-axis-mod");
const SharedWiggleMixin_1 = __importDefault(require("../shared/SharedWiggleMixin"));
const util_2 = require("../util");
const randomColor = () => '#000000'.replaceAll('0', () => (~~(Math.random() * 16)).toString(16));
const Tooltip = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/Tooltip'))));
const SetColorDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SetColorDialog'))));
const WiggleClusterDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/WiggleClusterDialog/WiggleClusterDialog'))));
const rendererTypes = new Map([
['xyplot', 'MultiXYPlotRenderer'],
['multirowxy', 'MultiRowXYPlotRenderer'],
['multirowdensity', 'MultiDensityRenderer'],
['multiline', 'MultiLineRenderer'],
['multirowline', 'MultiRowLineRenderer'],
]);
function stateModelFactory(_pluginManager, configSchema) {
return mobx_state_tree_1.types
.compose('MultiLinearWiggleDisplay', (0, SharedWiggleMixin_1.default)(configSchema), mobx_state_tree_1.types.model({
type: mobx_state_tree_1.types.literal('MultiLinearWiggleDisplay'),
layout: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.frozen(), []),
showSidebar: true,
}))
.volatile(() => ({
sourcesLoadingStopToken: undefined,
featureUnderMouseVolatile: undefined,
sourcesVolatile: undefined,
}))
.actions(self => ({
setShowSidebar(arg) {
self.showSidebar = arg;
},
setSourcesLoading(str) {
if (self.sourcesLoadingStopToken) {
(0, stopToken_1.stopStopToken)(self.sourcesLoadingStopToken);
}
self.sourcesLoadingStopToken = str;
},
setLayout(layout) {
self.layout = layout;
},
clearLayout() {
self.layout = [];
},
setSources(sources) {
if (!(0, fast_deep_equal_1.default)(sources, self.sourcesVolatile)) {
self.sourcesVolatile = sources;
}
},
setFeatureUnderMouse(f) {
self.featureUnderMouseVolatile = f;
},
}))
.views(self => ({
get featureUnderMouse() {
return self.featureUnderMouseVolatile;
},
get TooltipComponent() {
return Tooltip;
},
get rendererTypeName() {
const name = self.rendererTypeNameSimple;
const rendererType = rendererTypes.get(name);
if (!rendererType) {
throw new Error(`unknown renderer ${name}`);
}
return rendererType;
},
}))
.views(self => ({
get graphType() {
return (self.rendererTypeName === 'MultiXYPlotRenderer' ||
self.rendererTypeName === 'MultiRowXYPlotRenderer' ||
self.rendererTypeName === 'MultiLineRenderer' ||
self.rendererTypeName === 'MultiRowLineRenderer');
},
get needsFullHeightScalebar() {
return (self.rendererTypeName === 'MultiXYPlotRenderer' ||
self.rendererTypeName === 'MultiLineRenderer');
},
get isMultiRow() {
return (self.rendererTypeName === 'MultiRowXYPlotRenderer' ||
self.rendererTypeName === 'MultiRowLineRenderer' ||
self.rendererTypeName === 'MultiDensityRenderer');
},
get needsCustomLegend() {
return self.rendererTypeName === 'MultiDensityRenderer';
},
get canHaveFill() {
return (self.rendererTypeName === 'MultiXYPlotRenderer' ||
self.rendererTypeName === 'MultiRowXYPlotRenderer');
},
get renderColorBoxes() {
return !(self.rendererTypeName === 'MultiRowLineRenderer' ||
self.rendererTypeName === 'MultiRowXYPlotRenderer');
},
get prefersOffset() {
return this.isMultiRow;
},
get sourcesWithoutLayout() {
var _a;
const sources = Object.fromEntries(((_a = self.sourcesVolatile) === null || _a === void 0 ? void 0 : _a.map(s => [s.name, s])) || []);
const iter = self.sourcesVolatile;
return iter === null || iter === void 0 ? void 0 : iter.map(s => ({
...sources[s.name],
...s,
})).map((s, i) => ({
...s,
color: s.color ||
(!this.isMultiRow ? colors_1.set1[i] || randomColor() : 'blue'),
}));
},
get sources() {
var _a;
const sources = Object.fromEntries(((_a = self.sourcesVolatile) === null || _a === void 0 ? void 0 : _a.map(s => [s.name, s])) || []);
const iter = self.layout.length ? self.layout : self.sourcesVolatile;
return iter === null || iter === void 0 ? void 0 : iter.map(s => ({
...sources[s.name],
...s,
})).map((s, i) => ({
...s,
color: s.color ||
(!this.isMultiRow ? colors_1.set1[i] || randomColor() : 'blue'),
}));
},
get quantitativeStatsReady() {
const view = (0, util_1.getContainingView)(self);
return (view.initialized && self.statsReadyAndRegionNotTooLarge && !self.error);
},
}))
.views(self => ({
get rowHeight() {
const { sources, height, isMultiRow } = self;
return isMultiRow ? height / ((sources === null || sources === void 0 ? void 0 : sources.length) || 1) : height;
},
get rowHeightTooSmallForScalebar() {
return this.rowHeight < 70;
},
get useMinimalTicks() {
return ((0, configuration_1.getConf)(self, 'minimalTicks') ||
this.rowHeightTooSmallForScalebar);
},
}))
.views(self => {
const { renderProps: superRenderProps } = self;
return {
adapterProps() {
const superProps = superRenderProps();
return {
...superProps,
displayModel: self,
config: self.rendererConfig,
filters: self.filters,
resolution: self.resolution,
rpcDriverName: self.rpcDriverName,
sources: self.sources,
};
},
get ticks() {
const { scaleType, domain, isMultiRow, rowHeight, useMinimalTicks } = self;
if (!domain) {
return undefined;
}
const offset = isMultiRow ? 0 : util_2.YSCALEBAR_LABEL_OFFSET;
const ticks = (0, react_d3_axis_mod_1.axisPropsFromTickScale)((0, util_2.getScale)({
scaleType,
domain,
range: [rowHeight - offset, offset],
inverted: (0, configuration_1.getConf)(self, 'inverted'),
}), 4);
return useMinimalTicks ? { ...ticks, values: domain } : ticks;
},
get colors() {
return [
'red',
'blue',
'green',
'orange',
'purple',
'cyan',
'pink',
'darkblue',
'darkred',
'pink',
];
},
get quantitativeStatsRelevantToCurrentZoom() {
var _a;
const view = (0, util_1.getContainingView)(self);
return ((_a = self.stats) === null || _a === void 0 ? void 0 : _a.currStatsBpPerPx) === view.bpPerPx;
},
};
})
.views(self => ({
get legendFontSize() {
return Math.min(self.rowHeight, 12);
},
get canDisplayLegendLabels() {
return self.rowHeight > 11;
},
get labelWidth() {
var _a;
const minWidth = 20;
return (0, util_1.max)(((_a = self.sources) === null || _a === void 0 ? void 0 : _a.map(s => (0, util_1.measureText)(s.name, this.legendFontSize)).map(width => (this.canDisplayLegendLabels ? width : minWidth))) ||
[]);
},
renderProps() {
const superProps = self.adapterProps();
return {
...superProps,
notReady: superProps.notReady || !self.sources || !self.stats,
displayModel: self,
rpcDriverName: self.rpcDriverName,
displayCrossHatches: self.displayCrossHatches,
height: self.height,
ticks: self.ticks,
stats: self.stats,
scaleOpts: self.scaleOpts,
onMouseMove: (_, f) => {
self.setFeatureUnderMouse(f);
},
onMouseLeave: () => {
self.setFeatureUnderMouse(undefined);
},
};
},
get hasResolution() {
return self.adapterCapabilities.includes('hasResolution');
},
get hasGlobalStats() {
return self.adapterCapabilities.includes('hasGlobalStats');
},
get fillSetting() {
if (self.filled) {
return 0;
}
else if (self.minSize === 1) {
return 1;
}
else {
return 2;
}
},
}))
.views(self => {
const { trackMenuItems: superTrackMenuItems } = self;
const hasRenderings = (0, configuration_1.getConf)(self, 'defaultRendering');
return {
trackMenuItems() {
return [
...superTrackMenuItems(),
{
label: 'Score',
subMenu: self.scoreTrackMenuItems(),
},
...(self.canHaveFill
? [
{
label: 'Fill mode',
subMenu: ['filled', 'no fill', 'no fill w/ emphasis'].map((elt, idx) => ({
label: elt,
type: 'radio',
checked: self.fillSetting === idx,
onClick: () => {
self.setFill(idx);
},
})),
},
]
: []),
...(hasRenderings
? [
{
label: 'Renderer type',
subMenu: [
'xyplot',
'multirowxy',
'multirowdensity',
'multiline',
'multirowline',
].map(key => ({
label: key,
type: 'radio',
checked: self.rendererTypeNameSimple === key,
onClick: () => {
self.setRendererType(key);
},
})),
},
]
: []),
...(self.graphType
? [
{
type: 'checkbox',
label: 'Draw cross hatches',
checked: self.displayCrossHatchesSetting,
onClick: () => {
self.toggleCrossHatches();
},
},
]
: []),
{
label: 'Cluster by score',
onClick: () => {
(0, util_1.getSession)(self).queueDialog(handleClose => [
WiggleClusterDialog,
{
model: self,
handleClose,
},
]);
},
},
{
label: 'Show sidebar',
type: 'checkbox',
checked: self.showSidebar,
onClick: () => {
self.setShowSidebar(!self.showSidebar);
},
},
{
label: 'Edit colors/arrangement...',
onClick: () => {
(0, util_1.getSession)(self).queueDialog(handleClose => [
SetColorDialog,
{
model: self,
handleClose,
},
]);
},
},
];
},
};
})
.actions(self => {
const { renderSvg: superRenderSvg } = self;
return {
afterAttach() {
;
(async () => {
try {
const [{ getMultiWiggleSourcesAutorun }, { getQuantitativeStatsAutorun },] = await Promise.all([
Promise.resolve().then(() => __importStar(require('../getMultiWiggleSourcesAutorun'))),
Promise.resolve().then(() => __importStar(require('../getQuantitativeStatsAutorun'))),
]);
getQuantitativeStatsAutorun(self);
getMultiWiggleSourcesAutorun(self);
}
catch (e) {
if ((0, mobx_state_tree_1.isAlive)(self)) {
console.error(e);
(0, util_1.getSession)(self).notifyError(`${e}`, e);
}
}
})();
},
async renderSvg(opts) {
const { renderSvg } = await Promise.resolve().then(() => __importStar(require('./renderSvg')));
return renderSvg(self, opts, superRenderSvg);
},
};
});
}
exports.default = stateModelFactory;