import { LayoutOption } from '../../controller/layout/defaultLayouts' ; import ForceLayout , { ForceProps } from '../force/ForceLayout' ; import { LayoutOptionBase , Data , ForceSimulation } from '../../types' ; /** web worker */ import Point from '../force/Point' ; import Vector from '../force/Vector' ; import Spring from '../force/Spring' ; import { getDegree } from '../utils/graph' ; import { Node , Edge } from '../force/Elements' ; import workerFunction from './worker' ; const babelDepString = [ `function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
  function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  var  _objectSpread2 = Object.assign
  ` , ] ; const workerDepString = [ Point . toString ( ) , Vector . toString ( ) , Spring . toString ( ) , Node . toString ( ) , Edge . toString ( ) , getDegree . toString ( ) , ForceLayout . toString ( ) , ] ; export interface ForceLayoutOptions extends ForceProps , LayoutOptionBase { /** 前置布局 */ preset ? : { name : string ; options : LayoutOption ; } ; isOptimization ? : boolean ; } interface Return { data : Data ; simulation : ForceSimulation ; } let globalWorker ; const forceLayout = ( data , options ) : Return => { const { graph , ... others } = options ; if ( globalWorker ) { globalWorker . terminate ( ) ; } /** serialize an object with method */ const optionString = JSON . stringify ( others , ( _key , value ) => { if ( typeof value === 'function' ) { return value . toString ( ) ; } return value ; } , 2 ) ; const workerStringArray = [ ... babelDepString , ... workerDepString , `const forceOptions = ${ optionString };` , workerFunction . toString ( ) , `;workerFunction()` , ] ; /** Build a worker from an anonymous function body */ const blobURL = URL . createObjectURL ( new Blob ( [ '(()=>{' , ... ( workerStringArray as [ string ] ) , '})()' ] , { type : 'application/javascript' , } ) ) ; globalWorker = new Worker ( blobURL ) ; globalWorker . postMessage ( { nodes : data . nodes , edges : data . edges , } ) ; const swap = { } ; let requestAnimationFrameId ; globalWorker . onmessage = ( e ) => { const { forceData , done } = e . data ; if ( requestAnimationFrameId ) window . cancelAnimationFrame ( requestAnimationFrameId ) ; if ( done ) { return ; } if ( ! swap . pre ) { swap . pre = forceData ; } else { swap . current = forceData ; swap . current . nodes . forEach ( ( node , index ) => { const preNode = swap . pre . nodes [ index ] ; let deltaX = ( node . x - preNode . x ) / 60 ; let deltaY = ( node . y - preNode . y ) / 60 ; deltaX = Math . abs ( deltaX ) > 1 ? deltaX : deltaX >= 0 ? 1 : - 1 ; deltaY = Math . abs ( deltaY ) > 1 ? deltaY : deltaY >= 0 ? 1 : - 1 ; preNode . deltaX = deltaX ; preNode . deltaY = deltaY ; } ) ; /** 补间动画 */ const step = ( ) => { swap . pre . nodes . forEach ( ( item ) => { const node = graph . findById ( item . id ) ; const model = node . get ( 'model' ) ; model . x = item . x ; model . y = item . y ; item . x += item . deltaX ; item . y += item . deltaY ; } ) ; graph . refreshPositions ( ) ; requestAnimationFrameId = window . requestAnimationFrame ( step ) ; } ; requestAnimationFrameId = window . requestAnimationFrame ( step ) ; } } ; return { data , simulation : null , } ; } ; export default forceLayout ;