@@ -14,7 +14,9 @@ import {
14
14
MeshBasicMaterial ,
15
15
Euler ,
16
16
PerspectiveCamera ,
17
+ Vector2 ,
17
18
} from 'three' ;
19
+ import html2canvas from 'html2canvas' ;
18
20
import { Configuration } from '../../lib/types/configuration' ;
19
21
import { ControlsManager } from './controls-manager' ;
20
22
import { RendererManager } from './renderer-manager' ;
@@ -755,6 +757,118 @@ export class ThreeManager {
755
757
this . animationsManager . animateClippingWithCollision ( tweenDuration , onEnd ) ;
756
758
}
757
759
760
+ saveBlob = ( function ( ) {
761
+ const a = document . createElement ( 'a' ) ;
762
+ document . body . appendChild ( a ) ;
763
+ a . style . display = 'none' ;
764
+ return function saveData ( blob , fileName ) {
765
+ const url = window . URL . createObjectURL ( blob ) ;
766
+ a . href = url ;
767
+ a . download = fileName ;
768
+ a . click ( ) ;
769
+ } ;
770
+ } ) ( ) ;
771
+
772
+ /**
773
+ * Takes a screen shot of the current view
774
+ * @param width the width of the picture to be created
775
+ * @param height the height of the picture to be created
776
+ * @param fitting the type of fitting to use in case width and height
777
+ * ratio do not match the current screen ratio. Posible values are
778
+ * - Crop : current view is cropped on both side or up and done to fit ratio
779
+ * thus it is not streched, but some parts are lost
780
+ * - Strech : current view is streched to given format
781
+ * this is the default and used also for any other value given to fitting
782
+ */
783
+ public makeScreenShot (
784
+ width : number ,
785
+ height : number ,
786
+ fitting : string = 'Strech'
787
+ ) {
788
+ // compute actual size of screen shot, based on current view and reuested size
789
+ const mainRenderer = this . rendererManager . getMainRenderer ( ) ;
790
+ var originalSize = new Vector2 ( ) ;
791
+ mainRenderer . getSize ( originalSize ) ;
792
+ var scaledHeight = height ;
793
+ var scaledWidth = width ;
794
+ if ( fitting == 'Crop' ) {
795
+ // Massage width and height so that we keep the screen ratio
796
+ // and thus the image from the screen is not streched
797
+ if ( originalSize . width * height < originalSize . height * width ) {
798
+ scaledHeight = ( originalSize . height * width ) / originalSize . width ;
799
+ } else {
800
+ scaledWidth = ( originalSize . width * height ) / originalSize . height ;
801
+ }
802
+ }
803
+ const heightShift = ( scaledHeight - height ) / 2 ;
804
+ const widthShift = ( scaledWidth - width ) / 2 ;
805
+
806
+ // get background color to be used
807
+ var bkgColor = getComputedStyle ( document . body ) . getPropertyValue (
808
+ '--phoenix-background-color'
809
+ ) ;
810
+
811
+ // grab output canvas on which we will draw, and set size
812
+ var outputCanvas = document . getElementById (
813
+ 'screenshotCanvas'
814
+ ) as HTMLCanvasElement ;
815
+ outputCanvas . width = width ;
816
+ outputCanvas . height = height ;
817
+ var ctx = outputCanvas . getContext ( '2d' ) ;
818
+ ctx . fillStyle = bkgColor ;
819
+ ctx . fillRect ( 0 , 0 , width , height ) ;
820
+ // draw main image on our output canvas, with right size
821
+ mainRenderer . setSize ( scaledWidth , scaledHeight , false ) ;
822
+ this . render ( ) ;
823
+ ctx . drawImage (
824
+ mainRenderer . domElement ,
825
+ widthShift ,
826
+ heightShift ,
827
+ width ,
828
+ height ,
829
+ 0 ,
830
+ 0 ,
831
+ width ,
832
+ height
833
+ ) ;
834
+ mainRenderer . setSize ( originalSize . width , originalSize . height , false ) ;
835
+ this . render ( ) ;
836
+
837
+ // Get info panel
838
+ const infoPanel = document . getElementById ( 'experimentInfo' ) ;
839
+ if ( infoPanel != null ) {
840
+ // Compute size of info panel on final picture
841
+ const infoHeight =
842
+ ( infoPanel . clientHeight * scaledHeight ) / originalSize . height ;
843
+ const infoWidth =
844
+ ( infoPanel . clientWidth * scaledWidth ) / originalSize . width ;
845
+
846
+ // Add info panel to output. This is HTML, so first convert it to canvas,
847
+ // and then draw to our output canvas
848
+ html2canvas ( infoPanel , { backgroundColor : bkgColor } ) . then ( ( canvas ) => {
849
+ canvas . toBlob ( ( blob ) => {
850
+ ctx . drawImage (
851
+ canvas ,
852
+ infoHeight / 6 ,
853
+ infoHeight / 6 ,
854
+ infoWidth ,
855
+ infoHeight
856
+ ) ;
857
+ // Finally save to png file
858
+ outputCanvas . toBlob ( ( blob ) => {
859
+ const a = document . createElement ( 'a' ) ;
860
+ document . body . appendChild ( a ) ;
861
+ a . style . display = 'none' ;
862
+ const url = window . URL . createObjectURL ( blob ) ;
863
+ a . href = url ;
864
+ a . download = `screencapture.png` ;
865
+ a . click ( ) ;
866
+ } ) ;
867
+ } ) ;
868
+ } ) ;
869
+ }
870
+ }
871
+
758
872
/**
759
873
* Initialize the VR session.
760
874
* @param xrSessionType Type of the XR session. Either AR or VR.
0 commit comments