Skip to content

Commit

Permalink
Merge pull request #650 from OpenImaging/window-lock-bug
Browse files Browse the repository at this point in the history
Fix window lock bug
  • Loading branch information
zachmullen authored May 3, 2023
2 parents 5acf6c1 + 97638e7 commit 90d76cc
Show file tree
Hide file tree
Showing 11 changed files with 5,402 additions and 10,100 deletions.
15,351 changes: 5,341 additions & 10,010 deletions web_client/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion web_client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"django-s3-file-field": "^0.3.0",
"gl-matrix": "^3.4.3",
"idle-js": "^1.2.0",
"itk": "14.0.0",
"itk-wasm": "^1.0.0-b.18",
"lodash": "^4.17.21",
"polyfill-object.fromentries": "^1.0.1",
"uuid": "^3.4.0",
Expand Down
6 changes: 4 additions & 2 deletions web_client/src/components/WindowWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ export default defineComponent({
function updateRender(ww, wl, updateRange = false) {
if (windowLocked.value) return;
if (currentWindowWidth.value !== ww) props.representation.setWindowWidth(ww);
if (currentWindowLevel.value !== wl) props.representation.setWindowLevel(wl);
store.commit('SET_WINDOW_WIDTH', ww);
store.commit('SET_WINDOW_LEVEL', wl);
props.representation.setWindowWidth(ww);
props.representation.setWindowLevel(wl);
if (updateRange) {
currentRange.value = [
wl - ww / 2,
Expand Down
2 changes: 1 addition & 1 deletion web_client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import Vuetify from 'vuetify';
import 'polyfill-object.fromentries';

import AsyncComputed from 'vue-async-computed';
import config from 'itk/itkConfig';
import * as Sentry from '@sentry/vue';
import config from './utils/itkConfig';
import App from './App.vue';
import router from './router';

Expand Down
1 change: 0 additions & 1 deletion web_client/src/module-declarations.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
declare module 'idle-vue';
declare module 'itk/itkConfig';
85 changes: 46 additions & 39 deletions web_client/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { InterpolationType } from 'vtk.js/Sources/Rendering/Core/ImageProperty/C

import '../utils/registerReaders';

import readImageArrayBuffer from 'itk/readImageArrayBuffer';
import WorkerPool from 'itk/WorkerPool';
// eslint-disable-next-line import/no-extraneous-dependencies
import { readImageArrayBuffer, WorkerPool, WorkerPoolFunction } from 'itk-wasm';
import ITKHelper from 'vtk.js/Sources/Common/DataModel/ITKHelper';
import axios from 'axios';
import djangoRest, { apiClient } from '@/django';
Expand All @@ -28,7 +28,8 @@ import {
SET_TASK_OVERVIEW, SET_PROJECTS, ADD_SCAN_DECISION, SET_FRAME_EVALUATION, SET_CURRENT_SCREENSHOT,
ADD_SCREENSHOT, REMOVE_SCREENSHOT, UPDATE_LAST_API_REQUEST_TIME, SET_LOADING_FRAME,
SET_ERROR_LOADING_FRAME, ADD_SCAN_FRAMES, ADD_EXPERIMENT_SCANS, ADD_EXPERIMENT,
UPDATE_EXPERIMENT, SET_WINDOW_LOCKED, SET_SCAN_CACHED_PERCENTAGE, SET_SLICE_LOCATION,
UPDATE_EXPERIMENT, SET_WINDOW_LOCKED, SET_WINDOW_WIDTH, SET_WINDOW_LEVEL,
SET_SCAN_CACHED_PERCENTAGE, SET_SLICE_LOCATION,
SET_CURRENT_VTK_INDEX_SLICES, SET_SHOW_CROSSHAIRS, SET_STORE_CROSSHAIRS, SET_REVIEW_MODE,
} from './mutation-types';

Expand Down Expand Up @@ -103,7 +104,7 @@ function getImageData(frameId: string, file, webWorker = null) {
// 4. Wait until the file has been loaded
io.onload = function onLoad() {
// 5. Read image using ITK
readImageArrayBuffer(webWorker, io.result, fileName)
readImageArrayBuffer(webWorker, io.result as ArrayBuffer, fileName, '')
// 6. Convert image from ITK to VTK
.then(({ webWorker, image }) => { // eslint-disable-line no-shadow
const frameData = convertItkToVtkImage(image, {
Expand Down Expand Up @@ -179,45 +180,45 @@ async function loadFileAndGetData(frame, { onDownloadProgress = null } = {}) {
* Use a worker to download image files. Only used by WorkerPool
* taskInfo Object Contains experimentId, scanId, and a frame object
*/
function poolFunction(webWorker, taskInfo) {
return new Promise((resolve, reject) => {
const { frame } = taskInfo;
const poolFunction: WorkerPoolFunction = (webWorker, taskInfo) => new Promise((resolve, reject) => {
const { frame } = taskInfo;

let filePromise = null;
let filePromise = null;

if (fileCache.has(frame.id)) {
filePromise = fileCache.get(frame.id);
} else {
let client = apiClient;
let downloadURL = `/frames/${frame.id}/download`;
if (frame.download_url) {
client = axios.create();
downloadURL = frame.download_url;
}
const download = ReaderFactory.downloadFrame(
client,
`image${frame.extension}`,
downloadURL,
);
filePromise = download.promise;
fileCache.set(frame.id, filePromise);
pendingFrameDownloads.add(download);
filePromise.then(() => {
pendingFrameDownloads.delete(download);
}).catch(() => {
pendingFrameDownloads.delete(download);
});
if (fileCache.has(frame.id)) {
filePromise = fileCache.get(frame.id);
} else {
let client = apiClient;
let downloadURL = `/frames/${frame.id}/download`;
if (frame.download_url) {
client = axios.create();
downloadURL = frame.download_url;
}
const download = ReaderFactory.downloadFrame(
client,
`image${frame.extension}`,
downloadURL,
);
filePromise = download.promise;
fileCache.set(frame.id, filePromise);
pendingFrameDownloads.add(download);
filePromise.then(() => {
pendingFrameDownloads.delete(download);
}).catch(() => {
pendingFrameDownloads.delete(download);
});
}

filePromise
.then((file) => {
resolve(getImageData(frame.id, file, webWorker));
})
.catch((err) => {
reject(err);
});
});
}
filePromise
.then((file) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
resolve(getImageData(frame.id, file, webWorker));
})
.catch((err) => {
reject(err);
});
});

/** Calculates the percent downloaded of currently loading frames */
function progressHandler(completed, total) {
Expand Down Expand Up @@ -645,6 +646,12 @@ export const storeConfig:StoreOptions<MIQAStore> = {
[SET_WINDOW_LOCKED](state, lockState) {
state.windowLocked = lockState;
},
[SET_WINDOW_WIDTH](state, ww) {
state.currentWindowWidth = ww;
},
[SET_WINDOW_LEVEL](state, wl) {
state.currentWindowLevel = wl;
},
[SET_SCAN_CACHED_PERCENTAGE](state, percentComplete) {
state.scanCachedPercentage = percentComplete;
},
Expand Down
2 changes: 2 additions & 0 deletions web_client/src/store/mutation-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const ADD_EXPERIMENT_SCANS = 'ADD_EXPERIMENT_SCANS';
export const ADD_EXPERIMENT = 'ADD_EXPERIMENT';
export const UPDATE_EXPERIMENT = 'UPDATE_EXPERIMENT';
export const SET_WINDOW_LOCKED = 'SET_WINDOW_LOCKED';
export const SET_WINDOW_WIDTH = 'SET_WINDOW_WIDTH';
export const SET_WINDOW_LEVEL = 'SET_WINDOW_LEVEL';
export const SET_SCAN_CACHED_PERCENTAGE = 'SET_SCAN_CACHED_PERCENTAGE';
export const SET_SLICE_LOCATION = 'SET_SLICE_LOCATION';
export const SET_CURRENT_VTK_INDEX_SLICES = 'SET_CURRENT_VTK_INDEX_SLICES';
Expand Down
2 changes: 1 addition & 1 deletion web_client/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any *//* eslint camelcase: "off" */
/* eslint no-unused-vars: "off" */
/* eslint no-shadow: "off" */
import type { WorkerPool } from 'itk/WorkerPool';
import type { WorkerPool } from 'itk-wasm';

interface ResponseData {
detail: string,
Expand Down
4 changes: 4 additions & 0 deletions web_client/src/utils/itkConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const itkConfig = {
itkModulesPath: 'itk',
};
export default itkConfig;
3 changes: 2 additions & 1 deletion web_client/src/utils/registerReaders.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import vtkITKImageReader from 'vtk.js/Sources/IO/Misc/ITKImageReader';
import readImageArrayBuffer from 'itk/readImageArrayBuffer';
// eslint-disable-next-line import/no-extraneous-dependencies
import { readImageArrayBuffer } from 'itk-wasm';

import ReaderFactory from './ReaderFactory';

Expand Down
44 changes: 0 additions & 44 deletions web_client/vue.config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
const fs = require('fs');
const util = require('util');
const webpack = require('webpack');
const CopyPlugin = require('copy-webpack-plugin');
const path = require('path');
const vtkChainWebpack = require('vtk.js/Utilities/config/chainWebpack');
const packageJson = require('./package.json');

const stat = util.promisify(fs.stat);

module.exports = {
devServer: {
port: 8081,
Expand All @@ -17,44 +11,6 @@ module.exports = {
publicPath: process.env.VUE_APP_STATIC_PATH,
configureWebpack: {
plugins: [
new CopyPlugin({
patterns: [
{
// It'd be preferable to "require.resolve" here, to ensure that the package resolved by
// imports matches these copied assets, but itk.js has a buggy "package.json" with an
// invalid "main" field, which causes warnings on every build.
from: path.join(__dirname, 'node_modules', 'itk'),
to: 'itk',
filter: async (resourcePath) => {
const resourceStats = await stat(resourcePath);
const resourceSize = resourceStats.size;
// Exclude files larger than 25MB.
// Cloudflare Pages does not allow assets larger than this:
// https://developers.cloudflare.com/pages/platform/limits/#file-size
// In a typical library, module resolution is handled by the bundler (Webpack, Parcel,
// etc.), which can perform tree shaking to exclude unused content from the final
// build and can make choices as to how to split and potentially asynchronously load
// built modules. See: https://webpack.js.org/guides/code-splitting/
// However, itk.js instead internally implements its own runtime asynchronous module
// loader:
// https://github.com/InsightSoftwareConsortium/itk-wasm/blob/v14.0.0/src/loadEmscriptenModuleBrowser.js
// and expects the build system to copy the entire itk.js library to the output
// directory:
// https://github.com/InsightSoftwareConsortium/itk-wasm/blob/v14.0.0/doc/content/examples/webpack.md
// Even if the bundler performs tree-shaking of the actual pure-Javascript code paths
// through itk.js, it's impossible to know what other files might be internally
// fetched by itk.js dynamically at runtime.
// So, here we'll copy everything by default, but exclude the largest files to
// make this application deployable, and hope that none of the excluded files were
// actually necessary at runtime.
// With [email protected], only "itk/PolyDataIOs/VTKExodusFileReader.js" is actually
// excluded.
// The semantics of "CopyPlugin.filter" are the same as "Array.prototype.filter".
return resourceSize <= (25 * 1024 * 1024);
},
},
],
}),
new webpack.DefinePlugin({
'process.env': {
VERSION: JSON.stringify(packageJson.version),
Expand Down

0 comments on commit 90d76cc

Please sign in to comment.