// @Override interpolateValue(start: Path, end: Path, fraction: number) { if (!start || !end || !start.isMorphableWith(end) || !fraction) { return start; } if (fraction === 1) { return end; } return PathUtil.interpolate(start, end, fraction); }
const applySplitsFn = (path: Path, gapGroups: ReadonlyTable<CmdInfo>) => { const splitOps: Array<{ readonly subIdx: number; readonly cmdIdx: number; readonly ts: number[]; }> = []; const numPaths = path.getSubPath(subIdx).getCommands().length; for (let i = gapGroups.length - 1; i >= 0; i--) { const gapGroup = gapGroups[i]; // Clamp the index between 1 and numCommands - 1 to account for cases // where the alignment algorithm attempts to append new commands to the // front and back of the sequence. const cmdIdx = _.clamp(_.last(gapGroup).nextCmdIdx, 1, numPaths - 1); const ts = gapGroup.map((unused, gapIdx) => (gapIdx + 1) / (gapGroup.length + 1)); splitOps.push({ subIdx, cmdIdx, ts }); } PathUtil.sortPathOps(splitOps); const mutator = path.mutate(); for (const { cmdIdx, ts } of splitOps) { mutator.splitCommand(subIdx, cmdIdx, ...ts); } return mutator.build(); };
(layer: VectorLayer | GroupLayer | PathLayer, parentNode: Node) => { if (layer instanceof VectorLayer) { if (withIds) { conditionalAttr(destinationNode, 'id', vl.name, ''); } conditionalAttr(destinationNode, 'opacity', vl.alpha, 1); return parentNode; } if (layer instanceof PathLayer) { const { pathData } = layer; if (!pathData.getPathString()) { return undefined; } const node = xmlDoc.createElement('path'); if (withIds) { conditionalAttr(node, 'id', layer.name); } maybeSetClipPathForLayerFn(node, layer.id); conditionalAttr(node, 'd', pathData.getPathString()); if (layer.fillColor) { conditionalAttr(node, 'fill', ColorUtil.androidToCssHexColor(layer.fillColor), ''); } else { conditionalAttr(node, 'fill', 'none'); } conditionalAttr(node, 'fill-opacity', layer.fillAlpha, 1); if (layer.strokeColor) { conditionalAttr(node, 'stroke', ColorUtil.androidToCssHexColor(layer.strokeColor), ''); } conditionalAttr(node, 'stroke-opacity', layer.strokeAlpha, 1); conditionalAttr(node, 'stroke-width', layer.strokeWidth, 0); if (layer.trimPathStart !== 0 || layer.trimPathEnd !== 1 || layer.trimPathOffset !== 0) { const flattenedTransform = LayerUtil.getCanvasTransformForLayer(vl, layer.id); const { a, d } = flattenedTransform; // Note that we only return the length of the first sub path due to // https://code.google.com/p/android/issues/detail?id=172547 let pathLength: number; if (Math.abs(a) !== 1 || Math.abs(d) !== 1) { // Then recompute the scaled path length. pathLength = pathData .mutate() .transform(flattenedTransform) .build() .getSubPathLength(0); } else { pathLength = pathData.getSubPathLength(0); } const strokeDashArray = PathUtil.toStrokeDashArray( layer.trimPathStart, layer.trimPathEnd, layer.trimPathOffset, pathLength, ).join(','); const strokeDashOffset = PathUtil.toStrokeDashOffset( layer.trimPathStart, layer.trimPathEnd, layer.trimPathOffset, pathLength, ).toString(); conditionalAttr(node, 'stroke-dasharray', strokeDashArray); conditionalAttr(node, 'stroke-dashoffset', strokeDashOffset); } conditionalAttr(node, 'stroke-linecap', layer.strokeLinecap, 'butt'); conditionalAttr(node, 'stroke-linejoin', layer.strokeLinejoin, 'miter'); conditionalAttr(node, 'stroke-miterlimit', layer.strokeMiterLimit, 4); const fillRule = !layer.fillType || layer.fillType === 'nonZero' ? 'nonzero' : 'evenodd'; conditionalAttr(node, 'fill-rule', fillRule, 'nonzero'); parentNode.appendChild(node); return parentNode; } if (layer instanceof GroupLayer) { const node = xmlDoc.createElement('g'); if (withIds) { conditionalAttr(node, 'id', layer.name); } const transformValues: string[] = []; if (layer.translateX || layer.translateY) { transformValues.push(`translate(${layer.translateX} ${layer.translateY})`); } if (layer.rotation) { transformValues.push(`rotate(${layer.rotation} ${layer.pivotX} ${layer.pivotY})`); } if (layer.scaleX !== 1 || layer.scaleY !== 1) { if (layer.pivotX || layer.pivotY) { transformValues.push(`translate(${layer.pivotX} ${layer.pivotY})`); } transformValues.push(`scale(${layer.scaleX} ${layer.scaleY})`); if (layer.pivotX || layer.pivotY) { transformValues.push(`translate(${-layer.pivotX} ${-layer.pivotY})`); } } let nodeToAttachToParent = node; if (transformValues.length) { node.setAttributeNS(undefined, 'transform', transformValues.join(' ')); if (isLayerBeingClippedFn(layer.id)) { // Create a wrapper node so that the clip-path is applied before the transformations. const wrapperNode = xmlDoc.createElement('g'); wrapperNode.appendChild(node); nodeToAttachToParent = wrapperNode; } } maybeSetClipPathForLayerFn(nodeToAttachToParent, layer.id); parentNode.appendChild(nodeToAttachToParent); return node; } return undefined; },
unsplitOpsMap.forEach((ops, idx) => { PathUtil.sortPathOps(ops); ops.forEach(op => pm.unsplitCommand(op.subIdx, op.cmdIdx)); });