import { IDocument , ITagNode } from 'svg-vdom' ; import { IParamsOption , IPathResultItem , IRuleOption } from '../../typings' ; import { douglasPeucker } from '../algorithm/douglas-peucker' ; import { LineTypes } from '../const' ; import { checkSubPath } from '../path/check-sub-paths' ; import { doCompute } from '../path/do-compute' ; import { itemMerge } from '../path/item-merge' ; import { lineNormalize } from '../path/line-normalize' ; import { mergePoints } from '../path/merge-points' ; import { parsePath } from '../path/parse' ; import { straighten as straightenPath } from '../path/straighten' ; import { stringifyPath } from '../path/stringify' ; import { checkAnimateAttr , findAnimateAttr , getAnimateAttr } from '../xml/get-animate-attr' ; import { getAttr } from '../xml/get-attr' ; import { parseStyleTree } from '../xml/parse-style-tree' ; const DPInit = ( threshold , pathArr ) : IPathResultItem [ ] => { const pathResult = [ ] ; let len = 0 ; for ( const pathItem of pathArr ) { if ( LineTypes . includes ( pathItem . type ) ) { const lastItem = pathResult [ len - 1 ] ; if ( lastItem . type === 'L' ) { itemMerge ( lastItem , pathItem ) ; } else { pathResult . push ( lineNormalize ( pathItem ) ) ; len ++ ; } } else { const lastItem = pathResult [ len - 1 ] ; if ( len > 0 && lastItem . type === 'L' ) { lastItem . val = douglasPeucker ( threshold , lastItem . from . concat ( lastItem . val ) ) . slice ( 2 ) ; } pathResult . push ( pathItem ) ; len ++ ; } } if ( pathResult [ len - 1 ] . type === 'L' ) { const lastItem = pathResult [ len - 1 ] ; lastItem . val = douglasPeucker ( threshold , lastItem . from . concat ( lastItem . val ) ) . slice ( 2 ) ; } return pathResult ; } ; const processPath = ( dVal , hasMarker , hasStroke , hasStrokeCap , { thinning , sizeDigit , angelDigit , straighten , mergePoint , } ) => { let pathResult = doCompute ( parsePath ( dVal ) ) ; if ( ! hasMarker ) { if ( straighten ) { pathResult = doCompute ( pathResult . map ( p => straightenPath ( straighten , p ) ) ) ; } if ( thinning ) { pathResult = doCompute ( pathResult . map ( p => DPInit ( thinning , p ) ) ) ; } if ( mergePoint ) { pathResult = doCompute ( pathResult . map ( p => mergePoints ( mergePoint , p ) ) ) ; } pathResult = doCompute ( checkSubPath ( pathResult , hasStroke , hasStrokeCap , sizeDigit , angelDigit ) ) ; } if ( pathResult . length ) { return stringifyPath ( pathResult , sizeDigit , angelDigit ) ; } else { return '' ; } } ; export const computePath = async ( dom , { params } ) : Promise < void > => new Promise ( resolve => { parseStyleTree ( dom ) ; const pathNodes = dom . querySelectorAll ( 'path,animateMotion,textPath' ) as ITagNode [ ] ; pathNodes . forEach ( node => { const attrName = node . nodeName === 'path' ? 'd' : 'path' ; const attrD = node . getAttribute ( attrName ) ; const animateAttrs = getAnimateAttr ( node ) ; const hasMarker = getAttr ( node , 'marker-start' , 'none' ) !== 'none' || getAttr ( node , 'marker-mid' , 'none' ) !== 'none' || getAttr ( node , 'marker-end' , 'none' ) !== 'none' ; const hasStroke = getAttr ( node , 'stroke' , 'none' ) !== 'none' && getAttr ( node , 'stroke-width' , '1' ) !== '0' ; const hasStrokeCap = getAttr ( node , 'stroke-linecap' , 'butt' ) !== 'butt' ; let noAttrD = true ; let noAnimateD = true ; if ( attrD ) { const pathResult = processPath ( attrD , hasMarker , hasStroke , hasStrokeCap , params ) ; if ( ! pathResult ) { node . removeAttribute ( attrName ) ; } else { noAttrD = false ; node . setAttribute ( attrName , pathResult ) ; } } if ( node . nodeName !== 'animateMotion' && checkAnimateAttr ( animateAttrs , attrName ) ) { const animateD = findAnimateAttr ( animateAttrs , attrName ) ; animateD . forEach ( item => { const value = item . values . map ( val => processPath ( val , hasMarker , hasStroke , hasStrokeCap , params ) ) ; item . keys . forEach ( ( key , index ) => { if ( key === 'values' ) { const values = value . slice ( index ) . filter ( v => ! ! v ) . join ( ';' ) ; if ( values ) { item . node . setAttribute ( key , values ) ; } else { item . node . removeAttribute ( key ) ; } } else { if ( value [ index ] ) { item . node . setAttribute ( key , value [ index ] ) ; } else { item . node . removeAttribute ( key ) ; } } } ) ; } ) ; if ( node . nodeName === 'path' && checkAnimateAttr ( getAnimateAttr ( node ) , attrName ) ) { noAnimateD = false ; } } if ( noAttrD && noAnimateD && node . nodeName === 'path' ) { node . remove ( ) ; } } ) ; resolve ( ) ; } ) ;