viewport.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import * as React from 'react';
  8. import { ButtonsType } from 'mol-util/input/input-observer';
  9. import { Canvas3dIdentifyHelper } from 'mol-plugin/util/canvas3d-identify';
  10. import { PluginComponent } from './base';
  11. import { PluginCommands } from 'mol-plugin/command';
  12. import { ParamDefinition as PD } from 'mol-util/param-definition';
  13. import { ParameterControls } from './controls/parameters';
  14. import { Canvas3DParams } from 'mol-canvas3d/canvas3d';
  15. import { PluginLayoutStateParams } from 'mol-plugin/layout';
  16. import { ControlGroup } from './controls/common';
  17. interface ViewportState {
  18. noWebGl: boolean
  19. }
  20. export class ViewportControls extends PluginComponent {
  21. state = {
  22. isSettingsExpanded: false
  23. }
  24. resetCamera = () => {
  25. PluginCommands.Camera.Reset.dispatch(this.plugin, {});
  26. }
  27. toggleSettingsExpanded = (e: React.MouseEvent<HTMLButtonElement>) => {
  28. this.setState({ isSettingsExpanded: !this.state.isSettingsExpanded });
  29. e.currentTarget.blur();
  30. }
  31. toggleControls = () => {
  32. PluginCommands.Layout.Update.dispatch(this.plugin, { state: { showControls: !this.plugin.layout.latestState.showControls } });
  33. }
  34. toggleExpanded = () => {
  35. PluginCommands.Layout.Update.dispatch(this.plugin, { state: { isExpanded: !this.plugin.layout.latestState.isExpanded } });
  36. }
  37. setSettings = (p: { param: PD.Base<any>, name: string, value: any }) => {
  38. PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { [p.name]: p.value } });
  39. }
  40. setLayout = (p: { param: PD.Base<any>, name: string, value: any }) => {
  41. PluginCommands.Layout.Update.dispatch(this.plugin, { state: { [p.name]: p.value } });
  42. }
  43. componentDidMount() {
  44. this.subscribe(this.plugin.events.canvad3d.settingsUpdated, e => {
  45. this.forceUpdate();
  46. });
  47. this.subscribe(this.plugin.layout.updated, () => {
  48. this.forceUpdate();
  49. });
  50. }
  51. icon(name: string, onClick: (e: React.MouseEvent<HTMLButtonElement>) => void, title: string, isOn = true) {
  52. return <button
  53. className={`msp-btn msp-btn-link msp-btn-link-toggle-${isOn ? 'on' : 'off'}`}
  54. onClick={onClick}
  55. title={title}>
  56. <span className={`msp-icon msp-icon-${name}`}/>
  57. </button>
  58. }
  59. render() {
  60. // TODO: show some icons dimmed etc..
  61. return <div className={'msp-viewport-controls'}>
  62. <div className='msp-viewport-controls-buttons'>
  63. {this.icon('tools', this.toggleControls, 'Toggle Controls', this.plugin.layout.latestState.showControls)}
  64. {this.icon('expand-layout', this.toggleExpanded, 'Toggle Expanded', this.plugin.layout.latestState.isExpanded)}
  65. {this.icon('settings', this.toggleSettingsExpanded, 'Settings', this.state.isSettingsExpanded)}
  66. {this.icon('reset-scene', this.resetCamera, 'Reset Camera')}
  67. </div>
  68. {this.state.isSettingsExpanded &&
  69. <div className='msp-viewport-controls-scene-options'>
  70. <ControlGroup header='Layout' initialExpanded={true}>
  71. <ParameterControls params={PluginLayoutStateParams} values={this.plugin.layout.latestState} onChange={this.setLayout} />
  72. </ControlGroup>
  73. <ControlGroup header='Viewport' initialExpanded={true}>
  74. <ParameterControls params={Canvas3DParams} values={this.plugin.canvas3d.props} onChange={this.setSettings} />
  75. </ControlGroup>
  76. </div>}
  77. </div>
  78. }
  79. }
  80. export class Viewport extends PluginComponent<{ }, ViewportState> {
  81. private container = React.createRef<HTMLDivElement>();
  82. private canvas = React.createRef<HTMLCanvasElement>();
  83. state: ViewportState = {
  84. noWebGl: false
  85. };
  86. private handleResize = () => {
  87. this.plugin.canvas3d.handleResize();
  88. }
  89. componentDidMount() {
  90. if (!this.canvas.current || !this.container.current || !this.plugin.initViewer(this.canvas.current!, this.container.current!)) {
  91. this.setState({ noWebGl: true });
  92. }
  93. this.handleResize();
  94. const canvas3d = this.plugin.canvas3d;
  95. this.subscribe(canvas3d.input.resize, this.handleResize);
  96. const idHelper = new Canvas3dIdentifyHelper(this.plugin, 15);
  97. this.subscribe(canvas3d.input.move, ({x, y, inside, buttons}) => {
  98. if (!inside || buttons) { return; }
  99. idHelper.move(x, y);
  100. });
  101. this.subscribe(canvas3d.input.leave, () => {
  102. idHelper.leave();
  103. });
  104. this.subscribe(canvas3d.input.click, ({x, y, buttons}) => {
  105. if (buttons !== ButtonsType.Flag.Primary) return;
  106. idHelper.select(x, y);
  107. });
  108. this.subscribe(this.plugin.layout.updated, () => {
  109. setTimeout(this.handleResize, 50);
  110. });
  111. }
  112. componentWillUnmount() {
  113. if (super.componentWillUnmount) super.componentWillUnmount();
  114. // TODO viewer cleanup
  115. }
  116. renderMissing() {
  117. return <div>
  118. <div>
  119. <p><b>WebGL does not seem to be available.</b></p>
  120. <p>This can be caused by an outdated browser, graphics card driver issue, or bad weather. Sometimes, just restarting the browser helps.</p>
  121. <p>For a list of supported browsers, refer to <a href='http://caniuse.com/#feat=webgl' target='_blank'>http://caniuse.com/#feat=webgl</a>.</p>
  122. </div>
  123. </div>
  124. }
  125. render() {
  126. if (this.state.noWebGl) return this.renderMissing();
  127. return <div className='msp-viewport'>
  128. <div className='msp-viewport-host3d' ref={this.container}>
  129. <canvas ref={this.canvas} />
  130. </div>
  131. </div>;
  132. }
  133. }