import * as SVG from "svgjs" ; import { Node } from "./node" ; /**
 * Separation between each line, measured as the number of pixels between the bottom
 * edge of one line and the top edge of the next.
 */ const lineSeparation = 5 ; interface Point { x : number ; y : number ; } function drawLines ( container ) { let root = < HTMLElement > container . querySelector ( ".qp-root" ) ; let draw = SVG ( root ) ; let clientRect = root . getBoundingClientRect ( ) ; let nodes = root . querySelectorAll ( ".qp-node" ) ; for ( let i = 0 ; i < nodes . length ; i ++ ) { drawLinesForParent ( draw , clientRect , new Node ( nodes [ i ] ) ) ; } } param parent function addPaddingForParent ( parent , padding ) { let qpNodeOuter = parent . element . parentElement ; let paddingElement = qpNodeOuter . parentElement ; paddingElement . style . paddingRight = `${ padding }px` ; } param thicknesses param gap returns function thicknessesToOffsets ( thicknesses , gap ) { let result = [ ] ; let total = thicknesses . reduce ( ( a , b ) => a + b , 0 ) + ( thicknesses . length - 1 ) * gap ; let left = - total / 2 ; for ( let i = 0 ; i < thicknesses . length ; i ++ ) { let right = left + thicknesses [ i ] ; result . push ( ( right + left ) / 2 ) ; left = right + gap ; } return result ; } param node function nodeToThickness ( node ) { const minThickness = 2 ; const maxThickness = 12 ; let rows = 0 ; if ( node . relOp != null ) { rows = node . relOp . actualRows == null ? node . relOp . estimatedRows : node . relOp . actualRows ; } return Math . max ( minThickness , Math . min ( Math . floor ( Math . log ( rows > 0 ? rows : 1 ) ) , maxThickness ) ) ; } param draw param clientRect param parent function drawLinesForParent ( draw , clientRect , parent ) { let children = parent . children ; let thicknesses = children . map ( nodeToThickness ) ; let padding = thicknesses . reduce ( ( a , b ) => a + b , 0 ) + lineSeparation * ( children . length - 1 ) ; addPaddingForParent ( parent , padding ) ; let offsets = thicknessesToOffsets ( thicknesses , lineSeparation ) ; for ( let i = 0 ; i < children . length ; i ++ ) { drawArrowBetweenNodes ( draw , clientRect , parent , children [ i ] , thicknesses [ i ] , offsets [ i ] ) ; } } param draw param clientRect param parent param child param thickness param offset function drawArrowBetweenNodes ( draw , clientRect , parent , child , thickness , offset ) { let parentOffset = parent . element . getBoundingClientRect ( ) ; let childOffset = child . element . getBoundingClientRect ( ) ; let toX = parentOffset . right ; let toY = ( parentOffset . top + parentOffset . bottom ) / 2 ; let fromX = childOffset . left ; let fromY = ( childOffset . top + childOffset . bottom ) / 2 ; if ( Math . abs ( fromY - toY ) < 5 ) { fromY = toY ; } let midOffsetLeft = toX / 2 + fromX / 2 ; let toPoint = { x : toX - clientRect . left + 1 , y : toY - clientRect . top + offset } ; let fromPoint = { x : childOffset . left - clientRect . left - 1 , y : fromY - clientRect . top } ; let bendOffsetX = midOffsetLeft - clientRect . left - offset ; drawArrow ( draw , toPoint , fromPoint , bendOffsetX , thickness , child . nodeId , child . statementId ) ; } param draw param from { x param to { x param bendX param nodeId param statementId function drawArrow ( draw , to , from , bendX , thickness , nodeId , statementId ) { let points = arrowPath ( to , from , bendX , thickness ) ; let line = draw . polyline ( points ) . fill ( "#E3E3E3" ) . stroke ( { color : "#505050" , width : 0.5 } ) . data ( "statement-id" , statementId ) ; if ( nodeId ) { line . data ( "node-id" , nodeId ) ; } } param to param from param bendX param thickness function arrowPath ( to , from , bendX , thickness ) { let w2 = thickness / 2 ; return [ [ to . x , to . y ] , [ to . x + w2 + 2 , to . y - ( w2 + 2 ) ] , [ to . x + w2 + 2 , to . y - w2 ] , [ bendX + ( to . y <= from . y ? w2 : - w2 ) , to . y - w2 ] , [ bendX + ( to . y <= from . y ? w2 : - w2 ) , from . y - w2 ] , [ from . x , from . y - w2 ] , [ from . x , from . y + w2 ] , [ bendX + ( to . y <= from . y ? - w2 : w2 ) , from . y + w2 ] , [ bendX + ( to . y <= from . y ? - w2 : w2 ) , to . y + w2 ] , [ to . x + w2 + 2 , to . y + w2 ] , [ to . x + w2 + 2 , to . y + w2 + 2 ] , [ to . x , to . y ] ] ; } export { drawLines , arrowPath , thicknessesToOffsets , nodeToThickness } ;