示例#1
0
 // @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);
 }
示例#2
0
 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();
 };
示例#3
0
    (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));
 });