Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions js/deck-gl/core/deck_ist.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,58 @@ const getCursor = ({ isDragging }) => {
return 'pointer';
};

export const ini_deck = (root, width, height, technology = '') => {
export const ini_deck = (
root,
width,
height,
technology = '',
reuseContext = null,
reuseDeck = null
) => {
const controller = { doubleClickZoom: false };
if (technology === 'point-cloud') {
controller.type = OrbitController;
}

const deck_ist = new Deck({
const deckProps = {
parent: root,
controller,
getCursor,
width,
height,
});
};

const canvas = reuseContext?.canvas;
if (canvas) {
if (canvas.parentNode !== root) {
root.appendChild(canvas);
}
deckProps.canvas = canvas;
}

if (reuseContext?.gl) {
deckProps.gl = reuseContext.gl;
}

if (reuseDeck) {
const canvas = reuseDeck.canvas;

if (canvas && canvas.parentNode !== root) {
root.appendChild(canvas);
}

reuseDeck.setProps({
parent: root,
controller,
getCursor,
width,
height,
});

return reuseDeck;
}

const deck_ist = new Deck(deckProps);

return deck_ist;
};
Expand Down
20 changes: 16 additions & 4 deletions js/deck-gl/layers/cell_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,20 @@ export const get_cell_color = (cats, highlighted_cells, i, d) => {
if (cats.cat === 'cluster') {
try {
const inst_cat = cats.cell_cats[d.index];
const normalizedInstCat = inst_cat == null ? inst_cat : String(inst_cat);
const normalizedSelectedCats = cats.selected_cats.map((cat) =>
cat == null ? cat : String(cat)
);

const isSelected =
normalizedSelectedCats.length === 0 ||
normalizedSelectedCats.some(
(cat) => cat === normalizedInstCat || (cat == null && inst_cat == null)
);

let inst_color = cats.color_dict_cluster[inst_cat];

let inst_opacity =
cats.selected_cats.length === 0 || cats.selected_cats.includes(inst_cat)
? 255
: 10;
let inst_opacity = isSelected ? 255 : 10;

// Check if inst_color is an array and log an error if it's not
if (!Array.isArray(inst_color)) {
Expand Down Expand Up @@ -113,6 +120,11 @@ export const ini_cell_layer = async (base_url, viz_state) => {

set_cell_names_array(viz_state.cats, cell_arrow_table);

// Ensure gene expression array starts with valid opacity values
viz_state.cats.cell_exp_array = new Array(
viz_state.cats.cell_names_array.length
).fill(0);

viz_state.spatial.cell_scatter_data = get_scatter_data(cell_arrow_table);

await set_color_dict_gene(
Expand Down
99 changes: 82 additions & 17 deletions js/viz/landscape_ist.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ export const landscape_ist = async (
rotation_x = 0,
rotate = 0,
max_tiles_to_view = 50,
scale_bar_microns_per_pixel = null
scale_bar_microns_per_pixel = null,
reuseContext = null,
reuseDeck = null
) => {
if (width === 0) {
width = '100%';
Expand Down Expand Up @@ -276,6 +278,8 @@ export const landscape_ist = async (
const datasetPrefixSeparator = '_';
const prefixAttr = ini_model?.get('cell_name_prefix_col');
const baseIdAttr = '__cell_base_id__';
const autoStripPrefix = prefixAttr === true;
const hasPrefixColumn = typeof prefixAttr === 'string' && prefixAttr.length > 0;

const filteredMeta = (() => {
if (!Array.isArray(meta_cell_attr)) {
Expand All @@ -286,7 +290,26 @@ export const landscape_ist = async (
};
}

if (!prefixAttr && datasetLabel) {
if (autoStripPrefix) {
const metaCell = {};
const idMap = [];

Object.entries(meta_cell || {}).forEach(([key, values]) => {
const sepIdx = String(key).indexOf(datasetPrefixSeparator);
if (sepIdx <= 0) {
metaCell[key] = values;
return;
}

const baseId = String(key).slice(sepIdx + 1);
metaCell[baseId] = values;
idMap.push({ sourceId: key, baseId });
});

return { metaCell, metaAttr: meta_cell_attr, idMap };
}

if (!hasPrefixColumn && datasetLabel) {
const metaCell = {};
const idMap = [];

Expand All @@ -309,6 +332,14 @@ export const landscape_ist = async (
}
}

if (!hasPrefixColumn) {
return {
metaCell: meta_cell,
metaAttr: meta_cell_attr,
idMap: [],
};
}

const prefixIdx = meta_cell_attr.indexOf(prefixAttr);
if (prefixIdx === -1) {
return {
Expand Down Expand Up @@ -621,7 +652,19 @@ export const landscape_ist = async (

viz_state.views = set_views(tech);

const deck_ist = await ini_deck(root, width, height, tech);
const deck_ist = await ini_deck(
root,
width,
height,
tech,
reuseContext,
reuseDeck
);

viz_state.gl_context = {
canvas: reuseContext?.canvas || deck_ist?.canvas || null,
gl: reuseContext?.gl || deck_ist?.animationLoop?.gl || null,
};
// set_initial_view_state(deck_ist, ini_x, ini_y, ini_z, ini_zoom)
set_views_prop(deck_ist, viz_state.views);

Expand Down Expand Up @@ -899,20 +942,21 @@ export const landscape_ist = async (

set_deck_on_view_state_change(deck_ist, layers_obj, viz_state);

const updateTriggerHandler = null;
const cellClusterHandler = null;
const updateTriggerHandler = () =>
update_ist_landscape_from_cgm(deck_ist, layers_obj, viz_state);

const cellClusterHandler = () =>
update_cell_clusters(deck_ist, layers_obj, viz_state);

const selectedCellsHandler = () => {
const cells = viz_state.model.get('selected_cells') || [];
viz_state.obs_store.selected_cells.set(cells);
};

if (Object.keys(viz_state.model).length > 0) {
viz_state.model.on('change:update_trigger', () =>
update_ist_landscape_from_cgm(deck_ist, layers_obj, viz_state)
);
viz_state.model.on('change:cell_clusters', () =>
update_cell_clusters(deck_ist, layers_obj, viz_state)
);
viz_state.model.on('change:selected_cells', () => {
const cells = viz_state.model.get('selected_cells') || [];
viz_state.obs_store.selected_cells.set(cells);
});
viz_state.model.on('change:update_trigger', updateTriggerHandler);
viz_state.model.on('change:cell_clusters', cellClusterHandler);
viz_state.model.on('change:selected_cells', selectedCellsHandler);
}

const ui_container = make_ist_ui_container(
Expand Down Expand Up @@ -1099,7 +1143,12 @@ export const landscape_ist = async (
},
update_layers: () => {},
get_state: get_state_snapshot,
finalize: () => {
getContext: () => viz_state.gl_context,
getDeck: () => deck_ist,
finalize: (options = {}) => {
const preserveContext = Boolean(options.preserveContext);
const keepDeck = Boolean(options.keepDeck);

if (updateTriggerHandler) {
viz_state.model.off('change:update_trigger', updateTriggerHandler);
}
Expand All @@ -1108,7 +1157,23 @@ export const landscape_ist = async (
viz_state.model.off('change:cell_clusters', cellClusterHandler);
}

deck_ist.finalize();
if (selectedCellsHandler) {
viz_state.model.off('change:selected_cells', selectedCellsHandler);
}

if (!preserveContext) {
const gl = deck_ist?.animationLoop?.gl;
const loseCtxExtension = gl?.getExtension('WEBGL_lose_context');
if (loseCtxExtension) {
loseCtxExtension.loseContext();
}
}

if (keepDeck) {
deck_ist.setProps({ layers: [] });
} else {
deck_ist.finalize();
}
},
};

Expand Down
22 changes: 20 additions & 2 deletions js/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,22 @@ import { render_enrich } from './widgets/enrich_widget';
const render_landscape_ist = async ({ model, el }) => {
let cleanup = null;
let build_chain = Promise.resolve();
let retainedContext = null;
let retainedDeck = null;

const build_landscape = () => {
build_chain = build_chain.then(async () => {
if (cleanup?.finalize) {
cleanup.finalize();
const nextContext = cleanup?.getContext ? cleanup.getContext() : null;
const nextDeck = cleanup?.getDeck ? cleanup.getDeck() : null;

cleanup.finalize({
preserveContext: true,
keepDeck: Boolean(nextDeck),
});

retainedContext = nextContext;
retainedDeck = nextDeck;
}

el.innerHTML = '';
Expand Down Expand Up @@ -114,8 +125,13 @@ const render_landscape_ist = async ({ model, el }) => {
rotation_x,
rotate,
max_tiles_to_view,
scale_bar_microns_per_pixel
scale_bar_microns_per_pixel,
retainedContext,
retainedDeck
);

retainedContext = cleanup?.getContext ? cleanup.getContext() : null;
retainedDeck = cleanup?.getDeck ? cleanup.getDeck() : null;
} finally {
loading.remove();
}
Expand All @@ -138,6 +154,8 @@ const render_landscape_ist = async ({ model, el }) => {
if (cleanup?.finalize) {
cleanup.finalize();
}
retainedContext = null;
retainedDeck = null;

model.off('change:base_url', handleDatasetChange);
model.off('change:dataset_name', handleDatasetChange);
Expand Down
Loading