plexora 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plexora/__init__.py +129 -0
- plexora/__main__.py +15 -0
- plexora/_url.py +105 -0
- plexora/api/__init__.py +55 -0
- plexora/api/dataset.py +398 -0
- plexora/api/http.py +19 -0
- plexora/api/plugin.py +541 -0
- plexora/api/store.py +221 -0
- plexora/cli.py +777 -0
- plexora/client/dist/354_bundle.js +2 -0
- plexora/client/dist/354_bundle.js.LICENSE.txt +20 -0
- plexora/client/dist/418_bundle.js +2 -0
- plexora/client/dist/418_bundle.js.LICENSE.txt +1 -0
- plexora/client/dist/693b935cb1f907814be9c6199a68c217.svg +19 -0
- plexora/client/dist/713c134ff47cd328a5b711526f151082.svg +18 -0
- plexora/client/dist/770_bundle.js +1 -0
- plexora/client/dist/ff743f408972e0e96ca9153ed5ae4c83.svg +23 -0
- plexora/client/dist/vendor_bundle.js +2 -0
- plexora/client/dist/vendor_bundle.js.LICENSE.txt +308 -0
- plexora/client/external/openseadragon-bin-2.4.0/LICENSE.txt +28 -0
- plexora/client/external/openseadragon-bin-2.4.0/canvas-overlay-hd.js +140 -0
- plexora/client/external/openseadragon-bin-2.4.0/changelog.txt +501 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/.gitattributes +17 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/LICENSE.txt +116 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/Toolbar.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/fullpage.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/home.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/next.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/previous.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateleft.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/rotateright.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/Photoshop/zoom.psd +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/README.md +9 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/fullpage_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/home_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/next_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/previous_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateleft_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/rotateright_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomin_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_grouphover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_hover.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_pressed.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-flat-toolbar-icons-master/images/zoomout_rest.png +0 -0
- plexora/client/external/openseadragon-bin-2.4.0/openseadragon-scalebar.js +562 -0
- plexora/client/src/css/import.css +474 -0
- plexora/client/src/css/main.css +903 -0
- plexora/client/src/css/openProject.css +363 -0
- plexora/client/src/css/quickView.css +166 -0
- plexora/client/src/css/tokens.css +51 -0
- plexora/client/src/css/viewer.css +1655 -0
- plexora/client/src/img/apple-touch-icon.png +0 -0
- plexora/client/src/img/favicon.ico +0 -0
- plexora/client/src/img/logo.ai +8892 -33
- plexora/client/src/img/logo.svg +1 -0
- plexora/client/src/img/logo_with_text.ai +9011 -34
- plexora/client/src/img/logo_with_text.svg +1 -0
- plexora/client/src/js/main.js +704 -0
- plexora/client/src/js/pluginRegistry.js +108 -0
- plexora/client/src/js/services/appStatus.js +286 -0
- plexora/client/src/js/services/browsePicker.js +73 -0
- plexora/client/src/js/services/dataLayer.js +400 -0
- plexora/client/src/js/services/datasetContext.js +143 -0
- plexora/client/src/js/services/glRenderer.js +143 -0
- plexora/client/src/js/services/importFormValidation.js +257 -0
- plexora/client/src/js/services/numericData.js +100 -0
- plexora/client/src/js/services/passVariablesToFrontend.js +20 -0
- plexora/client/src/js/services/simpleEventHandler.js +25 -0
- plexora/client/src/js/vendor.js +29 -0
- plexora/client/src/js/views/channelList.js +663 -0
- plexora/client/src/js/views/colorSwatchPicker.js +202 -0
- plexora/client/src/js/views/columnClassifier.js +146 -0
- plexora/client/src/js/views/coordinateField.js +133 -0
- plexora/client/src/js/views/dataSourceField.js +276 -0
- plexora/client/src/js/views/imageViewer.js +3306 -0
- plexora/client/src/js/views/miniMap.js +787 -0
- plexora/client/src/js/views/navbarControls.js +178 -0
- plexora/client/src/js/views/openProjectPage.js +239 -0
- plexora/client/src/js/views/projectEdit.js +335 -0
- plexora/client/src/js/views/quickViewLanding.js +136 -0
- plexora/client/src/js/views/rainbow.js +326 -0
- plexora/client/src/js/views/requirementsModal.js +572 -0
- plexora/client/src/js/views/rgbImageViewer.js +115 -0
- plexora/client/src/js/views/searchableSelect.js +411 -0
- plexora/client/src/js/views/segmentationProgress.js +122 -0
- plexora/client/src/js/views/toolLoader.js +747 -0
- plexora/client/src/js/views/viewerControls.js +689 -0
- plexora/client/src/js/views/viewerManager.js +434 -0
- plexora/client/src/js/views/viewerSidebar.js +1117 -0
- plexora/client/src/js/workers/tileDecoder.js +130 -0
- plexora/client/src/shaders/frag.glsl +528 -0
- plexora/client/src/shaders/vert.glsl +12 -0
- plexora/client/templates/base.html +212 -0
- plexora/client/templates/index.html +238 -0
- plexora/client/templates/open_project.html +96 -0
- plexora/client/templates/project_columns.html +86 -0
- plexora/client/templates/project_edit.html +196 -0
- plexora/client/templates/upload.html +118 -0
- plexora/connect.py +528 -0
- plexora/datasource.py +782 -0
- plexora/jupyter.py +406 -0
- plexora/notebook_env.py +232 -0
- plexora/paths.py +486 -0
- plexora/plugins/__init__.py +12 -0
- plexora/plugins/cell_explorer/__init__.py +100 -0
- plexora/plugins/cell_explorer/server/__init__.py +11 -0
- plexora/plugins/cell_explorer/server/routes.py +167 -0
- plexora/plugins/cell_explorer/server/state.py +281 -0
- plexora/plugins/cell_explorer/server/values.py +145 -0
- plexora/plugins/cell_explorer/server/variables.py +367 -0
- plexora/plugins/cell_explorer/static/cellExplorerApi.js +158 -0
- plexora/plugins/cell_explorer/static/cellExplorerColors.js +316 -0
- plexora/plugins/cell_explorer/static/cellExplorerContinuous.js +403 -0
- plexora/plugins/cell_explorer/static/cellExplorerFigureBridge.js +133 -0
- plexora/plugins/cell_explorer/static/cellExplorerLegend.js +188 -0
- plexora/plugins/cell_explorer/static/cellExplorerRoiBridge.js +822 -0
- plexora/plugins/cell_explorer/static/cellExplorerSidebarController.js +826 -0
- plexora/plugins/cell_explorer/static/cellExplorerState.js +372 -0
- plexora/plugins/cell_explorer/static/cell_explorer.css +752 -0
- plexora/plugins/cell_explorer/templates/cell_explorer/panel.html +137 -0
- plexora/plugins/figure_builder/__init__.py +125 -0
- plexora/plugins/figure_builder/server/__init__.py +7 -0
- plexora/plugins/figure_builder/server/compose.py +365 -0
- plexora/plugins/figure_builder/server/export.py +784 -0
- plexora/plugins/figure_builder/server/export_jobs.py +148 -0
- plexora/plugins/figure_builder/server/operations.py +556 -0
- plexora/plugins/figure_builder/server/pixels.py +142 -0
- plexora/plugins/figure_builder/server/provenance.py +174 -0
- plexora/plugins/figure_builder/server/render.py +278 -0
- plexora/plugins/figure_builder/server/repository.py +701 -0
- plexora/plugins/figure_builder/server/routes.py +594 -0
- plexora/plugins/figure_builder/server/schema.py +1023 -0
- plexora/plugins/figure_builder/server/sources.py +120 -0
- plexora/plugins/figure_builder/server/textmetrics.py +155 -0
- plexora/plugins/figure_builder/static/figureActions.js +363 -0
- plexora/plugins/figure_builder/static/figureBuilderApi.js +255 -0
- plexora/plugins/figure_builder/static/figureCanvas.js +2362 -0
- plexora/plugins/figure_builder/static/figureCaptureBoxes.js +369 -0
- plexora/plugins/figure_builder/static/figureCaptureDock.js +466 -0
- plexora/plugins/figure_builder/static/figureCaptureTool.js +1034 -0
- plexora/plugins/figure_builder/static/figureConfirm.js +136 -0
- plexora/plugins/figure_builder/static/figureContextBar.js +1193 -0
- plexora/plugins/figure_builder/static/figureContextMenu.js +253 -0
- plexora/plugins/figure_builder/static/figureDocumentState.js +275 -0
- plexora/plugins/figure_builder/static/figureExportUi.js +174 -0
- plexora/plugins/figure_builder/static/figureLibrary.js +247 -0
- plexora/plugins/figure_builder/static/figureQuickEdit.js +628 -0
- plexora/plugins/figure_builder/static/figureRichText.js +634 -0
- plexora/plugins/figure_builder/static/figureSceneSnapshot.js +361 -0
- plexora/plugins/figure_builder/static/figureSchema.js +218 -0
- plexora/plugins/figure_builder/static/figureSidebarController.js +1159 -0
- plexora/plugins/figure_builder/static/figureTextEditor.js +503 -0
- plexora/plugins/figure_builder/static/figureTextPanel.js +491 -0
- plexora/plugins/figure_builder/static/figureViewOptions.js +273 -0
- plexora/plugins/figure_builder/static/figureWorkspace.js +2030 -0
- plexora/plugins/figure_builder/static/figure_builder.css +3292 -0
- plexora/plugins/figure_builder/templates/figure_builder/library.html +74 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace.html +27 -0
- plexora/plugins/figure_builder/templates/figure_builder/workspace_body.html +458 -0
- plexora/plugins/gating/__init__.py +76 -0
- plexora/plugins/gating/server/__init__.py +0 -0
- plexora/plugins/gating/server/anndata_gates.py +367 -0
- plexora/plugins/gating/server/database.py +16 -0
- plexora/plugins/gating/server/model.py +320 -0
- plexora/plugins/gating/server/routes.py +235 -0
- plexora/plugins/gating/static/csvGatingList.js +947 -0
- plexora/plugins/gating/static/gating.css +289 -0
- plexora/plugins/gating/static/gatingApi.js +221 -0
- plexora/plugins/gating/static/gatingSidebarController.js +513 -0
- plexora/plugins/gating/templates/gating/legacy.html +26 -0
- plexora/plugins/gating/templates/gating/panel.html +69 -0
- plexora/plugins/roi/__init__.py +95 -0
- plexora/plugins/roi/server/__init__.py +8 -0
- plexora/plugins/roi/server/adapters.py +655 -0
- plexora/plugins/roi/server/geojson.py +267 -0
- plexora/plugins/roi/server/geometry.py +181 -0
- plexora/plugins/roi/server/mapping.py +169 -0
- plexora/plugins/roi/server/operations.py +293 -0
- plexora/plugins/roi/server/repository.py +215 -0
- plexora/plugins/roi/server/routes.py +409 -0
- plexora/plugins/roi/server/schema.py +323 -0
- plexora/plugins/roi/static/roi.css +583 -0
- plexora/plugins/roi/static/roiApi.js +177 -0
- plexora/plugins/roi/static/roiFigureBridge.js +107 -0
- plexora/plugins/roi/static/roiGeometry.js +350 -0
- plexora/plugins/roi/static/roiRenderer.js +278 -0
- plexora/plugins/roi/static/roiSidebarController.js +1038 -0
- plexora/plugins/roi/static/roiState.js +518 -0
- plexora/plugins/roi/static/roiTools.js +993 -0
- plexora/plugins/roi/templates/roi/panel.html +240 -0
- plexora/proxy.py +57 -0
- plexora/server/models/adapters/__init__.py +94 -0
- plexora/server/models/adapters/anndata_adapter.py +388 -0
- plexora/server/models/adapters/base.py +93 -0
- plexora/server/models/adapters/classify.py +192 -0
- plexora/server/models/adapters/csv_adapter.py +105 -0
- plexora/server/models/adapters/inspection.py +265 -0
- plexora/server/models/adapters/spatialdata_adapter.py +248 -0
- plexora/server/models/centroid_tiles.py +305 -0
- plexora/server/models/data_model.py +1659 -0
- plexora/server/models/database_model.py +169 -0
- plexora/server/models/project.py +1270 -0
- plexora/server/plugins.py +199 -0
- plexora/server/routes/browse_routes.py +41 -0
- plexora/server/routes/data_routes.py +294 -0
- plexora/server/routes/import_routes.py +603 -0
- plexora/server/routes/page_routes.py +139 -0
- plexora/server/routes/project_routes.py +438 -0
- plexora/server/routes/quick_view_routes.py +62 -0
- plexora/server/routes/system_routes.py +39 -0
- plexora/server/routes/tool_routes.py +418 -0
- plexora/server/utils/addHEColumns.py +11 -0
- plexora/server/utils/fast_png.py +97 -0
- plexora/server/utils/fullConversion.py +50 -0
- plexora/server/utils/native_dialog.py +168 -0
- plexora/server/utils/pre_normalization.py +47 -0
- plexora/server/utils/segmentation_pyramid.py +598 -0
- plexora/server/utils/smallestenclosingcircle.py +126 -0
- plexora/server/utils/tiffsurgeon.py +372 -0
- plexora/server_cli.py +48 -0
- plexora/test.py +0 -0
- plexora-0.0.1.dist-info/METADATA +341 -0
- plexora-0.0.1.dist-info/RECORD +248 -0
- plexora-0.0.1.dist-info/WHEEL +5 -0
- plexora-0.0.1.dist-info/entry_points.txt +12 -0
- plexora-0.0.1.dist-info/licenses/LICENSE +207 -0
- plexora-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import "regenerator-runtime/runtime.js";
|
|
2
|
+
|
|
3
|
+
// Global HD-toggle state, read by getTileUrl() below. A plain module-scope
|
|
4
|
+
// flag (not a ViewerManager instance field) because getTileUrl runs with
|
|
5
|
+
// `this` bound to the tileSource object it's attached to, not the
|
|
6
|
+
// ViewerManager -- this is the one place in the tile-loading path that
|
|
7
|
+
// needs the toggle state and can't reach it via `this`.
|
|
8
|
+
export const tileQuality = { hd: false };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @function toIdealTile -- full tile dimension in full image pixels
|
|
12
|
+
* @param fullScale - scale factor to full image
|
|
13
|
+
* @param useY - 0 for x and 1 for y
|
|
14
|
+
* @returns Number
|
|
15
|
+
*/
|
|
16
|
+
function toIdealTile(fullScale, useY) {
|
|
17
|
+
const { _tileWidth, _tileHeight } = this;
|
|
18
|
+
return [_tileWidth, _tileHeight][useY] * fullScale;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @function toIdealTile -- clipped tile dimension in full image pixels
|
|
23
|
+
* @param fullScale - scale factor to full image
|
|
24
|
+
* @param v - x or y index of tile
|
|
25
|
+
* @param useY - x=0 and y=1
|
|
26
|
+
* @returns Number
|
|
27
|
+
*/
|
|
28
|
+
function toRealTile(fullScale, v, useY) {
|
|
29
|
+
const shape = [this.width, this.height][useY];
|
|
30
|
+
const tileShape = this.toIdealTile(fullScale, useY);
|
|
31
|
+
return Math.min(shape - v * tileShape, tileShape);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @function toTileBoundary -- tile start and size in full image pixels
|
|
36
|
+
* @param fullScale - scale factor to full image
|
|
37
|
+
* @param v - x or y index of tile
|
|
38
|
+
* @param useY - x=0 and y=1
|
|
39
|
+
* @typedef {object} Bound
|
|
40
|
+
* @property {number} start - full image pixel start of tile
|
|
41
|
+
* @property {number} size - full image pixel size of tile
|
|
42
|
+
* @returns Bound
|
|
43
|
+
*/
|
|
44
|
+
function toTileBoundary(fullScale, v, useY) {
|
|
45
|
+
const start = v * this.toIdealTile(fullScale, useY);
|
|
46
|
+
const size = this.toRealTile(fullScale, v, useY);
|
|
47
|
+
return { start, size };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @function toMagnifiedBounds -- return bounds of magnified tile
|
|
52
|
+
* @param _level - openseadragon tile level
|
|
53
|
+
* @param _x - openseadragon tile x index
|
|
54
|
+
* @param _y - openseadragon tile y index
|
|
55
|
+
* @typedef {object} Bounds
|
|
56
|
+
* @property {Array} x - start and end image x-coordinates
|
|
57
|
+
* @property {Array} y - start and end image y-coordinates
|
|
58
|
+
* @returns Bounds
|
|
59
|
+
*/
|
|
60
|
+
function toMagnifiedBounds(_level, _x, _y) {
|
|
61
|
+
const tl = this.toTileLevels(_level, _x, _y);
|
|
62
|
+
if (tl.relativeImageScale >= 1) {
|
|
63
|
+
return { x: [0, 1], y: [0, 1] };
|
|
64
|
+
}
|
|
65
|
+
const ownScale = tl.outputFullScale;
|
|
66
|
+
const parentScale = tl.inputFullScale;
|
|
67
|
+
const [x, y] = [tl.outputTile.x, tl.outputTile.y].map((parentOffset, i) => {
|
|
68
|
+
const hd = this.toTileBoundary(ownScale, [_x, _y][i], i);
|
|
69
|
+
const sd = this.toTileBoundary(parentScale, parentOffset, i);
|
|
70
|
+
const start = (hd.start - sd.start) / sd.size;
|
|
71
|
+
const end = start + hd.size / sd.size;
|
|
72
|
+
return [
|
|
73
|
+
[start, end],
|
|
74
|
+
[1 - end, 1 - start],
|
|
75
|
+
][i];
|
|
76
|
+
});
|
|
77
|
+
return { x, y };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @function toTileLevels -- measure scaled/non-scaled tile details
|
|
82
|
+
* @param level - openseadragon tile level
|
|
83
|
+
* @param x - openseadragon tile x index
|
|
84
|
+
* @param y - openseadragon tile y index
|
|
85
|
+
* @typedef {object} TileLevels
|
|
86
|
+
* @property {number} inputFullScale - full scale of source tile
|
|
87
|
+
* @property {number} outputFullScale - full scale of renedered tile
|
|
88
|
+
* @property {number} relativeImageScale - scale relative to image pixels
|
|
89
|
+
* @property {object} inputTile - level, x, and y of source tile
|
|
90
|
+
* @property {object} outputTile - level, x, and y of rendered tile
|
|
91
|
+
* @returns TileLevels
|
|
92
|
+
*/
|
|
93
|
+
function toTileLevels(level, x, y) {
|
|
94
|
+
const { extraZoomLevels } = this;
|
|
95
|
+
const flipped = this.maxLevel - level;
|
|
96
|
+
const relativeLevel = flipped - extraZoomLevels;
|
|
97
|
+
const sourceLevel = Math.max(relativeLevel, 0);
|
|
98
|
+
const extraZoom = sourceLevel - relativeLevel;
|
|
99
|
+
const inputTile = {
|
|
100
|
+
x: Math.floor(x / 2 ** extraZoom),
|
|
101
|
+
y: Math.floor(y / 2 ** extraZoom),
|
|
102
|
+
level: sourceLevel,
|
|
103
|
+
};
|
|
104
|
+
const outputTile = {
|
|
105
|
+
...inputTile,
|
|
106
|
+
level: level - extraZoom,
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
inputFullScale: 2 ** (flipped + extraZoom),
|
|
110
|
+
relativeImageScale: 2 ** relativeLevel,
|
|
111
|
+
outputFullScale: 2 ** flipped,
|
|
112
|
+
inputTile,
|
|
113
|
+
outputTile,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @function getTileUrl -- return url for tile
|
|
119
|
+
* @param level - openseadragon tile level
|
|
120
|
+
* @param x - openseadragon tile x index
|
|
121
|
+
* @param y - openseadragon tile y index
|
|
122
|
+
* @returns string
|
|
123
|
+
*/
|
|
124
|
+
function getTileUrl(level, x, y) {
|
|
125
|
+
const s = this.toTileLevels(level, x, y).inputTile;
|
|
126
|
+
// Segmentation (tileFormat 32) always ignores the HD toggle -- it has
|
|
127
|
+
// its own fixed encoding regardless -- so its URL (and OSD's URL-keyed
|
|
128
|
+
// tile cache) never churns when HD is flipped.
|
|
129
|
+
const hdParam = this.tileFormat !== 32 && tileQuality.hd ? "?q=hd" : "";
|
|
130
|
+
return `${this.src}${s.level}/${s.x}_${s.y}.png${hdParam}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @function getTileKey -- return string key for tile
|
|
135
|
+
* @param level - openseadragon tile level
|
|
136
|
+
* @param x - openseadragon tile x index
|
|
137
|
+
* @param y - openseadragon tile y index
|
|
138
|
+
* @returns string
|
|
139
|
+
*/
|
|
140
|
+
function getTileKey(level, x, y) {
|
|
141
|
+
const { srcIdx, tileFormat } = this;
|
|
142
|
+
const s = this.toTileLevels(level, x, y).inputTile;
|
|
143
|
+
return `${tileFormat}-${srcIdx}-${s.level}-${s.x}-${s.y}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @function getImagePixel -- return image pixel for screen position
|
|
148
|
+
* @param tiledImage - openseadragon tiled image
|
|
149
|
+
* @param position - screen position
|
|
150
|
+
* @returns array
|
|
151
|
+
*/
|
|
152
|
+
function getImagePixel(tiledImage, position) {
|
|
153
|
+
const tileScale = 2 ** this.extraZoomLevels;
|
|
154
|
+
const frac = tiledImage.viewport.pointFromPixel(position);
|
|
155
|
+
const zoomed = tiledImage.viewportToImageCoordinates(frac);
|
|
156
|
+
return [zoomed.x, zoomed.y].map((v) => v / tileScale);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @class ViewerManager
|
|
161
|
+
*/
|
|
162
|
+
export class ViewerManager {
|
|
163
|
+
colorConnector = {};
|
|
164
|
+
rangeConnector = {};
|
|
165
|
+
|
|
166
|
+
show_sel = true;
|
|
167
|
+
sel_outlines = false;
|
|
168
|
+
labelLayerRequested = false;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Constructs a ColorManager instance before delegating initialization.
|
|
172
|
+
*
|
|
173
|
+
* @param imageViewer - ImageViewer instance
|
|
174
|
+
* @param channelList - ChannelList instance
|
|
175
|
+
*/
|
|
176
|
+
constructor(imageViewer, channelList) {
|
|
177
|
+
this.viewer = imageViewer.viewer;
|
|
178
|
+
this.imageViewer = imageViewer;
|
|
179
|
+
this.channelList = channelList;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @function init
|
|
184
|
+
* Setups up the color manager.
|
|
185
|
+
*/
|
|
186
|
+
init() {
|
|
187
|
+
// Load label image
|
|
188
|
+
this.load_label_image();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @function setHdMode
|
|
193
|
+
* Toggle the global HD (full-precision 16-bit) tile quality on/off and
|
|
194
|
+
* force OpenSeadragon to re-fetch currently-loaded tiles at the new
|
|
195
|
+
* quality. Segmentation tiles are unaffected (see getTileUrl). Dispatches
|
|
196
|
+
* a DOM event so the (unbundled) sidebar can remap its per-channel range
|
|
197
|
+
* sliders between byte units ([0,255], default mode) and raw 16-bit
|
|
198
|
+
* units (HD mode) -- a plain window event because viewerSidebar.js is a
|
|
199
|
+
* raw <script>, not an ES module, so it can't import tileQuality here
|
|
200
|
+
* directly.
|
|
201
|
+
*
|
|
202
|
+
* Just flipping the flag and clearing OpenSeadragon's shared tile cache
|
|
203
|
+
* isn't enough: each TiledImage also keeps its own per-address Tile
|
|
204
|
+
* cache (tilesMatrix), and invalidating that in place left stale/
|
|
205
|
+
* recycled tile canvases on screen without OpenSeadragon ever
|
|
206
|
+
* re-invoking tile-drawing to repaint them (visible as leftover static
|
|
207
|
+
* from whatever was on screen at the moment of the toggle). Removing
|
|
208
|
+
* and re-adding every active channel sidesteps that entirely by making
|
|
209
|
+
* OpenSeadragon build a brand new TiledImage for each one -- the same
|
|
210
|
+
* thing that already happens (and reliably works) when a channel gets
|
|
211
|
+
* toggled off and back on.
|
|
212
|
+
* @param enabled - true for HD (16-bit), false for the fast/default WebP path
|
|
213
|
+
*/
|
|
214
|
+
setHdMode(enabled) {
|
|
215
|
+
tileQuality.hd = enabled;
|
|
216
|
+
Object.keys(this.channelList.currentChannels).map(Number).forEach((srcIdx) => {
|
|
217
|
+
this.channel_remove(srcIdx);
|
|
218
|
+
this.channel_add(srcIdx);
|
|
219
|
+
});
|
|
220
|
+
window.dispatchEvent(new CustomEvent("plexora:hd-mode-changed", { detail: { enabled } }));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @function isHdMode
|
|
225
|
+
* @returns {boolean} whether the global HD (full-precision 16-bit) tile
|
|
226
|
+
* quality is currently enabled.
|
|
227
|
+
*/
|
|
228
|
+
isHdMode() {
|
|
229
|
+
return tileQuality.hd;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @function channel_add
|
|
234
|
+
* Add channel to multi-channel rendering
|
|
235
|
+
* @param srcIdx - integer id of channel to add
|
|
236
|
+
*/
|
|
237
|
+
channel_add(srcIdx) {
|
|
238
|
+
// If already exists
|
|
239
|
+
if (srcIdx in this.channelList.currentChannels) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const url = this.imageViewer.config["imageData"][srcIdx]["src"];
|
|
244
|
+
const { maxLevel, extraZoomLevels } = this.imageViewer.config;
|
|
245
|
+
const magnification = 2 ** extraZoomLevels;
|
|
246
|
+
|
|
247
|
+
// Define url and suburl
|
|
248
|
+
const group = url.split("/");
|
|
249
|
+
const sub_url = group[group.length - 2];
|
|
250
|
+
const range = this.channelList.rangeConnector[srcIdx];
|
|
251
|
+
const { color } = this.channelList.colorConnector[srcIdx] || {};
|
|
252
|
+
const viewerChannel = {
|
|
253
|
+
url: url,
|
|
254
|
+
sub_url: sub_url,
|
|
255
|
+
color: color || d3.color("white"),
|
|
256
|
+
range: range || this.imageViewer.numericData.bitRange,
|
|
257
|
+
};
|
|
258
|
+
this.channelList.currentChannels[srcIdx] = viewerChannel;
|
|
259
|
+
|
|
260
|
+
this.viewer.addTiledImage({
|
|
261
|
+
tileSource: {
|
|
262
|
+
height: this.imageViewer.config.height * magnification,
|
|
263
|
+
width: this.imageViewer.config.width * magnification,
|
|
264
|
+
maxLevel: extraZoomLevels + maxLevel - 1,
|
|
265
|
+
compositeOperation: "lighter",
|
|
266
|
+
tileWidth: this.imageViewer.config.tileWidth,
|
|
267
|
+
tileHeight: this.imageViewer.config.tileHeight,
|
|
268
|
+
toMagnifiedBounds: toMagnifiedBounds,
|
|
269
|
+
extraZoomLevels: extraZoomLevels,
|
|
270
|
+
toTileBoundary: toTileBoundary,
|
|
271
|
+
getImagePixel: getImagePixel,
|
|
272
|
+
toTileLevels: toTileLevels,
|
|
273
|
+
toIdealTile: toIdealTile,
|
|
274
|
+
toRealTile: toRealTile,
|
|
275
|
+
getTileUrl: getTileUrl,
|
|
276
|
+
getTileKey: getTileKey,
|
|
277
|
+
tileFormat: 16,
|
|
278
|
+
srcIdx: srcIdx,
|
|
279
|
+
src: url,
|
|
280
|
+
},
|
|
281
|
+
// index: 0,
|
|
282
|
+
opacity: 1,
|
|
283
|
+
preload: true,
|
|
284
|
+
// "open" is what wires up the GL colorize pipeline (see imageViewer.js's
|
|
285
|
+
// initGL, bound to the "open" handler) -- previously only raised from
|
|
286
|
+
// load_label_image()'s success callback, which never runs for a
|
|
287
|
+
// datasource with no segmentation (noLabel short-circuits it). That left
|
|
288
|
+
// image channels fetching real tile bytes successfully but never
|
|
289
|
+
// getting GL-rendered: tiles loaded, nothing drew. initGL is safe to
|
|
290
|
+
// run more than once, so raising it here too (redundant when a label
|
|
291
|
+
// image is also present) is harmless.
|
|
292
|
+
success: (e) => {
|
|
293
|
+
this.viewer.raiseEvent("open", e.item);
|
|
294
|
+
this.raiseLabelLayer();
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* @function channel_remove - remove channel from multichannel rendering
|
|
302
|
+
* @param srcIdx - integer id of channel to remove
|
|
303
|
+
*/
|
|
304
|
+
channel_remove(srcIdx) {
|
|
305
|
+
const img_count = this.viewer.world.getItemCount();
|
|
306
|
+
|
|
307
|
+
// remove channel
|
|
308
|
+
if (srcIdx in this.channelList.currentChannels) {
|
|
309
|
+
// remove channel - first find it
|
|
310
|
+
for (let i = 0; i < img_count; i = i + 1) {
|
|
311
|
+
const url = this.viewer.world.getItemAt(i).source.src;
|
|
312
|
+
if (url === this.channelList.currentChannels[srcIdx]?.url) {
|
|
313
|
+
this.viewer.world.removeItem(this.viewer.world.getItemAt(i));
|
|
314
|
+
delete this.channelList.currentChannels[srcIdx];
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @function evaluateTF - finds color for value in transfer function
|
|
324
|
+
* @param val - input to transfer function
|
|
325
|
+
* @param tf - colors of transfer function
|
|
326
|
+
* @returns object
|
|
327
|
+
*/
|
|
328
|
+
evaluateTF(val, tf) {
|
|
329
|
+
let lerpFactor = Math.round(((val - tf.min) / (tf.max - tf.min)) * (tf.num_bins - 1));
|
|
330
|
+
|
|
331
|
+
if (lerpFactor >= tf.num_bins) {
|
|
332
|
+
lerpFactor = tf.num_bins - 1;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (lerpFactor < 0) {
|
|
336
|
+
lerpFactor = 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return tf.tf[lerpFactor];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @function force_repaint
|
|
344
|
+
*/
|
|
345
|
+
force_repaint() {
|
|
346
|
+
// Refilter, redraw
|
|
347
|
+
// this.viewer.forceRefilter();
|
|
348
|
+
this.viewer.forceRedraw();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Keep the transparent segmentation layer above image channels.
|
|
353
|
+
*/
|
|
354
|
+
raiseLabelLayer() {
|
|
355
|
+
const world = this.viewer?.world;
|
|
356
|
+
if (!world) return;
|
|
357
|
+
for (let i = 0; i < world.getItemCount(); i += 1) {
|
|
358
|
+
const item = world.getItemAt(i);
|
|
359
|
+
if (item?.source?.tileFormat == 32) {
|
|
360
|
+
world.setItemIndex(item, world.getItemCount() - 1);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* @function load_label_image
|
|
368
|
+
*/
|
|
369
|
+
load_label_image() {
|
|
370
|
+
if (this.labelLayerRequested) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
this.labelLayerRequested = true;
|
|
374
|
+
const self = this;
|
|
375
|
+
|
|
376
|
+
// Load label image in background if it exists. Gate on config.segmentation
|
|
377
|
+
// (set only when a segmentation file was actually registered), not just
|
|
378
|
+
// imageData[0].src -- imageData[0] is the label/"Area" channel only when
|
|
379
|
+
// segmentation exists; otherwise it's just the first real image channel
|
|
380
|
+
// (e.g. "DNA"), which always has a real src and would be wrongly loaded
|
|
381
|
+
// as a label layer, silently, with no error to trigger the centroid
|
|
382
|
+
// fallback below.
|
|
383
|
+
if (this.imageViewer.config["segmentation"] && this.imageViewer.config["imageData"]?.[0]?.["src"]) {
|
|
384
|
+
let url = this.imageViewer.config["imageData"][0]["src"];
|
|
385
|
+
const { maxLevel, extraZoomLevels } = this.imageViewer.config;
|
|
386
|
+
const magnification = 2 ** extraZoomLevels;
|
|
387
|
+
this.viewer.addTiledImage({
|
|
388
|
+
tileSource: {
|
|
389
|
+
height: this.imageViewer.config.height * magnification,
|
|
390
|
+
width: this.imageViewer.config.width * magnification,
|
|
391
|
+
maxLevel: extraZoomLevels + maxLevel - 1,
|
|
392
|
+
maxImageCacheCount: 50,
|
|
393
|
+
compositeOperation: "source-over",
|
|
394
|
+
tileWidth: this.imageViewer.config.tileWidth,
|
|
395
|
+
tileHeight: this.imageViewer.config.tileHeight,
|
|
396
|
+
toMagnifiedBounds: toMagnifiedBounds,
|
|
397
|
+
extraZoomLevels: extraZoomLevels,
|
|
398
|
+
toTileBoundary: toTileBoundary,
|
|
399
|
+
getImagePixel: getImagePixel,
|
|
400
|
+
toTileLevels: toTileLevels,
|
|
401
|
+
toIdealTile: toIdealTile,
|
|
402
|
+
toRealTile: toRealTile,
|
|
403
|
+
getTileUrl: getTileUrl,
|
|
404
|
+
getTileKey: getTileKey,
|
|
405
|
+
tileFormat: 32,
|
|
406
|
+
srcIdx: 0,
|
|
407
|
+
src: url,
|
|
408
|
+
},
|
|
409
|
+
opacity: 1,
|
|
410
|
+
success: (e) => {
|
|
411
|
+
// The GL layer initializes on 'open', so raise it here.
|
|
412
|
+
self.viewer.raiseEvent("open", e.item);
|
|
413
|
+
self.raiseLabelLayer();
|
|
414
|
+
},
|
|
415
|
+
error: () => {
|
|
416
|
+
this.imageViewer.noLabel = true;
|
|
417
|
+
if (PlexoraDataset.hasCentroids(this.imageViewer.config)) {
|
|
418
|
+
this.imageViewer.updateCentroidFallback(true);
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
} else {
|
|
423
|
+
this.imageViewer.noLabel = true;
|
|
424
|
+
// A project with no table -- or one whose coordinate columns are
|
|
425
|
+
// still unidentified -- has no per-cell positions. Falling back to
|
|
426
|
+
// centroids there would round-trip to the server for a manifest
|
|
427
|
+
// that was never going to have any points, delaying load for
|
|
428
|
+
// nothing.
|
|
429
|
+
if (PlexoraDataset.hasCentroids(this.imageViewer.config)) {
|
|
430
|
+
this.imageViewer.updateCentroidFallback(true);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|