diff --git a/spec/helper/PlayServiceMockCreator.spec.ts b/spec/helper/PlayServiceMockCreator.spec.ts index e12708be8..7baee410f 100644 --- a/spec/helper/PlayServiceMockCreator.spec.ts +++ b/spec/helper/PlayServiceMockCreator.spec.ts @@ -14,6 +14,7 @@ export class PlayServiceMockCreator extends MockCreatorBase { this._mockProperty(mock, "direction$", new Subject()); this._mockProperty(mock, "playing$", new Subject()); + this._mockProperty(mock, "speed$", new Subject()); return mock; } diff --git a/src/Component.ts b/src/Component.ts index cf29062d6..52b604e4b 100644 --- a/src/Component.ts +++ b/src/Component.ts @@ -12,6 +12,7 @@ export {DirectionDOMCalculator} from "./component/direction/DirectionDOMCalculat export {DirectionDOMRenderer} from "./component/direction/DirectionDOMRenderer"; export {ImageComponent} from "./component/ImageComponent"; export {KeyboardComponent} from "./component/keyboard/KeyboardComponent"; +export {KeyPlayHandler} from "./component/keyboard/KeyPlayHandler"; export {KeyZoomHandler} from "./component/keyboard/KeyZoomHandler"; export {KeySequenceNavigationHandler} from "./component/keyboard/KeySequenceNavigationHandler"; export {KeySpatialNavigationHandler} from "./component/keyboard/KeySpatialNavigationHandler"; diff --git a/src/component/interfaces/IKeyboardConfiguration.ts b/src/component/interfaces/IKeyboardConfiguration.ts index 939c874d0..86978a932 100644 --- a/src/component/interfaces/IKeyboardConfiguration.ts +++ b/src/component/interfaces/IKeyboardConfiguration.ts @@ -20,11 +20,11 @@ import {IComponentConfiguration} from "../../Component"; */ export interface IKeyboardConfiguration extends IComponentConfiguration { /** - * Enable or disable the `KeyHandler`. + * Enable or disable the `KeyPlayHandler`. * * @default true */ - keyZoom?: boolean; + keyPlay?: boolean; /** * Enable or disable the `KeySequenceNavigationHandler`. @@ -39,6 +39,13 @@ export interface IKeyboardConfiguration extends IComponentConfiguration { * @default true */ keySpatialNavigation?: boolean; + + /** + * Enable or disable the `KeyZoomHandler`. + * + * @default true + */ + keyZoom?: boolean; } export default IKeyboardConfiguration; diff --git a/src/component/keyboard/KeyPlayHandler.ts b/src/component/keyboard/KeyPlayHandler.ts new file mode 100644 index 000000000..b9361a038 --- /dev/null +++ b/src/component/keyboard/KeyPlayHandler.ts @@ -0,0 +1,113 @@ +/// + +import {Observable} from "rxjs/Observable"; +import {Subscription} from "rxjs/Subscription"; + +import { + IKeyboardConfiguration, + HandlerBase, +} from "../../Component"; +import {EdgeDirection} from "../../Edge"; +import { + IEdgeStatus, + Node, +} from "../../Graph"; + +/** + * The `KeyPlayHandler` allows the user to control the play behavior + * using the following key commands: + * + * `Spacebar`: Start or stop playing. + * `SHIFT` + `D`: Switch direction. + * `<`: Decrease speed. + * `>`: Increase speed. + * + * @example + * ``` + * var keyboardComponent = viewer.getComponent("keyboard"); + * + * keyboardComponent.keyPlay.disable(); + * keyboardComponent.keyPlay.enable(); + * + * var isEnabled = keyboardComponent.keyPlay.isEnabled; + * ``` + */ +export class KeyPlayHandler extends HandlerBase { + private _keyDownSubscription: Subscription; + + protected _enable(): void { + this._keyDownSubscription = this._container.keyboardService.keyDown$ + .withLatestFrom( + this._navigator.playService.playing$, + this._navigator.playService.direction$, + this._navigator.playService.speed$, + this._navigator.stateService.currentNode$ + .switchMap( + (node: Node): Observable => { + return node.sequenceEdges$; + })) + .subscribe( + ( + [event, playing, direction, speed, status]: + [KeyboardEvent, boolean, EdgeDirection, number, IEdgeStatus]): void => { + + if (event.altKey || event.ctrlKey || event.metaKey) { + return; + } + + switch (event.key) { + case "D": + if (!event.shiftKey) { + return; + } + + const newDirection: EdgeDirection = playing ? + null : direction === EdgeDirection.Next ? + EdgeDirection.Prev : direction === EdgeDirection.Prev ? + EdgeDirection.Next : null; + + if (newDirection != null) { + this._navigator.playService.setDirection(newDirection); + } + + break; + case " ": + if (event.shiftKey) { + return; + } + + if (playing) { + this._navigator.playService.stop(); + } else { + for (let edge of status.edges) { + if (edge.data.direction === direction) { + this._navigator.playService.play(); + } + } + } + + break; + case "<": + this._navigator.playService.setSpeed(speed - 0.05); + break; + case ">": + this._navigator.playService.setSpeed(speed + 0.05); + break; + default: + return; + } + + event.preventDefault(); + }); + } + + protected _disable(): void { + this._keyDownSubscription.unsubscribe(); + } + + protected _getConfiguration(enable: boolean): IKeyboardConfiguration { + return { keyZoom: enable }; + } +} + +export default KeyPlayHandler; diff --git a/src/component/keyboard/KeySequenceNavigationHandler.ts b/src/component/keyboard/KeySequenceNavigationHandler.ts index ec2700d75..48e5e405d 100644 --- a/src/component/keyboard/KeySequenceNavigationHandler.ts +++ b/src/component/keyboard/KeySequenceNavigationHandler.ts @@ -17,7 +17,7 @@ import { } from "../../Graph"; /** - * The `KeySequenceNavigationHandler` allows the user navigate through a sequence using the + * The `KeySequenceNavigationHandler` allows the user to navigate through a sequence using the * following key commands: * * `ALT` + `Up Arrow`: Navigate to next image in the sequence. diff --git a/src/component/keyboard/KeySpatialNavigationHandler.ts b/src/component/keyboard/KeySpatialNavigationHandler.ts index aabc1beec..fbcaaa8e0 100644 --- a/src/component/keyboard/KeySpatialNavigationHandler.ts +++ b/src/component/keyboard/KeySpatialNavigationHandler.ts @@ -35,7 +35,7 @@ import { } from "../../Viewer"; /** - * The `KeySpatialNavigationHandler` allows the user navigate through a sequence using the + * The `KeySpatialNavigationHandler` allows the user to navigate through a sequence using the * following key commands: * * `Up Arrow`: Step forward. diff --git a/src/component/keyboard/KeyZoomHandler.ts b/src/component/keyboard/KeyZoomHandler.ts index a03af0b64..cfc70f44b 100644 --- a/src/component/keyboard/KeyZoomHandler.ts +++ b/src/component/keyboard/KeyZoomHandler.ts @@ -20,7 +20,7 @@ import { } from "../../Viewer"; /** - * The `KeyZoomHandler` allows the user zoom in and out using the + * The `KeyZoomHandler` allows the user to zoom in and out using the * following key commands: * * `+`: Zoom in. diff --git a/src/component/keyboard/KeyboardComponent.ts b/src/component/keyboard/KeyboardComponent.ts index 0b025ef63..d1a0443d5 100644 --- a/src/component/keyboard/KeyboardComponent.ts +++ b/src/component/keyboard/KeyboardComponent.ts @@ -4,9 +4,10 @@ import { ComponentService, Component, IKeyboardConfiguration, - KeyZoomHandler, + KeyPlayHandler, KeySequenceNavigationHandler, KeySpatialNavigationHandler, + KeyZoomHandler, } from "../../Component"; import { Spatial, @@ -37,27 +38,29 @@ import { export class KeyboardComponent extends Component { public static componentName: string = "keyboard"; - private _keyZoomHandler: KeyZoomHandler; + private _keyPlayHandler: KeyPlayHandler; private _keySequenceNavigationHandler: KeySequenceNavigationHandler; private _keySpatialNavigationHandler: KeySpatialNavigationHandler; + private _keyZoomHandler: KeyZoomHandler; private _configurationSubscription: Subscription; constructor(name: string, container: Container, navigator: Navigator) { super(name, container, navigator); - this._keyZoomHandler = new KeyZoomHandler(this, container, navigator, new ViewportCoords()); + this._keyPlayHandler = new KeyPlayHandler(this, container, navigator); this._keySequenceNavigationHandler = new KeySequenceNavigationHandler(this, container, navigator); this._keySpatialNavigationHandler = new KeySpatialNavigationHandler(this, container, navigator, new Spatial()); + this._keyZoomHandler = new KeyZoomHandler(this, container, navigator, new ViewportCoords()); } /** - * Get key zoom. + * Get key play. * - * @returns {KeyZoomHandler} The key zoom handler. + * @returns {KeyPlayHandler} The key play handler. */ - public get keyZoom(): KeyZoomHandler { - return this._keyZoomHandler; + public get keyPlay(): KeyPlayHandler { + return this._keyPlayHandler; } /** @@ -78,14 +81,23 @@ export class KeyboardComponent extends Component { return this._keySpatialNavigationHandler; } + /** + * Get key zoom. + * + * @returns {KeyZoomHandler} The key zoom handler. + */ + public get keyZoom(): KeyZoomHandler { + return this._keyZoomHandler; + } + protected _activate(): void { this._configurationSubscription = this._configuration$ .subscribe( (configuration: IKeyboardConfiguration): void => { - if (configuration.keyZoom) { - this._keyZoomHandler.enable(); + if (configuration.keyPlay) { + this._keyPlayHandler.enable(); } else { - this._keyZoomHandler.disable(); + this._keyPlayHandler.disable(); } if (configuration.keySequenceNavigation) { @@ -99,6 +111,12 @@ export class KeyboardComponent extends Component { } else { this._keySpatialNavigationHandler.disable(); } + + if (configuration.keyZoom) { + this._keyZoomHandler.enable(); + } else { + this._keyZoomHandler.disable(); + } }); } @@ -107,7 +125,7 @@ export class KeyboardComponent extends Component { } protected _getDefaultConfiguration(): IKeyboardConfiguration { - return { keySequenceNavigation: true, keySpatialNavigation: true, keyZoom: true }; + return { keyPlay: true, keySequenceNavigation: true, keySpatialNavigation: true, keyZoom: true }; } }