SlideEditor.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import React, { useEffect, useCallback, useMemo } from 'react'
  21. import { useDispatch, useSelector } from 'react-redux'
  22. import html2canvas from 'html2canvas'
  23. import pick from 'lodash/pick'
  24. import {
  25. makeSelectCurrentDisplay,
  26. makeSelectCurrentSlide
  27. } from 'containers/Viz/selectors'
  28. import {
  29. makeSelectCurrentLayerList,
  30. makeSelectCurrentLayersOperationInfo,
  31. makeSelectCurrentSelectedLayerList
  32. } from '../selectors'
  33. import { DisplayActions } from '../actions'
  34. import SplitPane from 'components/SplitPane'
  35. import {
  36. DisplayContainer,
  37. DisplayBottom,
  38. SlideContainer,
  39. SlideBackground,
  40. SlideContent
  41. } from '../components/Container'
  42. import LayerList from '../components/Layer/List'
  43. import SlideLayerList from './SlideLayerList'
  44. import SlideBaselines from './SlideBaselines'
  45. import { LayerOperations } from '../components/constants'
  46. import { DeltaPosition } from '../components/types'
  47. import { DragTriggerTypes } from '../constants'
  48. import { ILayerOperationInfo } from 'app/containers/Display/components/types'
  49. import { SecondaryGraphTypes } from 'app/containers/Display/components/Setting'
  50. const SlideEditor: React.FC = () => {
  51. const dispatch = useDispatch()
  52. const {
  53. id: displayId,
  54. config: { displayParams }
  55. } = useSelector(makeSelectCurrentDisplay())
  56. const currentSlide = useSelector(makeSelectCurrentSlide())
  57. const currentLayerList = useSelector(makeSelectCurrentLayerList())
  58. const layersOperationInfo = useSelector(
  59. makeSelectCurrentLayersOperationInfo()
  60. )
  61. const currentSelectedLayerList = useSelector(
  62. makeSelectCurrentSelectedLayerList()
  63. )
  64. const {
  65. id: slideId,
  66. config: { slideParams }
  67. } = currentSlide
  68. useEffect(() => {
  69. dispatch(DisplayActions.loadSlideDetail(displayId, slideId))
  70. }, [displayId, slideId])
  71. useEffect(() => {
  72. const selectLayerLabel = currentSelectedLayerList.some((item) => SecondaryGraphTypes.Label === item.subType)
  73. if (!selectLayerLabel && currentSelectedLayerList.length > 0) {
  74. refBackground.current.focus()
  75. }
  76. }, [layersOperationInfo])
  77. const refContent = React.useRef<HTMLDivElement>(null)
  78. const refBackground = React.useRef() as React.MutableRefObject<HTMLInputElement>
  79. const doLayerOperation = useCallback(
  80. (operation: LayerOperations) => {
  81. switch (operation) {
  82. case LayerOperations.Copy:
  83. dispatch(DisplayActions.copySlideLayers())
  84. break
  85. case LayerOperations.Paste:
  86. dispatch(DisplayActions.pasteSlideLayers())
  87. break
  88. case LayerOperations.Delete:
  89. dispatch(DisplayActions.deleteSlideLayers(displayId, slideId))
  90. break
  91. case LayerOperations.Undo:
  92. // @TODO
  93. break
  94. case LayerOperations.Redo:
  95. // @TODO
  96. break
  97. }
  98. },
  99. [displayId, slideId]
  100. )
  101. const changeLayersPosition = useCallback(
  102. (
  103. deltaPosition: DeltaPosition,
  104. scale: number,
  105. eventTrigger: DragTriggerTypes
  106. ) => {
  107. dispatch(
  108. DisplayActions.dragLayer(
  109. pick(slideParams, 'width', 'height'),
  110. scale,
  111. deltaPosition,
  112. eventTrigger,
  113. false
  114. )
  115. )
  116. },
  117. [slideParams]
  118. )
  119. const commandLayers = useCallback((operation) => {
  120. dispatch(DisplayActions.changeLayersStack(operation))
  121. }, [])
  122. const selectionChange = useCallback(
  123. (layerId: number, checked: boolean, exclusive: boolean) => {
  124. refBackground.current.focus()
  125. dispatch(DisplayActions.selectLayer(layerId, checked, exclusive))
  126. },
  127. []
  128. )
  129. const onLayerOperationInfoChange = useCallback((changedInfo: Pick<Partial<ILayerOperationInfo>, 'selected'| 'editing'>) => {
  130. dispatch(DisplayActions.clearLayersOperationInfo(changedInfo))
  131. }, [])
  132. const createCover = useCallback(() => {
  133. const { transform, transition } = refContent.current.style
  134. refContent.current.style.transform = ''
  135. refContent.current.style.transition = 'none'
  136. html2canvas(refContent.current, { useCORS: true }).then((canvas) => {
  137. canvas.toBlob((blob) => {
  138. dispatch(DisplayActions.uploadCurrentSlideCover(blob, currentSlide))
  139. refContent.current.style.transform = transform
  140. refContent.current.style.transition = transition
  141. })
  142. })
  143. }, [refContent.current, currentSlide])
  144. const grid = useMemo(() => displayParams && displayParams.grid, [
  145. displayParams
  146. ])
  147. return (
  148. <SplitPane
  149. className="display-layout-content"
  150. type="horizontal"
  151. initialSize={240}
  152. minSize={160}
  153. maxSize={480}
  154. invert
  155. >
  156. <DisplayContainer grid={grid}>
  157. <SlideContainer slideId={slideId} slideParams={slideParams}>
  158. <SlideBackground
  159. parentRef={refBackground}
  160. autoFit
  161. className="display-slide-background-grid"
  162. onChangeLayersPosition={changeLayersPosition}
  163. onDoLayerOperation={doLayerOperation}
  164. onRemoveLayerOperationInfo={onLayerOperationInfoChange}
  165. >
  166. <SlideContent ref={refContent}>
  167. <SlideLayerList />
  168. <SlideBaselines />
  169. </SlideContent>
  170. </SlideBackground>
  171. </SlideContainer>
  172. <DisplayBottom onCreateCover={createCover} />
  173. </DisplayContainer>
  174. <LayerList
  175. layers={currentLayerList}
  176. selection={layersOperationInfo}
  177. onCommand={commandLayers}
  178. onSelectionChange={selectionChange}
  179. />
  180. </SplitPane>
  181. )
  182. }
  183. export default SlideEditor