JavaScript에서 맞춤 애니메이션 동작 생성 및 수정
개요
사용자 지정 애니메이션 동작을 사용하면 색상 변경, 도형 회전, 편집 가능한 움직임 경로 따르기와 같은 애니메이션 효과 내 개별 작업을 제어할 수 있습니다. 이 가이드는 동작을 생성하고 결합하는 방법, 타이밍을 구성하는 방법, 기존 애니메이션을 검사 및 수정하는 방법, 그리고 속성이 프레젠테이션을 저장하고 다시 열 때 유지되는지 확인하는 방법을 보여줍니다.
미리 정의된 효과 및 클릭 트리거에 대해서는 도형 애니메이션을 참조하십시오.
애니메이션 모델 이해
애니메이션은 타임라인 → 시퀀스 → 이펙트 → 동작으로 구성됩니다:
getTimeline메서드는 슬라이드 타임라인을 반환하며, 여기에는 기본 시퀀스와 대화형 시퀀스가 포함됩니다.Sequence는 효과를 포함하며, 서로 다른 도형을 대상으로 할 수 있습니다.Effect는 대상 도형, 프리셋, 서브타입 및 효과 타이밍을 식별합니다.Effect.getBehaviors가 반환하는 컬렉션에는 효과를 구현하는 작업이 들어 있습니다: 색상 변경, 이동, 회전, 속성 설정 등.
개별 동작 만들기
Sequence.addEffect를 호출하여 효과를 만들고 getBehaviors 컬렉션에 접근합니다. 프리셋은 이 컬렉션을 자동으로 채울 수 있습니다. 프리셋을 확장할 때는 기존 작업을 유지하고, 의도적으로 교체할 경우 clear를 사용하십시오.
BehaviorFactory는 아래에 표시된 8가지 동작 유형을 생성합니다. 움직임은 경로 만들기에서 다룹니다. 각 스니펫에는 모듈 임포트가 포함되어 있으며 aspose.slides.via.java 및 java 패키지가 설치된 Node.js 스크립트로 실행할 수 있습니다. 출력 파일을 읽는 예제보다 파일 생성 예제를 먼저 실행하십시오. 이후 편집 예제에서는 사용되는 출력 파일을 명시합니다.
회전
createRotationEffect를 사용하여 회전을 생성합니다. getBy는 상대 각도를 도 단위로 지정하고, getFrom과 getTo는 시작점과 끝점을 지정합니다.
예제는 Spin 효과로 시작하여 프리셋 작업을 하나의 회전 동작으로 교체하고 해당 작업에 2초 지속시간을 부여합니다. 90도의 상대 각도는 도형의 초기 방향에서 1/4 회전을 의미하므로 명시적인 시작 각도가 필요하지 않습니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.Spin, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const rotation = factory.createRotationEffect();
rotation.setBy(90);
rotation.getTiming().setDuration(2);
effect.getBehaviors().add(rotation);
presentation.save("rotation.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
rotation.pptx에는 하나의 도형과 하나의 회전 동작이 포함되어 있습니다. 아래의 컬렉션, 타이밍 및 회전 편집 예제는 이 파일을 사용합니다.
크기 조정
createScaleEffect를 X/Y 백분율과 함께 사용합니다: getFrom 및 getTo는 시작 및 종료 크기를 나타내고, getBy는 상대적인 변화를 나타냅니다. 여기서 100은 원래 크기를 의미합니다.
예제는 두 차원을 100%에서 125%로 2초 동안 확대합니다. 가로와 세로 백분율을 동일하게 사용하면 도형의 비율이 유지되며, 서로 다르게 설정하면 한 차원이 다른 차원보다 더 늘어납니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.GrowShrink, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const scale = factory.createScaleEffect();
scale.setFrom(java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(100), java.newFloat(100)));
scale.setTo(java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(125), java.newFloat(125)));
scale.getTiming().setDuration(2);
effect.getBehaviors().add(scale);
presentation.save("scale.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
색상
createColorEffect를 사용하여 채우기 색상을 파란색에서 주황색으로 변경합니다. getFrom과 getTo는 색상이며, getBy는 색상 오프셋입니다. Behavior.getProperties는 애니메이션되는 속성을 식별합니다.
도형의 단색 채우기는 파란색으로 초기화되어 애니메이션 시작 색상과 일치합니다. fill-color 속성을 선택하면 동작이 도형의 어떤 부분을 변경할지 알 수 있게 되며, 색상 끝점만으로는 해당 속성을 식별할 수 없습니다. 저장된 효과는 2초 동안 주황색으로 전환함을 설명합니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
shape.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
shape.getFillFormat().getSolidFillColor().setColor(java.getStaticFieldValue("java.awt.Color", "BLUE"));
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.ChangeFillColor, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const color = factory.createColorEffect();
color.getProperties().add(aspose.slides.BehaviorProperty.getFillColor().getValue());
color.getFrom().setColor(java.getStaticFieldValue("java.awt.Color", "BLUE"));
const orange = java.newInstanceSync("java.awt.Color", 255, 165, 0);
color.getTo().setColor(orange);
color.getTiming().setDuration(2);
effect.getBehaviors().add(color);
presentation.save("color.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
필터
createFilterEffect를 사용하여 와이프를 선택합니다. getType, getSubtype, getReveal는 필터, 방향 및 도형을 표시하거나 숨길지를 지정합니다.
이 예제는 오른쪽 방향 서브타입을 사용하여 도형을 표시하는 2초 와이프를 구성합니다. 필터 설정은 효과 내부 동작에 속하므로 프리셋의 원래 작업을 제거한 후에 설정됩니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.Wipe, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const filter = factory.createFilterEffect();
filter.setType(aspose.slides.FilterEffectType.Wipe);
filter.setSubtype(aspose.slides.FilterEffectSubtype.Right);
filter.setReveal(aspose.slides.FilterEffectRevealType.In);
filter.getTiming().setDuration(2);
effect.getBehaviors().add(filter);
presentation.save("filter.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
속성
createPropertyEffect를 사용하여 불투명도를 애니메이션합니다. getFrom, getTo, getBy는 문자열이며 getValueType 및 getCalcMode를 통해 해석됩니다. 세 값을 모두 무작위로 설정하기보다 끝점이나 상대 오프셋을 선택하십시오.
여기서 선택된 속성은 불투명도이며, 숫자 문자열은 25% 불투명도에서 완전한 불투명도로의 변화를 나타냅니다. 선형 보간은 해당 값들 사이의 점진적인 변화를 설명합니다. 이 예제를 다른 속성에 적용할 경우 해당 속성에 맞는 값 유형과 끝점 값을 선택하십시오.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.Fade, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const property = factory.createPropertyEffect();
property.getProperties().add(aspose.slides.BehaviorProperty.getStyleOpacity().getValue());
property.setValueType(aspose.slides.PropertyValueType.Number);
property.setCalcMode(aspose.slides.PropertyCalcModeType.Linear);
property.setFrom("0.25");
property.setTo("1");
property.getTiming().setDuration(2);
effect.getBehaviors().add(property);
presentation.save("property.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
설정
createSetEffect를 사용하여 getTo를 통해 가시성을 할당합니다. set 동작은 끝점 사이를 보간하지 않습니다.
예제는 가시성 속성을 선택하고 동작이 실행될 때 문자열 visible을 할당합니다. 이 최소 프레젠테이션에서 사각형은 이미 보이므로 할당만으로 눈에 띄는 시각적 변화가 없을 수 있습니다. 이러한 작업은 도형이 언제 숨겨지거나 보이게 할지를 제어하는 큰 효과의 일부로 유용합니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.Appear, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const set = factory.createSetEffect();
set.getProperties().add(aspose.slides.BehaviorProperty.getStyleVisibility().getValue());
set.setTo("visible");
effect.getBehaviors().add(set);
presentation.save("set.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
명령
createCommandEffect를 사용하고 getType, getCommandString, getShapeTarget을 구성합니다. 작업 디렉터리에 sample.wav라는 WAV 녹음을 배치하십시오. 이 예제는 addAudioFrameEmbedded로 이를 삽입하고 오디오 프레임에 재생 명령을 연결합니다.
오디오 프레임은 효과와 명령 모두의 대상입니다. 이는 재생 요청을 삽입된 녹음에 연결하며, 명령 문자열만으로는 제어할 미디어 객체를 식별하지 못합니다. 효과는 슬라이드 쇼 중 클릭 시 시작하도록 구성됩니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const audioStream = java.newInstanceSync("java.io.FileInputStream", "sample.wav");
try {
const audioFrame = slide.getShapes().addAudioFrameEmbedded(100, 100, 40, 40, audioStream);
const effect = slide.getTimeline().getMainSequence().addEffect(audioFrame, aspose.slides.EffectType.MediaPlay, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const command = factory.createCommandEffect();
command.setType(java.newByte(aspose.slides.CommandEffectType.Call));
command.setCommandString("play");
command.setShapeTarget(audioFrame);
effect.getBehaviors().add(command);
presentation.save("command.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
audioStream.close();
}
} finally {
presentation.dispose();
}
저장하면 command.pptx에 명령이 저장되며, 녹음은 재생되지 않습니다. 재생하려면 해당 명령과 미디어 대상을 지원하는 슬라이드 쇼 플레이어가 필요합니다.
동작 컬렉션 관리
BehaviorCollection은 add, insert, remove, removeAt를 지원합니다. 이 예제는 rotation.pptx를 열어 크기 조정을 추가하고 회전 앞에 이동시킨 다음 회전을 제거합니다. 동일 객체를 제거하고 다시 삽입하면 복사하지 않고 저장된 위치가 바뀝니다.
편집 순서는 컬렉션을 rotation–scale에서 scale–rotation으로, 그리고 scale만 남도록 변경합니다. 인덱스는 현재 컬렉션을 기준하므로 재정렬 후 회전의 새로운 인덱스를 사용해 제거합니다. 최종 열거는 어떤 동작이 저장될지 확인합니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("rotation.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const behaviors = effect.getBehaviors();
const factory = new aspose.slides.BehaviorFactory();
const scale = factory.createScaleEffect();
scale.setTo(java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(125), java.newFloat(125)));
scale.getTiming().setDuration(2);
behaviors.add(scale);
behaviors.remove(scale);
behaviors.insert(0, scale);
behaviors.removeAt(1);
for (let i = 0; i < behaviors.getCount(); i++) {
const behavior = behaviors.get_Item(i);
console.log(behavior.getClass().getSimpleName());
}
presentation.save("collection-edited.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
출력은 ScaleEffect이며, 크기 조정만 남습니다. 컬렉션 순서 자체만으로 동작을 연속적으로 예약하지는 않습니다. 모든 작업을 교체할 때만 컬렉션을 비우십시오.
동작 타이밍 구성
Behavior.getTiming은 Timing을 노출하며, Effect.getTiming과 독립적입니다. 효과 타이밍은 전체 효과를 스케줄링하고, 동작 타이밍은 그 안의 작업을 설명합니다.
지속시간, 지연, 반복 및 가속 설정
rotation.pptx를 열어 지속시간(getDuration)과 트리거 지연시간(getTriggerDelayTime)을 초 단위로 설정하고, setRepeatCount로 반복 횟수를 구성합니다. getAccelerate와 getDecelerate는 지속시간의 비율이며, 합계가 1을 초과하지 않도록 합니다.
입력 파일은 회전 예제에서 만든 파일이며, 첫 번째 동작이 회전임이 알려져 있습니다. 이 예제는 해당 동작의 타이밍만 변경하고 90도 각도는 그대로 유지합니다. 각도와 타이밍을 별도로 유지하면 애니메이션을 다시 만들지 않고도 속도를 조절하기 쉽습니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("rotation.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const rotation = effect.getBehaviors().get_Item(0);
rotation.getTiming().setDuration(2);
rotation.getTiming().setTriggerDelayTime(java.newFloat(0.5));
rotation.getTiming().setRepeatCount(3);
rotation.getTiming().setAccelerate(java.newFloat(0.2));
rotation.getTiming().setDecelerate(java.newFloat(0.2));
presentation.save("timing.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
동작은 2초 지속시간, 0.5초 지연, 반복 횟수 3을 사용합니다. 지속시간의 앞과 뒤 20%가 가속 및 감속에 사용됩니다.
다른 반복 정책으로는 getRepeatDuration, getRepeatUntilEndSlide, getRepeatUntilNextClick이 있으며, 모두 동시에 활성화하기보다 하나를 선택하십시오. getAutoReverse는 순방향 재생 후 애니메이션을 역방향으로 재생합니다. 가속 및 감속은 연속적인 변화에 적용되며, 이산 할당이나 명령에는 적용되지 않습니다.
움직임 경로 만들기
createMotionEffect를 사용하여 움직임을 생성합니다. getFrom, getTo, getBy는 백분율 기반 좌표 또는 오프셋을 설명합니다. 편집 가능한 경로를 만들려면 MotionPath를 생성하고 MotionEffect.setPath로 할당합니다. MotionPath는 경로 명령을 저장합니다.
MotionCommandPathType은 작업을 선택합니다:
| Command | Points | Meaning |
|---|---|---|
| MoveTo | One | 시작 위치를 설정합니다. |
| LineTo | One | 직선 구간을 끝점까지 이동합니다. |
| CurveTo | Three | 두 개의 제어점과 끝점으로 정의된 3차 곡선을 따릅니다. |
| CloseLoop | None | 시작 위치로 돌아갑니다. |
| End | None | 경로를 종료합니다. |
MotionPathPointsType은 코너 혹은 스무스 포인트와 같은 점 편집 특성을 설명합니다. 이는 명령 유형을 대체하지 않습니다. 아래 곡선 예제에서는 곡선 포인트 유형을, 직선 구간에서는 코너 포인트 유형을 사용하십시오.
경로 좌표는 슬라이드 크기에 정규화됩니다: X 변위 0.25는 슬라이드 너비의 1/4을 의미하며, 0.25 포인트가 아닙니다. Y 양수는 아래쪽으로 진행합니다. 절대 명령은 경로 좌표계에서 위치를 지정하고, 상대 명령은 현재 위치에서의 오프셋을 지정합니다. 이는 getOrigin이 경로의 기준 프레임을 선택하고, getPathEditMode가 도형 이동 시 경로가 어떻게 움직이는지를 제어하는 것과는 별개입니다.
직선 경로 만들기
시작점, 하나의 직선 구간, 종료 명령으로 움직임 동작을 만듭니다. MotionPath.add는 명령 유형, 점들, 점 유형, 상대 좌표 플래그를 받습니다.
시작 명령은 (0, 0)을 설정하고, 직선은 (0.25, 0)에서 끝나 슬라이드 폭의 1/4에 해당하는 수평 변위를 제공합니다. 종료 명령은 좌표 점이 없습니다. 경로를 할당한 후, 효과에 움직임 동작을 추가하면 해당 경로가 사각형에 연결됩니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, 100, 100, 160, 80);
const effect = slide.getTimeline().getMainSequence().addEffect(shape, aspose.slides.EffectType.PathRight, aspose.slides.EffectSubtype.None, aspose.slides.EffectTriggerType.OnClick);
effect.getBehaviors().clear();
const factory = new aspose.slides.BehaviorFactory();
const motion = factory.createMotionEffect();
motion.setOrigin(aspose.slides.MotionOriginType.Layout);
motion.getTiming().setDuration(2);
const path = new aspose.slides.MotionPath();
path.add(aspose.slides.MotionCommandPathType.MoveTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0), java.newFloat(0))]), aspose.slides.MotionPathPointsType.Auto, false);
path.add(aspose.slides.MotionCommandPathType.LineTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.25), java.newFloat(0))]), aspose.slides.MotionPathPointsType.Corner, false);
path.add(aspose.slides.MotionCommandPathType.End, java.newArray("java.awt.geom.Point2D$Float", []), aspose.slides.MotionPathPointsType.None, false);
motion.setPath(path);
effect.getBehaviors().add(motion);
presentation.save("motion.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
motion.pptx에는 세 개의 경로 명령을 가진 하나의 움직임 동작이 포함됩니다. 아래 파일 편집 예제는 이 알려진 구조를 사용합니다.
절대 좌표와 상대 좌표 비교
이 두 경로 객체는 동일한 경로를 설명합니다. 절대 명령은 (0.3, 0.1)에서 끝나고, 상대 명령은 현재 위치 (0.2, 0)에 (0.1, 0.1)을 더합니다.
두 경로 모두 같은 위치에서 시작합니다. 상대 직선의 경우 X와 Y 오프셋을 현재 위치에 더해 끝점을 얻고, 절대 직선은 직접 끝점을 읽습니다. 좌표를 변환하지 않고 플래그만 전환하면 다른 경로가 됩니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const absolutePath = new aspose.slides.MotionPath();
absolutePath.add(aspose.slides.MotionCommandPathType.MoveTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.2), java.newFloat(0))]), aspose.slides.MotionPathPointsType.Auto, false);
absolutePath.add(aspose.slides.MotionCommandPathType.LineTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.3), java.newFloat(0.1))]), aspose.slides.MotionPathPointsType.Corner, false);
const relativePath = new aspose.slides.MotionPath();
relativePath.add(aspose.slides.MotionCommandPathType.MoveTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.2), java.newFloat(0))]), aspose.slides.MotionPathPointsType.Auto, false);
relativePath.add(aspose.slides.MotionCommandPathType.LineTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.1), java.newFloat(0.1))]), aspose.slides.MotionPathPointsType.Corner, true);
두 경로 중 하나를 움직임 동작에 할당하여 프레젠테이션에서 사용할 수 있습니다. 마지막 Boolean 인자는 해당 명령에 상대 좌표를 선택합니다.
직선을 곡선으로 교체
motion.pptx를 열어 직선 명령을 삼차 곡선으로 교체합니다. 먼저 두 개의 제어점을 제공하고 그 뒤에 끝점을 제공합니다.
시작 위치는 이전 명령에 의해 제공됩니다. 첫 두 점은 곡선을 형성하고, 세 번째는 목적지이며, 연속된 세 목적지가 아닙니다. 명령 유형, 점 편집 유형 및 점 배열을 함께 업데이트하면 세그먼트가 새로운 기하학에 일관됩니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("motion.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const motion = effect.getBehaviors().get_Item(0);
const path = motion.getPath();
path.get_Item(1).setCommandType(aspose.slides.MotionCommandPathType.CurveTo);
path.get_Item(1).setPointsType(aspose.slides.MotionPathPointsType.CurveSmooth);
path.get_Item(1).setPoints(java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.1), java.newFloat(0)), java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.2), java.newFloat(0.1)), java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.3), java.newFloat(0.1))]));
presentation.save("curve.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
curve.pptx의 경로는 여전히 세 개의 명령을 갖으며, 중간 명령이 이제 곡선을 정의합니다.
저장된 경로 검사 및 편집
각 MotionCmdPath는 getPoints, getCommandType, getPointsType, isRelative를 노출합니다. 아래 예제는 motion.pptx에 있는 세 개 명령 경로를 사용합니다. 임의 입력의 경우, 효과를 찾고 인덱스로 편집하기 전 명령 유형 및 점 개수를 확인하십시오.
명령 및 좌표 읽기
경로를 변경하지 않고 읽습니다. End와 CloseLoop 명령은 점이 필요 없으므로 null 점 배열을 허용합니다.
출력은 각 숫자형 명령 유형을 점 목록 전에 상대 좌표 플래그와 짝지어 표시합니다. 이는 경로를 수정하기 전에 끝점과 오프셋을 구분할 수 있게 합니다. 곡선은 세 개의 점을 나열하고, 이 파일의 직선은 하나만 나열합니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("motion.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const motion = effect.getBehaviors().get_Item(0);
const path = motion.getPath();
for (let i = 0; i < path.getCount(); i++) {
const segment = path.get_Item(i);
console.log(segment.getCommandType() + ", relative: " + segment.isRelative());
const points = segment.getPoints();
if (points != null) {
for (const point of points) {
console.log("X=" + point.getX() + ", Y=" + point.getY());
}
}
}
} finally {
presentation.dispose();
}
목록에는 시작점, (0.25, 0)에서 끝나는 절대 직선, 그리고 종료 명령이 포함됩니다.
끝점 변경
motion.pptx를 열어 직선의 점 배열을 교체하여 끝점을 이동합니다.
입력 파일에서 인덱스 0은 시작 명령, 인덱스 1은 직선입니다. 직선의 단일 점을 교체하면 명령 유형, 타이밍, 컬렉션 내 위치를 변경하지 않고 목적지를 바꿉니다. 명령이 절대 좌표를 사용하므로 새 쌍은 추가 오프셋이 아닌 위치를 지정합니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("motion.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const motion = effect.getBehaviors().get_Item(0);
motion.getPath().get_Item(1).setPoints(java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.4), java.newFloat(0.1))]));
presentation.save("motion-endpoint.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
motion-endpoint.pptx의 직선은 (0.4, 0.1)에서 끝나며, 원본 파일은 변경되지 않았습니다.
구간 교체
insert와 removeAt를 사용하여 motion.pptx의 직선을 교체합니다. 삽입하면 기존 직선이 인덱스 2로 이동합니다.
이는 기존 좌표를 편집하는 대신 명령 객체를 교체함을 보여줍니다. 삽입 후 컬렉션은 일시적으로 시작 명령, 새로운 직선, 기존 직선, 종료 명령을 포함합니다. 인덱스 2를 제거하면 기존 직선이 삭제되고 새로운 경로가 남습니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("motion.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
const motion = effect.getBehaviors().get_Item(0);
const path = motion.getPath();
path.insert(1, aspose.slides.MotionCommandPathType.LineTo, java.newArray("java.awt.geom.Point2D$Float", [java.newInstanceSync("java.awt.geom.Point2D$Float", java.newFloat(0.2), java.newFloat(0.1))]), aspose.slides.MotionPathPointsType.Corner, false);
path.removeAt(2);
presentation.save("motion-edited.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
저장된 경로는 여전히 세 개의 명령을 가지고 있으며, 새로운 직선은 (0.2, 0.1)에서 끝나고 마지막은 종료 명령입니다.
기존 동작 수정 및 확인
동작의 인덱스를 모를 경우 유형으로 선택합니다. 이 예제는 rotation.pptx를 열어 RotationEffect를 찾고 각도를 변경한 후 다시 열어 저장된 값을 확인합니다.
유형 검사는 루프가 회전이 아닌 동작을 건너뛰게 합니다. 두 번째 로드에서는 저장된 파일을 별도 프레젠테이션 객체에 읽어 들여 비교가 메모리에 남은 값이 아니라 영구 저장된 데이터를 확인합니다. 이 예제는 알려진 효과가 메인 시퀀스의 첫 번째에 있다고 가정합니다; 유형으로 동작을 선택하는 것이 임의 프레젠테이션에서 올바른 효과를 찾는 것은 아닙니다.
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation("rotation.pptx");
try {
const effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
for (let i = 0; i < effect.getBehaviors().getCount(); i++) {
const behavior = effect.getBehaviors().get_Item(i);
if (java.instanceOf(behavior, "com.aspose.slides.IRotationEffect")) {
const rotation = behavior;
rotation.setBy(180);
}
}
presentation.save("rotation-edited.pptx", aspose.slides.SaveFormat.Pptx);
const reopened = new aspose.slides.Presentation("rotation-edited.pptx");
try {
const savedEffect = reopened.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
for (let i = 0; i < savedEffect.getBehaviors().getCount(); i++) {
const behavior = savedEffect.getBehaviors().get_Item(i);
if (java.instanceOf(behavior, "com.aspose.slides.IRotationEffect")) {
const rotation = behavior;
console.log("Rotation preserved: " + (Math.abs(rotation.getBy() - 180) < 0.001));
}
}
} finally {
reopened.dispose();
}
} finally {
presentation.dispose();
}
출력은 Rotation preserved: true입니다. 동일한 유형 검사 패턴을 다른 동작에도 적용하십시오. 전체 보존 검사를 위해 대상 도형, 효과, 동작 유형 및 순서, 타이밍, 경로 명령을 비교하십시오. 부동소수점 값은 숫자 오차를 사용하십시오. 애니메이션 레이아웃이 알려지지 않은 프레젠테이션의 경우, 메인 및 대화형 시퀀스 탐색을 위해 도형 애니메이션 읽기를 참조하십시오.
동작 순서, 프리셋 및 재생
BehaviorCollection의 순서는 효과 작업이 저장된 순서이며, 모든 동작이 자동으로 이전 동작을 기다리는 재생목록이 아닙니다. 타이밍과 포함된 효과가 스케줄을 결정합니다. 동작은 겹칠 수 있으며, 동일 속성에 대한 작업은 getAdditive와 getAccumulate를 통해 상호 작용할 수 있습니다. 단순히 컬렉션 순서를 바꾸어 “이동 후 회전”을 스케줄하지 말고, 명시적인 타이밍이나 별도 효과를 사용하십시오. 이는 도형 애니메이션에 설명되어 있습니다.
Effect의 getType과 getSubtype은 프리셋을 설명합니다. 이는 편집된 동작 트리의 전체 설명이 아닙니다. 동작을 사용자 정의하기 전에 프리셋과 서브타입을 선택하십시오: 프리셋을 변경하면 컬렉션이 재구성되고 사용자 정의 작업이 삭제될 수 있습니다. 예를 들어, 사용자 정의 Spin 효과를 Fade로 바꾸면 회전 동작이 set 및 filter 동작으로 교체됩니다. 프리셋이나 서브타입을 변경한 후 컬렉션을 다시 검사하십시오. 프리셋 동작을 비우면 프리셋이 필요로 하는 가시성이나 초기화 작업도 삭제될 수 있습니다. 예제는 가시적인 도형을 사용하고 동작을 교체하도록 의도했으며, 모든 프리셋 구현을 재구성하지는 않습니다.
포맷 호환성
보존된 동작 트리가 모든 뷰어나 내보내기 렌더러에서 동일한 재생을 보장하지는 않습니다. 저장된 데이터와 렌더링된 출력을 별도로 확인하십시오.
| Format or output | What to verify |
|---|---|
| PPTX | 주요 예제 형식으로 사용하십시오. 파일을 다시 열어 편집 가능한 동작 트리를 확인하고, 대상 PowerPoint 버전에서 재생을 점검하십시오. |
| PPT | 레거시 바이너리 표현은 PPTX와 다를 수 있습니다. 별도의 저장‑재열 사이클과 재생을 테스트하십시오; PPTX 출력이 성공했다고 모든 사용자 정의 조합이 지원된다고 추론하지 마십시오. |
| PDF, PNG, JPEG, and other static slide images | 정적 슬라이드 이미지이며, 재생 가능한 동작 타임라인이나 최종 애니메이션 프레임을 보장하지 않습니다. |
| HTML5 | 지원되는 애니메이션이 활성화된 경우 애니메이션을 재생할 수 있습니다. 브라우저에서 사용자 정의 조합을 테스트하십시오. |
| Animated GIF | 렌더링된 프레임을 저장하며, 편집 가능한 동작이나 클릭 트리거 인터랙션을 포함하지 않습니다. 실제 렌더링된 움직임을 확인하십시오. |
| Video | 애니메이션 프레임을 렌더링하고 비디오로 인코딩합니다. 지원은 렌더러의 지원 애니메이션 및 효과에 제한됩니다; 명령 및 인터랙티브 이벤트는 편집 가능한 타임라인이 되지 않습니다. |
FAQ
왜 내 효과에 아무 것도 추가하기 전에 이미 동작이 포함되어 있나요?
미리 정의된 효과를 생성하면 기본 작업이 생성될 수 있습니다. 동작을 확장하거나 교체하기 전에 이를 검사하십시오.
동작을 앞쪽으로 이동하면 먼저 재생되나요?
반드시 그렇지는 않습니다. 컬렉션 순서는 타이밍을 대체하지 못합니다. 지연, 지속시간 및 동일 속성에 대한 작업 간 상호 작용을 확인하십시오.
왜 종료 명령에 점이 없나요?
경로의 끝을 표시하며 좌표가 필요 없습니다. 파일에서 읽은 경로를 검사할 때 null 점 배열을 확인하십시오.
성공적인 왕복이 재생을 확인하기에 충분한가요?
아니요. 재열은 확인한 속성의 보존을 확인할 뿐입니다. 슬라이드 쇼 플레이어나 애니메이션 내보내기를 별도로 테스트해 시각적 동작을 확인하십시오.