From fdbb1fa42af7906dd6b5751c35dae432c9f3bfd6 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Thu, 8 Nov 2018 16:22:43 +0100
Subject: [PATCH] mol-canvas3d: refacroring, moved now() to mol-util

---
 src/apps/canvas/app.ts                       |  2 +-
 src/apps/canvas/component/representation.tsx |  2 +-
 src/apps/canvas/structure-view.ts            |  4 +-
 src/apps/canvas/volume-view.ts               |  2 +-
 src/examples/task.ts                         |  3 +-
 src/mol-canvas3d/camera.ts                   | 28 ++++++-
 src/mol-canvas3d/canvas3d.ts                 | 88 +++++++++-----------
 src/mol-canvas3d/controls/trackball.ts       |  3 +-
 src/mol-model/structure/query/context.ts     |  2 +-
 src/mol-plugin/context.ts                    |  5 +-
 src/mol-task/execution/observable.ts         |  2 +-
 src/mol-task/index.ts                        |  3 +-
 src/mol-task/util/chunked.ts                 |  2 +-
 src/{mol-task/util => mol-util}/now.ts       |  6 +-
 src/mol-util/performance-monitor.ts          |  2 +-
 src/mol-util/uuid.ts                         |  2 +-
 src/perf-tests/tasks.ts                      |  2 +-
 src/servers/model/preprocess/parallel.ts     |  2 +-
 src/servers/model/server/api-local.ts        |  2 +-
 src/servers/model/server/query.ts            |  3 +-
 src/servers/model/utils/fetch-props-pdbe.ts  |  2 +-
 21 files changed, 94 insertions(+), 73 deletions(-)
 rename src/{mol-task/util => mol-util}/now.ts (83%)

diff --git a/src/apps/canvas/app.ts b/src/apps/canvas/app.ts
index 25b2b5aeb..35732c7e5 100644
--- a/src/apps/canvas/app.ts
+++ b/src/apps/canvas/app.ts
@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import Canvas3D from 'mol-canvas3d/canvas3d';
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
 import { getCifFromUrl, getModelsFromMmcif, getCifFromFile, getCcp4FromUrl, getVolumeFromCcp4, getCcp4FromFile, getVolumeFromVolcif } from './util';
 import { StructureView } from './structure-view';
 import { BehaviorSubject } from 'rxjs';
diff --git a/src/apps/canvas/component/representation.tsx b/src/apps/canvas/component/representation.tsx
index 8bbdf8bae..0e4aedd7b 100644
--- a/src/apps/canvas/component/representation.tsx
+++ b/src/apps/canvas/component/representation.tsx
@@ -5,7 +5,7 @@
  */
 
 import * as React from 'react'
-import Canvas3D from 'mol-canvas3d/canvas3d';
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
 import { App } from '../app';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Representation } from 'mol-repr';
diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts
index eeff5581a..4ba79d8bb 100644
--- a/src/apps/canvas/structure-view.ts
+++ b/src/apps/canvas/structure-view.ts
@@ -8,7 +8,7 @@ import { Model, Structure } from 'mol-model/structure';
 import { getStructureFromModel } from './util';
 import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry';
 import { getAxesShape } from './assembly-symmetry';
-import Canvas3D from 'mol-canvas3d/canvas3d';
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
 // import { MeshBuilder } from 'mol-geo/mesh/mesh-builder';
 // import { addSphere } from 'mol-geo/mesh/builder/sphere';
 // import { Shape } from 'mol-model/shape';
@@ -217,7 +217,7 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon
                 }
             }
 
-            canvas3d.center(structure.boundary.sphere.center)
+            canvas3d.camera.setState({ target: structure.boundary.sphere.center })
 
             // const mb = MeshBuilder.create()
             // mb.setGroup(0)
diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts
index 6c05559ef..9d7b8cd1c 100644
--- a/src/apps/canvas/volume-view.ts
+++ b/src/apps/canvas/volume-view.ts
@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import Canvas3D from 'mol-canvas3d/canvas3d';
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
 import { BehaviorSubject } from 'rxjs';
 import { App } from './app';
 import { VolumeData } from 'mol-model/volume';
diff --git a/src/examples/task.ts b/src/examples/task.ts
index 64143cfb7..074190653 100644
--- a/src/examples/task.ts
+++ b/src/examples/task.ts
@@ -4,7 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Task, Progress, Scheduler, now, MultistepTask, chunkedSubtask } from 'mol-task'
+import { Task, Progress, Scheduler, MultistepTask, chunkedSubtask } from 'mol-task'
+import { now } from 'mol-util/now';
 
 export async function test1() {
     const t = Task.create('test', async () => 1);
diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index 88027f1e5..f2e482abc 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -5,13 +5,18 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra'
+import { Mat4, Vec3, Vec4, EPSILON } from 'mol-math/linear-algebra'
 import { Viewport, cameraLookAt, cameraProject, cameraUnproject } from './camera/util';
 import { Object3D } from 'mol-gl/object3d';
+import { BehaviorSubject } from 'rxjs';
 
 export { Camera }
 
+// TODO: slab controls that modify near/far planes?
+
 class Camera implements Object3D {
+    readonly updatedViewProjection = new BehaviorSubject<Camera>(this);
+
     readonly view: Mat4 = Mat4.identity();
     readonly projection: Mat4 = Mat4.identity();
     readonly projectionView: Mat4 = Mat4.identity();
@@ -32,6 +37,9 @@ class Camera implements Object3D {
     get target() { return this.state.target; }
     set target(v: Vec3) { Vec3.copy(this.state.target, v); }
 
+    private prevProjection = Mat4.identity();
+    private prevView = Mat4.identity();
+
     updateMatrices() {
         const snapshot = this.state as Camera.Snapshot;
         const height = 2 * Math.tan(snapshot.fov / 2) * Vec3.distance(snapshot.position, snapshot.target);
@@ -43,8 +51,22 @@ class Camera implements Object3D {
             default: throw new Error('unknown camera mode');
         }
 
+        const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON.Value) || !Mat4.areEqual(this.view, this.prevView, EPSILON.Value);
+
         Mat4.mul(this.projectionView, this.projection, this.view)
         Mat4.invert(this.inverseProjectionView, this.projectionView)
+
+
+        if (changed) {
+            Mat4.mul(this.projectionView, this.projection, this.view)
+            Mat4.invert(this.inverseProjectionView, this.projectionView)
+
+            Mat4.copy(this.prevView, this.view);
+            Mat4.copy(this.prevProjection, this.projection);
+            this.updatedViewProjection.next(this);
+        }
+
+        return changed;
     }
 
     setState(snapshot?: Partial<Camera.Snapshot>) {
@@ -73,6 +95,10 @@ class Camera implements Object3D {
         return cameraUnproject(out, point, this.viewport, this.inverseProjectionView)
     }
 
+    dispose() {
+        this.updatedViewProjection.complete();
+    }
+
     constructor(state?: Partial<Camera.Snapshot>, viewport = Viewport.create(-1, -1, 1, 1)) {
         this.viewport = viewport;
         Camera.copySnapshot(this.state, state);
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 10e2ae36f..3151bab2f 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -5,8 +5,9 @@
  */
 
 import { BehaviorSubject } from 'rxjs';
+import { now } from 'mol-util/now';
 
-import { Vec3, Mat4, EPSILON } from 'mol-math/linear-algebra'
+import { Vec3 } from 'mol-math/linear-algebra'
 import InputObserver from 'mol-util/input/input-observer'
 import * as SetUtils from 'mol-util/set'
 import Renderer, { RendererStats } from 'mol-gl/renderer'
@@ -27,17 +28,19 @@ import { Color } from 'mol-util/color';
 import { Camera } from './camera';
 
 export const DefaultCanvas3DProps = {
+    // TODO: FPS cap?
+    // maxFps: 30,
     cameraPosition: Vec3.create(0, 0, 50),
     cameraMode: 'perspective' as Camera.Mode,
     backgroundColor: Color(0x000000),
 }
 export type Canvas3DProps = typeof DefaultCanvas3DProps
 
+export { Canvas3D }
+
 interface Canvas3D {
     readonly webgl: WebGLContext,
 
-    center: (p: Vec3) => void
-
     hide: (repr: Representation<any>) => void
     show: (repr: Representation<any>) => void
 
@@ -46,7 +49,7 @@ interface Canvas3D {
     update: () => void
     clear: () => void
 
-    draw: (force?: boolean) => void
+    // draw: (force?: boolean) => void
     requestDraw: (force?: boolean) => void
     animate: () => void
     pick: () => void
@@ -54,9 +57,7 @@ interface Canvas3D {
     mark: (loci: Loci, action: MarkerAction) => void
     getLoci: (pickingId: PickingId) => { loci: Loci, repr?: Representation<any> }
 
-    readonly reprCount: BehaviorSubject<number>
-    readonly identified: BehaviorSubject<string>
-    readonly didDraw: BehaviorSubject<number>
+    readonly didDraw: BehaviorSubject<now.Timestamp>
 
     handleResize: () => void
     resetCamera: () => void
@@ -77,11 +78,9 @@ namespace Canvas3D {
         const p = { ...props, ...DefaultCanvas3DProps }
 
         const reprMap = new Map<Representation<any>, Set<RenderObject>>()
-        const reprCount = new BehaviorSubject(0)
-        const identified = new BehaviorSubject('')
 
-        const startTime = performance.now()
-        const didDraw = new BehaviorSubject(0)
+        const startTime = now()
+        const didDraw = new BehaviorSubject<now.Timestamp>(0 as now.Timestamp)
         const input = InputObserver.create(canvas)
 
         const camera = new Camera({
@@ -117,8 +116,6 @@ namespace Canvas3D {
         let isPicking = false
         let drawPending = false
         let lastRenderTime = -1
-        const prevProjectionView = Mat4.zero()
-        const prevSceneView = Mat4.zero()
 
         function getLoci(pickingId: PickingId) {
             let loci: Loci = EmptyLoci
@@ -155,7 +152,7 @@ namespace Canvas3D {
         //     return 0
         // }
 
-        function render(variant: RenderVariant, force?: boolean) {
+        function render(variant: RenderVariant, force: boolean) {
             if (isPicking) return false
             // const p = scene.boundingSphere.center
             // console.log(p[0], p[1], p[2])
@@ -177,51 +174,56 @@ namespace Canvas3D {
 
             // console.log(camera.fogNear, camera.fogFar, targetDistance)
 
-            switch (variant) {
-                case 'pickObject': objectPickTarget.bind(); break;
-                case 'pickInstance': instancePickTarget.bind(); break;
-                case 'pickGroup': groupPickTarget.bind(); break;
-                case 'draw':
-                    webgl.unbindFramebuffer();
-                    renderer.setViewport(0, 0, canvas.width, canvas.height);
-                    break;
-            }
             let didRender = false
             controls.update()
-            camera.updateMatrices();
-            if (force || !Mat4.areEqual(camera.projectionView, prevProjectionView, EPSILON.Value) || !Mat4.areEqual(scene.view, prevSceneView, EPSILON.Value)) {
-                // console.log('foo', force, prevSceneView, scene.view)
-                Mat4.copy(prevProjectionView, camera.projectionView)
-                Mat4.copy(prevSceneView, scene.view)
+            const cameraChanged = camera.updateMatrices();
+
+            if (force || cameraChanged) {
+                switch (variant) {
+                    case 'pickObject': objectPickTarget.bind(); break;
+                    case 'pickInstance': instancePickTarget.bind(); break;
+                    case 'pickGroup': groupPickTarget.bind(); break;
+                    case 'draw':
+                        webgl.unbindFramebuffer();
+                        renderer.setViewport(0, 0, canvas.width, canvas.height);
+                        break;
+                }
+
                 renderer.render(scene, variant)
                 if (variant === 'draw') {
-                    lastRenderTime = performance.now()
+                    lastRenderTime = now()
                     pickDirty = true
                 }
                 didRender = true
             }
-            return didRender
+
+            return didRender && cameraChanged;
         }
 
+        let forceNextDraw = false;
+
         function draw(force?: boolean) {
-            if (render('draw', force)) {
-                didDraw.next(performance.now() - startTime)
+            if (render('draw', !!force || forceNextDraw)) {
+                didDraw.next(now() - startTime as now.Timestamp)
             }
+            forceNextDraw = false;
             drawPending = false
         }
 
         function requestDraw(force?: boolean) {
             if (drawPending) return
             drawPending = true
-            window.requestAnimationFrame(() => draw(force))
+            forceNextDraw = !!force;
+            // The animation frame is being requested by animate already.
+            // window.requestAnimationFrame(() => draw(force))
         }
 
         function animate() {
             draw(false)
-            if (performance.now() - lastRenderTime > 200) {
+            if (now() - lastRenderTime > 200) {
                 if (pickDirty) pick()
             }
-            window.requestAnimationFrame(() => animate())
+            window.requestAnimationFrame(animate)
         }
 
         function pick() {
@@ -273,11 +275,6 @@ namespace Canvas3D {
         return {
             webgl,
 
-            center: (target: Vec3) => {
-                // Vec3.set(controls.target, p[0], p[1], p[2])
-                camera.setState({ target })
-            },
-
             hide: (repr: Representation<any>) => {
                 const renderObjectSet = reprMap.get(repr)
                 if (renderObjectSet) renderObjectSet.forEach(o => o.state.visible = false)
@@ -299,7 +296,6 @@ namespace Canvas3D {
                     repr.renderObjects.forEach(o => scene.add(o))
                 }
                 reprMap.set(repr, newRO)
-                reprCount.next(reprMap.size)
                 scene.update()
             },
             remove: (repr: Representation<any>) => {
@@ -307,7 +303,6 @@ namespace Canvas3D {
                 if (renderObjectSet) {
                     renderObjectSet.forEach(o => scene.remove(o))
                     reprMap.delete(repr)
-                    reprCount.next(reprMap.size)
                     scene.update()
                 }
             },
@@ -317,7 +312,7 @@ namespace Canvas3D {
                 scene.clear()
             },
 
-            draw,
+            // draw,
             requestDraw,
             animate,
             pick,
@@ -341,8 +336,6 @@ namespace Canvas3D {
                     case 'pickGroup': return groupPickTarget.getImageData()
                 }
             },
-            reprCount,
-            identified,
             didDraw,
             setProps: (props: Partial<Canvas3DProps>) => {
                 if (props.cameraMode !== undefined && props.cameraMode !== camera.state.mode) {
@@ -372,6 +365,7 @@ namespace Canvas3D {
                 input.dispose()
                 controls.dispose()
                 renderer.dispose()
+                camera.dispose()
             }
         }
 
@@ -388,6 +382,4 @@ namespace Canvas3D {
             groupPickTarget.setSize(pickWidth, pickHeight)
         }
     }
-}
-
-export default Canvas3D
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/mol-canvas3d/controls/trackball.ts b/src/mol-canvas3d/controls/trackball.ts
index dc2f49ecb..9703eac2d 100644
--- a/src/mol-canvas3d/controls/trackball.ts
+++ b/src/mol-canvas3d/controls/trackball.ts
@@ -25,7 +25,7 @@ export const DefaultTrackballControlsProps = {
     staticMoving: true,
     dynamicDampingFactor: 0.2,
 
-    minDistance: 0,
+    minDistance: 0.01,
     maxDistance: Infinity
 }
 export type TrackballControlsProps = Partial<typeof DefaultTrackballControlsProps>
@@ -293,7 +293,6 @@ namespace TrackballControls {
 
         return {
             viewport,
-            // target,
 
             get dynamicDampingFactor() { return dynamicDampingFactor },
             set dynamicDampingFactor(value: number ) { dynamicDampingFactor = value },
diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts
index 7bc0e6d68..9dd28a6b2 100644
--- a/src/mol-model/structure/query/context.ts
+++ b/src/mol-model/structure/query/context.ts
@@ -5,7 +5,7 @@
  */
 
 import { Structure, StructureElement, Unit } from '../structure';
-import { now } from 'mol-task';
+import { now } from 'mol-util/now';
 import { ElementIndex } from '../model';
 import { Link } from '../structure/unit/links';
 
diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts
index 4aca923fe..b519cc8d7 100644
--- a/src/mol-plugin/context.ts
+++ b/src/mol-plugin/context.ts
@@ -5,7 +5,7 @@
  */
 
 import { StateTree, StateSelection, Transformer, Transform } from 'mol-state';
-import Canvas3D from 'mol-canvas3d/canvas3d';
+import { Canvas3D } from 'mol-canvas3d/canvas3d';
 import { StateTransforms } from './state/transforms';
 import { PluginStateObjects as SO } from './state/objects';
 import { RxEventHelper } from 'mol-util/rx-event-helper';
@@ -141,8 +141,7 @@ export class PluginContext {
         if (!sel.length) return;
 
         const center = (sel[0].obj! as SO.Structure).data.boundary.sphere.center;
-        console.log({ sel, center, rc: this.canvas3d.reprCount });
-        this.canvas3d.center(center);
+        this.canvas3d.camera.setState({ target: center });
         this.canvas3d.requestDraw(true);
     }
 
diff --git a/src/mol-task/execution/observable.ts b/src/mol-task/execution/observable.ts
index 5b8e82f89..5b8d15a07 100644
--- a/src/mol-task/execution/observable.ts
+++ b/src/mol-task/execution/observable.ts
@@ -7,7 +7,7 @@
 import { Task } from '../task'
 import { RuntimeContext } from './runtime-context'
 import { Progress } from './progress'
-import { now } from '../util/now'
+import { now } from 'mol-util/now';
 import { Scheduler } from '../util/scheduler'
 import { UserTiming } from '../util/user-timing'
 
diff --git a/src/mol-task/index.ts b/src/mol-task/index.ts
index 2ef6489c9..62d09e846 100644
--- a/src/mol-task/index.ts
+++ b/src/mol-task/index.ts
@@ -7,9 +7,8 @@
 import { Task } from './task'
 import { RuntimeContext } from './execution/runtime-context'
 import { Progress } from './execution/progress'
-import { now } from './util/now'
 import { Scheduler } from './util/scheduler'
 import { MultistepTask } from './util/multistep'
 import { chunkedSubtask } from './util/chunked'
 
-export { Task, RuntimeContext, Progress, now, Scheduler, MultistepTask, chunkedSubtask }
\ No newline at end of file
+export { Task, RuntimeContext, Progress, Scheduler, MultistepTask, chunkedSubtask }
\ No newline at end of file
diff --git a/src/mol-task/util/chunked.ts b/src/mol-task/util/chunked.ts
index d091e5706..88233dd17 100644
--- a/src/mol-task/util/chunked.ts
+++ b/src/mol-task/util/chunked.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { now } from './now'
+import { now } from 'mol-util/now';
 import { RuntimeContext } from '../execution/runtime-context'
 
 type UniformlyChunkedFn<S> = (chunkSize: number, state: S) => number
diff --git a/src/mol-task/util/now.ts b/src/mol-util/now.ts
similarity index 83%
rename from src/mol-task/util/now.ts
rename to src/mol-util/now.ts
index f4961d217..abf35487f 100644
--- a/src/mol-task/util/now.ts
+++ b/src/mol-util/now.ts
@@ -7,7 +7,7 @@
 declare var process: any;
 declare var window: any;
 
-const now: () => number = (function () {
+const now: () => now.Timestamp = (function () {
     if (typeof window !== 'undefined' && window.performance) {
         const perf = window.performance;
         return () => perf.now();
@@ -23,4 +23,8 @@ const now: () => number = (function () {
     }
 }());
 
+namespace now {
+    export type Timestamp = number & { '@type': 'now-timestamp' }
+}
+
 export { now }
\ No newline at end of file
diff --git a/src/mol-util/performance-monitor.ts b/src/mol-util/performance-monitor.ts
index 614b19a29..615bf93ba 100644
--- a/src/mol-util/performance-monitor.ts
+++ b/src/mol-util/performance-monitor.ts
@@ -5,7 +5,7 @@
  * Copyright (c) 2016 - now David Sehnal, licensed under Apache 2.0, See LICENSE file for more info.
  */
 
-import { now } from 'mol-task/util/now'
+import { now } from 'mol-util/now';
 
 export class PerformanceMonitor {
     private starts = new Map<string, number>();
diff --git a/src/mol-util/uuid.ts b/src/mol-util/uuid.ts
index 4c77f7de6..7972eaf9f 100644
--- a/src/mol-util/uuid.ts
+++ b/src/mol-util/uuid.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { now } from 'mol-task'
+import { now } from 'mol-util/now';
 
 type UUID = string & { '@type': 'uuid' }
 
diff --git a/src/perf-tests/tasks.ts b/src/perf-tests/tasks.ts
index f0c0eb86b..068c47b52 100644
--- a/src/perf-tests/tasks.ts
+++ b/src/perf-tests/tasks.ts
@@ -1,5 +1,5 @@
 import * as B from 'benchmark'
-import { now } from 'mol-task/util/now'
+import { now } from 'mol-util/now';
 import { Scheduler } from 'mol-task/util/scheduler'
 
 export namespace Tasks {
diff --git a/src/servers/model/preprocess/parallel.ts b/src/servers/model/preprocess/parallel.ts
index 2e24f3e0c..1b600b5b0 100644
--- a/src/servers/model/preprocess/parallel.ts
+++ b/src/servers/model/preprocess/parallel.ts
@@ -6,7 +6,7 @@
 
 import * as path from 'path'
 import * as cluster from 'cluster'
-import { now } from 'mol-task';
+import { now } from 'mol-util/now';
 import { PerformanceMonitor } from 'mol-util/performance-monitor';
 import { preprocessFile } from './preprocess';
 import { createModelPropertiesProvider } from '../property-provider';
diff --git a/src/servers/model/server/api-local.ts b/src/servers/model/server/api-local.ts
index f1d5e2f1c..83fe022eb 100644
--- a/src/servers/model/server/api-local.ts
+++ b/src/servers/model/server/api-local.ts
@@ -10,7 +10,7 @@ import { JobManager, Job } from './jobs';
 import { ConsoleLogger } from 'mol-util/console-logger';
 import { resolveJob } from './query';
 import { StructureCache } from './structure-wrapper';
-import { now } from 'mol-task';
+import { now } from 'mol-util/now';
 import { PerformanceMonitor } from 'mol-util/performance-monitor';
 import { QueryName } from './api';
 
diff --git a/src/servers/model/server/query.ts b/src/servers/model/server/query.ts
index 0c80ae56c..f10795964 100644
--- a/src/servers/model/server/query.ts
+++ b/src/servers/model/server/query.ts
@@ -8,7 +8,8 @@ import { Column } from 'mol-data/db';
 import { CifWriter } from 'mol-io/writer/cif';
 import { StructureQuery, StructureSelection, Structure } from 'mol-model/structure';
 import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
-import { now, Progress } from 'mol-task';
+import { Progress } from 'mol-task';
+import { now } from 'mol-util/now';
 import { ConsoleLogger } from 'mol-util/console-logger';
 import { PerformanceMonitor } from 'mol-util/performance-monitor';
 import Config from '../config';
diff --git a/src/servers/model/utils/fetch-props-pdbe.ts b/src/servers/model/utils/fetch-props-pdbe.ts
index f28d9946b..76d77f662 100644
--- a/src/servers/model/utils/fetch-props-pdbe.ts
+++ b/src/servers/model/utils/fetch-props-pdbe.ts
@@ -9,7 +9,7 @@ import * as fs from 'fs'
 import * as path from 'path'
 import * as argparse from 'argparse'
 import { makeDir } from 'mol-util/make-dir';
-import { now } from 'mol-task';
+import { now } from 'mol-util/now';
 import { PerformanceMonitor } from 'mol-util/performance-monitor';
 
 const cmdParser = new argparse.ArgumentParser({
-- 
GitLab