diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fc525ae14c3bf6ed48eb5e011e99156b7aa6172..2f581a838c154e7cac9f6ced2e9c813faae51d2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,24 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Input/controls improvements + - Move or fly around the scene using keys + - Pointer lock to look around scene + - Toggle spin/rock animation using keys + +## [v3.32.0] - 2023-03-20 + +- Avoid rendering of fully transparent renderables - Add occlusion color parameter - Fix issue with outlines and orthographic camera - Reduce over-blurring occlusion at larger view distances - Fix occlusion artefact with non-canvas viewport and pixel-ratio > 1 - Update nodejs-shims conditionals to handle polyfilled document object in NodeJS environment. - Ensure marking edges are at least one pixel wide -- Input/controls improvements - - Move or fly around the scene using keys - - Pointer lock to look around scene - - Toggle spin/rock animation using keys +- Add exposure parameter to renderer +- Only trigger marking when mouse is directly over canvas +- Fix blurry occlusion in screenshots +- [Breaking] Add `setFSModule` to `mol-util/data-source` instead of trying to trick WebPack ## [v3.31.4] - 2023-02-24 diff --git a/package-lock.json b/package-lock.json index f97b902bb3bcb6a315a8a021e4e7e4e00c6362ec..b18bb879a97c954afe0e0cb44cff481fb14f14d7 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index e6c29447fc0bc95b0cc91f31f686fcba2ac0f2c3..f8db17bd33f61347e46c63a9e509796800f6e09f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "molstar", - "version": "3.31.4", + "version": "3.32.0", "description": "A comprehensive macromolecular library.", "homepage": "https://github.com/molstar/molstar#readme", "repository": { @@ -102,46 +102,46 @@ "license": "MIT", "devDependencies": { "@graphql-codegen/add": "^4.0.1", - "@graphql-codegen/cli": "^3.2.1", + "@graphql-codegen/cli": "^3.2.2", "@graphql-codegen/time": "^4.0.0", - "@graphql-codegen/typescript": "^3.0.1", + "@graphql-codegen/typescript": "^3.0.2", "@graphql-codegen/typescript-graphql-files-modules": "^2.2.1", "@graphql-codegen/typescript-graphql-request": "^4.5.8", - "@graphql-codegen/typescript-operations": "^3.0.1", + "@graphql-codegen/typescript-operations": "^3.0.2", "@types/cors": "^2.8.13", "@types/gl": "^6.0.2", "@types/jpeg-js": "^0.3.7", "@types/pngjs": "^6.0.1", - "@types/jest": "^29.4.0", + "@types/jest": "^29.5.0", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", - "@typescript-eslint/eslint-plugin": "^5.53.0", - "@typescript-eslint/parser": "^5.53.0", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", "benchmark": "^2.1.4", "concurrently": "^7.6.0", - "cpx2": "^4.2.0", + "cpx2": "^4.2.2", "crypto-browserify": "^3.12.0", "css-loader": "^6.7.3", - "eslint": "^8.34.0", + "eslint": "^8.36.0", "extra-watch-webpack-plugin": "^1.0.3", "file-loader": "^6.2.0", "fs-extra": "^11.1.0", "graphql": "^16.6.0", "http-server": "^14.1.1", - "jest": "^29.4.3", - "mini-css-extract-plugin": "^2.7.2", + "jest": "^29.5.0", + "mini-css-extract-plugin": "^2.7.5", "path-browserify": "^1.0.1", "raw-loader": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.58.3", - "sass-loader": "^13.2.0", - "simple-git": "^3.16.1", + "sass": "^1.59.3", + "sass-loader": "^13.2.1", + "simple-git": "^3.17.0", "stream-browserify": "^3.0.0", - "style-loader": "^3.3.1", + "style-loader": "^3.3.2", "ts-jest": "^29.0.5", - "typescript": "^4.9.5", - "webpack": "^5.75.0", + "typescript": "^5.0.2", + "webpack": "^5.76.2", "webpack-cli": "^5.0.1" }, "dependencies": { @@ -149,7 +149,7 @@ "@types/benchmark": "^2.1.2", "@types/compression": "1.7.2", "@types/express": "^4.17.17", - "@types/node": "^16.18.12", + "@types/node": "^16.18.16", "@types/node-fetch": "^2.6.2", "@types/swagger-ui-dist": "3.30.1", "argparse": "^2.0.1", @@ -159,10 +159,10 @@ "express": "^4.18.2", "h264-mp4-encoder": "^1.0.12", "immer": "^9.0.19", - "immutable": "^4.2.4", + "immutable": "^4.3.0", "node-fetch": "^2.6.9", "rxjs": "^7.8.0", - "swagger-ui-dist": "^4.16.1", + "swagger-ui-dist": "^4.18.1", "tslib": "^2.5.0", "util.promisify": "^1.1.1", "xhr2": "^0.2.1" diff --git a/src/examples/image-renderer/index.ts b/src/examples/image-renderer/index.ts index 4acaa96cd27581bec00a8e88d855f71b83b0e236..a4f6961115f7176edac416948bf8e2c924a986f0 100644 --- a/src/examples/image-renderer/index.ts +++ b/src/examples/image-renderer/index.ts @@ -19,8 +19,11 @@ import { StructureRepresentation3D } from '../../mol-plugin-state/transforms/rep import { HeadlessPluginContext } from '../../mol-plugin/headless-plugin-context'; import { DefaultPluginSpec } from '../../mol-plugin/spec'; import { STYLIZED_POSTPROCESSING } from '../../mol-plugin/util/headless-screenshot'; +import { setFSModule } from '../../mol-util/data-source'; +setFSModule(fs); + interface Args { pdbId: string, outDirectory: string diff --git a/src/extensions/zenodo/ui.tsx b/src/extensions/zenodo/ui.tsx index 7a4ad4a1620d55ed9828c55301f346d2ee8d5403..6a52228492df8971a3bded83c62793f1b0dcea62 100644 --- a/src/extensions/zenodo/ui.tsx +++ b/src/extensions/zenodo/ui.tsx @@ -202,7 +202,7 @@ export class ZenodoImportUI extends CollapsableControls<{}, State> { })); } else if (t.name === 'trajectory') { const [topologyUrl, topologyFormat, topologyIsBinary] = t.params.topology.split('|'); - const [coordinatesUrl, coordinatesFormat, coordinatesIsBinary] = t.params.coordinates.split('|'); + const [coordinatesUrl, coordinatesFormat] = t.params.coordinates.split('|'); await this.plugin.runTask(this.plugin.state.data.applyAction(LoadTrajectory, { source: { @@ -216,7 +216,6 @@ export class ZenodoImportUI extends CollapsableControls<{}, State> { coordinates: { url: coordinatesUrl, format: coordinatesFormat as any, - isBinary: coordinatesIsBinary === 'true', }, } } diff --git a/src/mol-canvas3d/helper/interaction-events.ts b/src/mol-canvas3d/helper/interaction-events.ts index 424232659892f8f288d7b334dbeec0d12278148e..ad2046dfa9422a987c7c862dc8cf6fd495f3ec70 100644 --- a/src/mol-canvas3d/helper/interaction-events.ts +++ b/src/mol-canvas3d/helper/interaction-events.ts @@ -197,8 +197,12 @@ export class Canvas3dInteractionHelper { this.drag(x, y, buttons, button, modifiers); }); - input.move.subscribe(({ x, y, inside, buttons, button, modifiers }) => { + input.move.subscribe(({ x, y, inside, buttons, button, modifiers, onElement }) => { if (!inside || this.isInteracting) return; + if (!onElement) { + this.leave(); + return; + } // console.log('move'); this.move(x, y, buttons, button, modifiers); }); diff --git a/src/mol-gl/_spec/gl.shim.ts b/src/mol-gl/_spec/gl.shim.ts index 5c07826ac49b6cf8369fa7f5ceba357164ad3a8e..55ee986271726e763a6121b738627593b8df191a 100644 --- a/src/mol-gl/_spec/gl.shim.ts +++ b/src/mol-gl/_spec/gl.shim.ts @@ -16,7 +16,7 @@ const c = { MAX_TEXTURE_MAX_ANISOTROPY_EXT: 0x84FF, MAX_TEXTURE_IMAGE_UNITS_NV: 0x8872 -}; +} as const; const gl = { ACTIVE_ATTRIBUTES: 35721, @@ -316,7 +316,7 @@ const gl = { VERTEX_SHADER: 35633, VIEWPORT: 2978, ZERO: 0 -}; +} as const; type gl = typeof gl export function createGl(width: number, height: number, contextAttributes: WebGLContextAttributes): WebGLRenderingContext { @@ -371,66 +371,66 @@ export function createGl(width: number, height: number, contextAttributes: WebGL case 'EXT_blend_minmax': return { MAX_EXT: 0, MIN_EXT: 0 - } as EXT_blend_minmax; + } as unknown as EXT_blend_minmax; case 'EXT_texture_filter_anisotropic': return { MAX_TEXTURE_MAX_ANISOTROPY_EXT: 0, TEXTURE_MAX_ANISOTROPY_EXT: 0 - } as EXT_texture_filter_anisotropic; + } as unknown as EXT_texture_filter_anisotropic; case 'EXT_frag_depth': return {} as EXT_frag_depth; - case 'EXT_shader_texture_lod': return {} as EXT_shader_texture_lod; + case 'EXT_shader_texture_lod': return {} as unknown as EXT_shader_texture_lod; case 'EXT_sRGB': return { FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: 0, SRGB8_ALPHA8_EXT: 0, SRGB_ALPHA_EXT: 0, SRGB_EXT: 0 - } as EXT_sRGB; + } as unknown as EXT_sRGB; case 'OES_vertex_array_object': return { VERTEX_ARRAY_BINDING_OES: 0, bindVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { }, createVertexArrayOES: function (): WebGLVertexArrayObjectOES { return {}; }, deleteVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { }, isVertexArrayOES: function (value: any) { return true; } - } as OES_vertex_array_object; + } as unknown as OES_vertex_array_object; case 'WEBGL_color_buffer_float': return { FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT: 0, RGB32F_EXT: 0, RGBA32F_EXT: 0, UNSIGNED_NORMALIZED_EXT: 0 - } as WEBGL_color_buffer_float; + } as unknown as WEBGL_color_buffer_float; case 'WEBGL_compressed_texture_astc': return null; case 'WEBGL_compressed_texture_s3tc_srgb': return null; case 'WEBGL_debug_shaders': return { getTranslatedShaderSource(shader: WebGLShader) { return ''; } - } as WEBGL_debug_shaders; + } as unknown as WEBGL_debug_shaders; case 'WEBGL_draw_buffers': return null; case 'WEBGL_lose_context': return { loseContext: function () { }, restoreContext: function () { }, - } as WEBGL_lose_context; + } as unknown as WEBGL_lose_context; case 'WEBGL_depth_texture': return { UNSIGNED_INT_24_8_WEBGL: 0 - } as WEBGL_depth_texture; + } as unknown as WEBGL_depth_texture; case 'WEBGL_debug_renderer_info': return { UNMASKED_RENDERER_WEBGL: 0, UNMASKED_VENDOR_WEBGL: 0 - } as WEBGL_debug_renderer_info; + } as unknown as WEBGL_debug_renderer_info; case 'WEBGL_compressed_texture_s3tc': return null; - case 'OES_texture_half_float_linear': return {} as OES_texture_half_float_linear; + case 'OES_texture_half_float_linear': return {} as unknown as OES_texture_half_float_linear; case 'OES_texture_half_float': return { HALF_FLOAT_OES: 0 - } as OES_texture_half_float; - case 'OES_texture_float_linear': return {} as OES_texture_float_linear; - case 'OES_texture_float': return {} as OES_texture_float; + } as unknown as OES_texture_half_float; + case 'OES_texture_float_linear': return {} as unknown as OES_texture_float_linear; + case 'OES_texture_float': return {} as unknown as OES_texture_float; case 'OES_standard_derivatives': return { FRAGMENT_SHADER_DERIVATIVE_HINT_OES: 0 - } as OES_standard_derivatives; - case 'OES_element_index_uint': return {} as OES_element_index_uint; + } as unknown as OES_standard_derivatives; + case 'OES_element_index_uint': return {} as unknown as OES_element_index_uint; case 'ANGLE_instanced_arrays': return { drawArraysInstancedANGLE: function (mode: number, first: number, count: number, primcount: number) {}, drawElementsInstancedANGLE: function (mode: number, count: number, type: number, offset: number, primcount: number) {}, vertexAttribDivisorANGLE: function (index: number, divisor: number) {}, VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: 0 - } as ANGLE_instanced_arrays; + } as unknown as ANGLE_instanced_arrays; } return null; }, diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index fd91530c40500e9570a973d6872e3645c81af088..1595f4994ea98cd382fda47084a5983252e80431 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -160,6 +160,7 @@ export const GlobalUniformSchema = { uMarkerAverage: UniformSpec('f'), uXrayEdgeFalloff: UniformSpec('f'), + uExposure: UniformSpec('f'), uRenderMask: UniformSpec('i'), uMarkingDepthTest: UniformSpec('b'), diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 19f335ad610ebd1ba3dbb926f17885d75bc06134..c1132d310e464de6dcdc6e1946186d67c311ac71 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -104,6 +104,7 @@ export const RendererParams = { markerPriority: PD.Select(1, [[1, 'Highlight'], [2, 'Select']]), xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }), + exposure: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.01 }), light: PD.ObjectList({ inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }), @@ -242,6 +243,7 @@ namespace Renderer { uMarkerAverage: ValueCell.create(0), uXrayEdgeFalloff: ValueCell.create(p.xrayEdgeFalloff), + uExposure: ValueCell.create(p.exposure), }; const globalUniformList = Object.entries(globalUniforms); @@ -607,7 +609,7 @@ namespace Renderer { // TODO: simplify, handle in renderable.state??? // uAlpha is updated in "render" so we need to recompute it here const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1); - if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) { + if ((alpha < 1 && alpha !== 0) || r.values.transparencyAverage.ref.value > 0 || r.values.dGeometryType.ref.value === 'directVolume' || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) { renderObject(r, 'colorWboit', Flag.None); } } @@ -655,7 +657,7 @@ namespace Renderer { // TODO: simplify, handle in renderable.state??? // uAlpha is updated in "render" so we need to recompute it here const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1); - if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dPointStyle?.ref.value === 'fuzzy' || !!r.values.uBackgroundColor || r.values.dXrayShaded?.ref.value) { + if ((alpha < 1 && alpha !== 0) || r.values.transparencyAverage.ref.value > 0 || r.values.dPointStyle?.ref.value === 'fuzzy' || r.values.dGeometryType.ref.value === 'text' || r.values.dXrayShaded?.ref.value) { renderObject(r, 'colorDpoit', Flag.None); } } @@ -787,6 +789,10 @@ namespace Renderer { p.xrayEdgeFalloff = props.xrayEdgeFalloff; ValueCell.update(globalUniforms.uXrayEdgeFalloff, p.xrayEdgeFalloff); } + if (props.exposure !== undefined && props.exposure !== p.exposure) { + p.exposure = props.exposure; + ValueCell.update(globalUniforms.uExposure, p.exposure); + } if (props.light !== undefined && !deepEqual(props.light, p.light)) { p.light = props.light; diff --git a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts index ff2036d50cdc38547483552017dae5c90274bbcc..d4f2dc1f432299f85475af8cd791dd33336c161f 100644 --- a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts +++ b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @@ -65,4 +65,6 @@ export const apply_light_color = ` #ifdef dXrayShaded gl_FragColor.a *= 1.0 - pow(abs(dot(normal, vec3(0.0, 0.0, 1.0))), uXrayEdgeFalloff); #endif + +gl_FragColor.rgb *= uExposure; `; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts index 31329c2a2fd8efdf1364b40b102b919a5b3f2c5b..3a3a28ca3f77d1c26df688a50a09e39380c7518b 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts +++ b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts @@ -72,6 +72,7 @@ uniform vec3 uInteriorColor; bool interior; uniform float uXrayEdgeFalloff; +uniform float uExposure; uniform mat4 uProjection; diff --git a/src/mol-gl/shader/direct-volume.frag.ts b/src/mol-gl/shader/direct-volume.frag.ts index 8c6a0d4dc32acdb260ad70671e9422eed3f08455..09df873119e7ef695c8bf0f0768c94d5aba1f46a 100644 --- a/src/mol-gl/shader/direct-volume.frag.ts +++ b/src/mol-gl/shader/direct-volume.frag.ts @@ -75,6 +75,7 @@ uniform vec3 uFogColor; uniform float uAlpha; uniform bool uTransparentBackground; uniform float uXrayEdgeFalloff; +uniform float uExposure; uniform int uRenderMask; diff --git a/src/mol-plugin-state/transforms/data.ts b/src/mol-plugin-state/transforms/data.ts index 0a45868821867087e60809a2670fc9000f30a312..4e264c4e0c46ee91136e74e20e91ec0a11d88312 100644 --- a/src/mol-plugin-state/transforms/data.ts +++ b/src/mol-plugin-state/transforms/data.ts @@ -282,7 +282,7 @@ const ParseCif = PluginStateTransform.BuiltIn({ })({ apply({ a }) { return Task.create('Parse CIF', async ctx => { - const parsed = await (SO.Data.String.is(a) ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx); + const parsed = await (typeof a.data === 'string' ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx); if (parsed.isError) throw new Error(parsed.message); return new SO.Format.Cif(parsed.result); }); diff --git a/src/mol-plugin-ui/controls.tsx b/src/mol-plugin-ui/controls.tsx index 44f9e9a712a66ce7a72049fb2a261613252fcb6f..2aa8241cd02e46abded13939548073bb9ed75304 100644 --- a/src/mol-plugin-ui/controls.tsx +++ b/src/mol-plugin-ui/controls.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -240,14 +240,9 @@ export class SelectionViewportControls extends PluginUIComponent { this.subscribe(this.plugin.behaviors.interaction.selectionMode, () => this.forceUpdate()); } - onMouseMove = (e: React.MouseEvent) => { - // ignore mouse moves when no button is held - if (e.buttons === 0) e.stopPropagation(); - }; - render() { if (!this.plugin.selectionMode) return null; - return <div className='msp-selection-viewport-controls' onMouseMove={this.onMouseMove}> + return <div className='msp-selection-viewport-controls'> <StructureSelectionActionsControls /> </div>; } diff --git a/src/mol-plugin-ui/controls/slider.tsx b/src/mol-plugin-ui/controls/slider.tsx index 02c16b34a966c11c7dd748b7c2b4df86a24d392e..5fdc7ada4d25a9627cb962a1464eadf44da19bb0 100644 --- a/src/mol-plugin-ui/controls/slider.tsx +++ b/src/mol-plugin-ui/controls/slider.tsx @@ -626,9 +626,9 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState const value = bounds[handle]; let direction = 0; - if (bounds[handle + 1] - value < threshold!) { + if (bounds[handle + 1] - value < +threshold!) { direction = +1; - } else if (value - bounds[handle - 1] < threshold!) { + } else if (value - bounds[handle - 1] < +threshold!) { direction = -1; } diff --git a/src/mol-plugin-ui/viewport.tsx b/src/mol-plugin-ui/viewport.tsx index 6d0c45df7796b782868ff32292dacb549def7b38..0dff3983fb17f77158a2456548ddeb34f6e1dc19 100644 --- a/src/mol-plugin-ui/viewport.tsx +++ b/src/mol-plugin-ui/viewport.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> @@ -76,13 +76,8 @@ export class ViewportControls extends PluginUIComponent<ViewportControlsProps, V return <IconButton svg={icon} toggleState={isOn} onClick={onClick} title={title} style={{ background: 'transparent' }} />; } - onMouseMove = (e: React.MouseEvent) => { - // ignore mouse moves when no button is held - if (e.buttons === 0) e.stopPropagation(); - }; - render() { - return <div className={'msp-viewport-controls'} onMouseMove={this.onMouseMove}> + return <div className={'msp-viewport-controls'}> <div className='msp-viewport-controls-buttons'> <div> <div className='msp-semi-transparent-background' /> diff --git a/src/mol-plugin/util/viewport-screenshot.ts b/src/mol-plugin/util/viewport-screenshot.ts index 97368fde642536abe397a736829216e82cbee236..820d0525df1f6f832c7617c52780a71757634cc4 100644 --- a/src/mol-plugin/util/viewport-screenshot.ts +++ b/src/mol-plugin/util/viewport-screenshot.ts @@ -119,7 +119,7 @@ class ViewportScreenshotHelper extends PluginComponent { postprocessing: { ...c.props.postprocessing, occlusion: aoProps.name === 'on' - ? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: 1 } } + ? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: c.webgl.pixelRatio } } : aoProps }, marking: { ...c.props.marking } @@ -143,7 +143,7 @@ class ViewportScreenshotHelper extends PluginComponent { postprocessing: { ...c.props.postprocessing, occlusion: aoProps.name === 'on' - ? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: 1 } } + ? { name: 'on', params: { ...aoProps.params, samples: 128, resolutionScale: c.webgl.pixelRatio } } : aoProps }, marking: { ...c.props.marking } diff --git a/src/mol-state/object.ts b/src/mol-state/object.ts index fff4c7a1aa4f87ac74dac8f5184a64ddd703ce6b..a72b2b75c4671fea81e5423f8c409849c8572649 100644 --- a/src/mol-state/object.ts +++ b/src/mol-state/object.ts @@ -35,7 +35,7 @@ namespace StateObject { export function create<Data, T extends Type>(type: T) { return class O implements StateObject<Data, T> { static type = type; - static is(obj?: StateObject): obj is O { return !!obj && type === obj.type; } + static is(obj?: StateObject): obj is StateObject<Data, T> { return !!obj && type === obj.type; } id = UUID.create22(); type = type; label: string; diff --git a/src/mol-util/data-source.ts b/src/mol-util/data-source.ts index 3d66dbf7466cc0ce305b10ce518949ca5377a34a..759e5b644b401fc314f4b5ba65043efa39522b21 100644 --- a/src/mol-util/data-source.ts +++ b/src/mol-util/data-source.ts @@ -300,14 +300,17 @@ function ajaxGetInternal<T extends DataType>(title: string | undefined, url: str }); } -// NOTE: lazy imports cannot be used here because WebPack complains since this -// is part of the "browser" build. +// NOTE: a workaround for using this in Node.js let _fs: (typeof import ('fs')) | undefined = undefined; function getFS() { - if (_fs) return _fs!; - const req = require; // To fool webpack - _fs = req('fs'); - return _fs!; + if (!_fs) { + throw new Error('When running in Node.js and reading from files, call mol-util/data-source\'s setFSModule function first.'); + } + return _fs; +} + +export function setFSModule(fs: typeof import ('fs')) { + _fs = fs; } /** Alternative implementation of ajaxGetInternal (because xhr2 does not support file:// protocol) */ diff --git a/src/mol-util/input/input-observer.ts b/src/mol-util/input/input-observer.ts index 51fe5bcb02a20a5c3d15eaedcfc45b5ca53e9368..2f3a6e1b47cd8069837bb88e4a9901fa208386b1 100644 --- a/src/mol-util/input/input-observer.ts +++ b/src/mol-util/input/input-observer.ts @@ -168,6 +168,9 @@ export type MoveInput = { movementX?: number, movementY?: number, inside: boolean, + // Move is subscribed to window element + // This indicates that the event originated from the element the InputObserver was created on + onElement: boolean } & BaseInput export type PinchInput = { @@ -220,6 +223,7 @@ type PointerEvent = { pageY: number movementX?: number movementY?: number + target: EventTarget | null preventDefault?: () => void } @@ -503,7 +507,8 @@ namespace InputObserver { clientX: (t0.clientX + t1.clientX) / 2, clientY: (t0.clientY + t1.clientY) / 2, pageX: (t0.pageX + t1.pageX) / 2, - pageY: (t0.pageY + t1.pageY) / 2 + pageY: (t0.pageY + t1.pageY) / 2, + target: ev.target }; } @@ -658,7 +663,7 @@ namespace InputObserver { } isInside = inside; - move.next({ x, y, pageX, pageY, movementX, movementY, buttons, button, modifiers: getModifierKeys(), inside }); + move.next({ x, y, pageX, pageY, movementX, movementY, buttons, button, modifiers: getModifierKeys(), inside, onElement: ev.target === element }); if (dragging === DraggingState.Stopped) return;