Skip to content

Commit

Permalink
transform path blocks after flattening layer
Browse files Browse the repository at this point in the history
  • Loading branch information
alexjlockwood committed Aug 8, 2017
1 parent ecee8fd commit b37c1bf
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 28 deletions.
6 changes: 5 additions & 1 deletion src/app/components/canvas/canvaslayers.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ export class CanvasLayersDirective extends CanvasLayoutMixin(DestroyableMixin())
let pathLength: number;
if (Math.abs(a) !== 1 || Math.abs(d) !== 1) {
// Then recompute the scaled path length.
pathLength = layer.pathData.transform(flattenedTransform).getSubPathLength(0);
pathLength = layer.pathData
.mutate()
.transform(flattenedTransform)
.build()
.getSubPathLength(0);
} else {
pathLength = layer.pathData.getSubPathLength(0);
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/components/layertimeline/layerlisttree.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
Convert to path
</button>
<button *ngIf="model.isMergeable"
(click)="this.onMergeGroupClick($event, layer)"
(click)="this.onFlattenGroupClick($event, layer)"
md-menu-item>
Merge with {{ this.layer.children.length === 1 ? this.layer.children[0].name : 'children layers' }}
Flatten group
</button>
</md-menu>
<button md-icon-button
Expand Down Expand Up @@ -118,7 +118,7 @@
(addTimelineBlockClick)="this.onAddTimelineBlockClick($event.event, $event.layer, $event.propertyName)"
(convertToClipPathClick)="this.onConvertToClipPathClick($event.event, $event.layer)"
(convertToPathClick)="this.onConvertToPathClick($event.event, $event.layer)"
(mergeGroupClick)="this.onMergeGroupClick($event.event, $event.layer)">
(flattenGroupClick)="this.onFlattenGroupClick($event.event, $event.layer)">
</app-layerlisttree>
</li>
</ul>
Expand Down
26 changes: 18 additions & 8 deletions src/app/components/layertimeline/layerlisttree.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class LayerListTreeComponent implements OnInit, Callbacks {
@Output() addTimelineBlockClick = new EventEmitter<TimelineBlockEvent>();
@Output() convertToClipPathClick = new EventEmitter<LayerEvent>();
@Output() convertToPathClick = new EventEmitter<LayerEvent>();
@Output() mergeGroupClick = new EventEmitter<LayerEvent>();
@Output() flattenGroupClick = new EventEmitter<LayerEvent>();

constructor(
private readonly store: Store<State>,
Expand All @@ -52,15 +52,25 @@ export class LayerListTreeComponent implements OnInit, Callbacks {
const availablePropertyNames = Array.from(
ModelUtil.getAvailablePropertyNamesForLayer(this.layer, animation),
);
const existingPropertyNames = Array.from(
_.keys(ModelUtil.getOrderedBlocksByPropertyByLayer(animation)[this.layer.id]),
);
const getExistingPropertyNamesFn = (layerId: string) => {
return _.keys(ModelUtil.getOrderedBlocksByPropertyByLayer(animation)[layerId]);
};
const existingPropertyNames = getExistingPropertyNamesFn(this.layer.id);
const isClipPathLayer = this.layer instanceof ClipPathLayer;
const isPathLayer = this.layer instanceof PathLayer;
const isMergeable =
this.layer instanceof GroupLayer &&
this.layer.children.length > 0 &&
existingPropertyNames.length === 0;
// TODO: allow merging groups w/ existing blocks in some cases?
existingPropertyNames.length === 0 &&
this.layer.children.every(l => {
return (
l instanceof PathLayer ||
l instanceof ClipPathLayer ||
// TODO: allow merging groups into groups w/ existing blocks in some cases?
getExistingPropertyNamesFn(l.id).length === 0
);
});
return {
animation,
isSelected: selectedLayerIds.has(this.layer.id),
Expand Down Expand Up @@ -131,9 +141,9 @@ export class LayerListTreeComponent implements OnInit, Callbacks {
}

// @Override Callbacks
onMergeGroupClick(event: MouseEvent, layer: Layer) {
onFlattenGroupClick(event: MouseEvent, layer: Layer) {
if (!this.actionModeService.isActionMode()) {
this.mergeGroupClick.emit({ event, layer });
this.flattenGroupClick.emit({ event, layer });
}
}

Expand All @@ -155,7 +165,7 @@ export interface Callbacks {
onAddTimelineBlockClick(event: MouseEvent, layer: Layer, propertyName: string): void;
onConvertToClipPathClick(event: MouseEvent, layer: Layer): void;
onConvertToPathClick(event: MouseEvent, layer: Layer): void;
onMergeGroupClick(event: MouseEvent, layer: Layer): void;
onFlattenGroupClick(event: MouseEvent, layer: Layer): void;
}

// tslint:disable: no-unused-variable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
(addTimelineBlockClick)="this.onAddTimelineBlockClick($event.event, $event.layer, $event.propertyName)"
(convertToClipPathClick)="this.onConvertToClipPathClick($event.event, $event.layer)"
(convertToPathClick)="this.onConvertToPathClick($event.event, $event.layer)"
(mergeGroupClick)="this.onMergeGroupClick($event.event, $event.layer)">
(flattenGroupClick)="this.onFlattenGroupClick($event.event, $event.layer)">
</app-layerlisttree>
</div>
<div *ngIf="(this.dragIndicatorObservable | async) as dragData"
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/layertimeline/layertimeline.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,8 +767,8 @@ export class LayerTimelineComponent extends DestroyableMixin()
}

// @Override LayerListTreeComponentCallbacks
onMergeGroupClick(event: MouseEvent, layer: Layer) {
this.layerTimelineService.mergeGroupLayer(layer.id);
onFlattenGroupClick(event: MouseEvent, layer: Layer) {
this.layerTimelineService.flattenGroupLayer(layer.id);
}

// @Override LayerListTreeComponentCallbacks
Expand Down
6 changes: 5 additions & 1 deletion src/app/scripts/export/SvgSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ function vectorLayerToSvgNode(
let pathLength: number;
if (Math.abs(a) !== 1 || Math.abs(d) !== 1) {
// Then recompute the scaled path length.
pathLength = layer.pathData.transform(flattenedTransform).getSubPathLength(0);
pathLength = layer.pathData
.mutate()
.transform(flattenedTransform)
.build()
.getSubPathLength(0);
} else {
pathLength = layer.pathData.getSubPathLength(0);
}
Expand Down
16 changes: 13 additions & 3 deletions src/app/scripts/import/SvgLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ function loadVectorLayerFromSvgString(
if (!refClipPathId) {
return layer;
}
const paths = (clipPathMap[refClipPathId] || []).map(p => p.transform(flattenedTransforms));
const paths = (clipPathMap[refClipPathId] || []).map(p => {
return new Path(p.mutate().transform(flattenedTransforms).build().getPathString());
});
if (!paths.length) {
// If the clipPath has no children, then clip the entire layer.
paths.push(new Path('M 0 0 Z'));
Expand Down Expand Up @@ -153,7 +155,9 @@ function loadVectorLayerFromSvgString(

let pathData = new Path(path);
if (transforms.length) {
pathData = pathData.transform(flattenedTransforms);
pathData = new Path(
pathData.mutate().transform(flattenedTransforms).build().getPathString(),
);
strokeWidth = MathUtil.round(strokeWidth * flattenedTransforms.getScaleFactor());
}
// TODO: make best effort attempt to restore trimPath{Start,End,Offset}
Expand Down Expand Up @@ -321,7 +325,13 @@ function buildPathInfosForClipPath(node: SVGClipPathElement) {
const refClipPathId = getReferencedClipPathId(childNode);
pathInfos.push({
refClipPathId,
path: new Path(pathStr).transform(Matrix.flatten(transforms)),
path: new Path(
new Path(pathStr)
.mutate()
.transform(Matrix.flatten(transforms))
.build()
.getPathString(),
),
});
}
}
Expand Down
27 changes: 18 additions & 9 deletions src/app/services/layertimeline.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
PathLayer,
VectorLayer,
} from 'app/model/layers';
import { Animation, AnimationBlock } from 'app/model/timeline';
import { Animation, AnimationBlock, PathAnimationBlock } from 'app/model/timeline';
import { Matrix, ModelUtil } from 'app/scripts/common';
import { State, Store } from 'app/store';
import {
Expand Down Expand Up @@ -252,8 +252,9 @@ export class LayerTimelineService {

/**
* Merges the specified group layer into its children layers.
* TODO: make it possible to merge groups that contain animation blocks?
*/
mergeGroupLayer(layerId: string) {
flattenGroupLayer(layerId: string) {
const vl = this.getVectorLayer();
const layer = vl.findLayerById(layerId) as GroupLayer;
if (!layer.children.length) {
Expand Down Expand Up @@ -284,7 +285,7 @@ export class LayerTimelineService {
return l;
}
const clonedLayer = l.clone();
clonedLayer.pathData = path.transform(layerTransform);
clonedLayer.pathData = path.mutate().transform(layerTransform).build();
return clonedLayer;
});
const parent = LayerUtil.findParent(vl, layerId).clone();
Expand All @@ -295,12 +296,20 @@ export class LayerTimelineService {
new SetVectorLayer(LayerUtil.updateLayer(vl, parent)),
...this.buildCleanupLayerIdActions(layerId),
];
const animation = this.getAnimation();
if (animation.blocks.some(b => b.layerId === layerId)) {
const newAnimation = animation.clone();
newAnimation.blocks = newAnimation.blocks.filter(b => b.layerId !== layerId);
actions.push(new SetAnimation(newAnimation));
}
const newAnimation = this.getAnimation().clone();
// TODO: show a dialog if the user is about to unknowingly delete any blocks?
newAnimation.blocks = newAnimation.blocks.filter(b => b.layerId !== layerId);
// TODO: also attempt to merge children group animation blocks?
newAnimation.blocks = newAnimation.blocks.map(b => {
if (!(b instanceof PathAnimationBlock)) {
return b;
}
const block = b.clone();
block.fromValue = block.fromValue.mutate().transform(layerTransform).build();
block.toValue = block.toValue.mutate().transform(layerTransform).build();
return block;
});
actions.push(new SetAnimation(newAnimation));
this.store.dispatch(new MultiAction(...actions));
}

Expand Down

0 comments on commit b37c1bf

Please sign in to comment.