Personalizza le forme delle presentazioni in JavaScript
Panoramica
Questo articolo spiega come personalizzare le forme nelle presentazioni in Aspose.Slides modificando la geometria della forma tramite punti di modifica e percorsi geometrici. Mostra come utilizzare GeometryPath per modificare le forme esistenti, eseguire operazioni di modifica di base del percorso, aggiungere o rimuovere punti e applicare la geometria aggiornata a una forma.
Dimostra inoltre come creare forme personalizzate e composite, costruire forme con angoli curvi, determinare se la geometria di una forma è chiusa, ispezionare gli elementi della forma e convertire i contorni di testo Java AWT in percorsi geometrici.
Modifica una Forma Utilizzando i Punti di Modifica
In PowerPoint, è possibile utilizzare Edit Points per modificare un quadrato:
- Spostare un angolo verso l’interno o verso l’esterno.
- Regolare la curvatura in un punto.
- Aggiungere nuovi punti.
Modificare i punti consente di modificare il contorno di una forma o di utilizzare una forma esistente come base per una nuova.
Suggerimenti per la Modifica delle Forme

Quando si modificano forme in PowerPoint, tenere a mente questi concetti:
- Una forma (o il suo percorso) può essere chiusa o aperta.
- Il percorso di una forma è composto da punti di ancoraggio collegati da segmenti.
- Un segmento può essere dritto o curvo. I punti di ancoraggio e le maniglie di controllo ne determinano la forma.
- I punti di ancoraggio possono essere punti d’angolo, punti dritti o punti lisci:
- In un punto d’angolo, i segmenti adiacenti possono incontrarsi ad un angolo.
- In un punto liscio, le due maniglie di controllo sono allineate e alla stessa distanza dal punto di ancoraggio.
- In un punto dritto, le due maniglie di controllo sono allineate ma possono avere distanze diverse dal punto di ancoraggio.
- Spostare i punti di ancoraggio o regolare le loro maniglie modifica il contorno della forma.
Per modificare le forme PowerPoint tramite punti di modifica, Aspose.Slides fornisce la classe GeometryPath.
- Un GeometryPath rappresenta un percorso geometrico dell’oggetto GeometryShape.
- Per ottenere il GeometryPath dall’istanza di GeometryShape, è possibile utilizzare il metodo GeometryShape.getGeometryPaths.
- Per impostare il GeometryPath per una forma, è possibile utilizzare questi metodi: GeometryShape.setGeometryPath per forme con un singolo percorso e GeometryShape.setGeometryPaths per forme con più percorsi.
- Per aggiungere segmenti, è possibile utilizzare i metodi di GeometryPath.
- Utilizzando i metodi GeometryPath.setStroke e GeometryPath.setFillMode, è possibile impostare l’aspetto di un percorso geometrico.
- Utilizzando il metodo GeometryPath.getPathData, è possibile recuperare il percorso geometrico di un GeometryShape come un array di segmenti di percorso.
- Per accedere a ulteriori opzioni di personalizzazione della geometria della forma, è possibile leggere un java.awt.Shape tramite il suo PathIterator e riprodurre i segmenti su un GeometryPath.
Operazioni di Modifica Semplici
Utilizzare i seguenti metodi per modificare un percorso geometrico. Le overload che accettano un indice inseriscono un segmento in quella posizione basata su zero nell’array dei segmenti del percorso.
| Operazione | Metodo |
|---|---|
| Aggiungere o inserire una linea retta. | GeometryPath.lineTo |
| Aggiungere o inserire una curva Bézier cubica con due punti di controllo e un punto finale. | GeometryPath.cubicBezierTo |
| Aggiungere o inserire una curva Bézier quadratica con un punto di controllo e un punto finale. | GeometryPath.quadraticBezierTo |
| Aggiungere un arco ellittico con le dimensioni e gli angoli specificati in gradi. | GeometryPath.arcTo |
| Chiudere la figura corrente collegando il suo punto finale al punto di partenza. | GeometryPath.closeFigure |
| Impostare il punto di partenza di una figura. | GeometryPath.moveTo |
| Rimuovere un segmento a un indice basato su zero. | GeometryPath.removeAt |
Aggiungere Punti Personalizzati a una Forma
Questo esempio inserisce due punti in una forma rettangolare utilizzando GeometryPath.lineTo e applica il percorso modificato con GeometryShape.setGeometryPath. Le coordinate sono locali alla forma: entrambi i nuovi punti si trovano al suo centro, a 100 punti dal lato sinistro e 50 punti dalla parte superiore. Gli indici dei segmenti 1 e 4 li posizionano sui bordi superiore e inferiore, tirando questi bordi verso l’interno.
const slides = require("aspose.slides.via.java");
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Rectangle, 100, 100, 200, 100);
const geometryPath = shape.getGeometryPaths()[0];
geometryPath.lineTo(100, 50, 1);
geometryPath.lineTo(100, 50, 4);
shape.setGeometryPath(geometryPath);
} finally {
presentation.dispose();
}

Rimuovere i Punti da una Forma
Questo esempio modifica un contorno a forma di cuore rimuovendo il segmento all’indice basato su zero 2 con GeometryPath.removeAt. L’applicazione del percorso modificato con GeometryShape.setGeometryPath aggiorna il contorno della forma.
const slides = require("aspose.slides.via.java");
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Heart, 100, 100, 300, 300);
const path = shape.getGeometryPaths()[0];
path.removeAt(2);
shape.setGeometryPath(path);
} finally {
presentation.dispose();
}

Creare una Forma Personalizzata
Questo esempio costruisce una stella a cinque punte con GeometryPath. Raggi esterni e interni alternati di 100 e 50 punti definiscono le punte e le rientranze; un passo di 72 gradi distribuisce uniformemente le cinque punte. Il percorso è chiuso con GeometryPath.closeFigure e applicato a una forma rettangolare utilizzando GeometryShape.setGeometryPath, sostituendone il contorno.
const slides = require("aspose.slides.via.java");
const java = require("java");
const points = [];
const outerRadius = 100;
const innerRadius = 50;
const angleStep = 72;
for (let angle = -90; angle < 270; angle += angleStep) {
let radians = angle * Math.PI / 180;
points.push({ x: outerRadius * Math.cos(radians) + outerRadius, y: outerRadius * Math.sin(radians) + outerRadius });
radians = (angle + angleStep / 2) * Math.PI / 180;
points.push({ x: innerRadius * Math.cos(radians) + outerRadius, y: innerRadius * Math.sin(radians) + outerRadius });
}
const starPath = new slides.GeometryPath();
starPath.moveTo(java.newFloat(points[0].x), java.newFloat(points[0].y));
for (let i = 1; i < points.length; i++) {
starPath.lineTo(java.newFloat(points[i].x), java.newFloat(points[i].y));
}
starPath.closeFigure();
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Rectangle, 100, 100, outerRadius * 2, outerRadius * 2);
shape.setGeometryPath(starPath);
} finally {
presentation.dispose();
}

Creare una Forma Personalizzata Composita
Questo esempio definisce due oggetti GeometryPath chiusi per il terzo superiore e inferiore di una forma. L’applicazione di entrambi i percorsi con GeometryShape.setGeometryPaths crea una singola forma composita con uno spazio nel terzo centrale.
const slides = require("aspose.slides.via.java");
const java = require("java");
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Rectangle, 100, 100, 200, 100);
const topPath = new slides.GeometryPath();
topPath.moveTo(0, 0);
topPath.lineTo(shape.getWidth(), 0);
topPath.lineTo(shape.getWidth(), java.newFloat(shape.getHeight() / 3));
topPath.lineTo(0, java.newFloat(shape.getHeight() / 3));
topPath.closeFigure();
const bottomPath = new slides.GeometryPath();
bottomPath.moveTo(0, java.newFloat(shape.getHeight() / 3 * 2));
bottomPath.lineTo(shape.getWidth(), java.newFloat(shape.getHeight() / 3 * 2));
bottomPath.lineTo(shape.getWidth(), shape.getHeight());
bottomPath.lineTo(0, shape.getHeight());
bottomPath.closeFigure();
const paths = java.newArray("com.aspose.slides.GeometryPath", [topPath, bottomPath]);
shape.setGeometryPaths(paths);
} finally {
presentation.dispose();
}

Creare una Forma Personalizzata con Angoli Curvi
Questo esempio combina segmenti dritti con GeometryPath.arcTo per creare una forma con angoli curvi verso l’interno. La dimensione di ogni angolo imposta la larghezza e l’altezza dell’arco in punti, e il tratto di -90 gradi disegna un quarto di ellisse in senso antiorario. Il percorso completato è applicato con GeometryShape.setGeometryPath e la presentazione viene salvata in formato PPTX.
const slides = require("aspose.slides.via.java");
const shapeX = 20;
const shapeY = 20;
const shapeWidth = 300;
const shapeHeight = 200;
const leftTopSize = 50;
const rightTopSize = 20;
const rightBottomSize = 40;
const leftBottomSize = 10;
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Custom, shapeX, shapeY, shapeWidth, shapeHeight);
const geometryPath = new slides.GeometryPath();
geometryPath.moveTo(leftTopSize, 0);
geometryPath.lineTo(shapeWidth - rightTopSize, 0);
geometryPath.arcTo(rightTopSize, rightTopSize, 180, -90);
geometryPath.lineTo(shapeWidth, shapeHeight - rightBottomSize);
geometryPath.arcTo(rightBottomSize, rightBottomSize, -90, -90);
geometryPath.lineTo(leftBottomSize, shapeHeight);
geometryPath.arcTo(leftBottomSize, leftBottomSize, 0, -90);
geometryPath.lineTo(0, leftTopSize);
geometryPath.arcTo(leftTopSize, leftTopSize, 90, -90);
geometryPath.closeFigure();
shape.setGeometryPath(geometryPath);
presentation.save("output.pptx", slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
Scoprire se la Geometria di una Forma è Chiusa
Il seguente helper verifica se ogni percorso geometrico non vuoto termina con un segmento di chiusura. Legge GeometryPath.getPathData e confronta il comando del segmento finale PathSegment.getPathCommand con PathCommandType.Close. Restituisce false quando non ci sono percorsi non vuoti. Questo controlla il comando finale di ogni percorso; non ispeziona ogni sottofigura all’interno di un percorso. L’esempio stampa true per un rettangolo.
const slides = require("aspose.slides.via.java");
function isGeometryClosed(geometryShape) {
let hasNonemptyPath = false;
for (const geometryPath of geometryShape.getGeometryPaths()) {
const segments = geometryPath.getPathData();
if (segments.length === 0) {
continue;
}
hasNonemptyPath = true;
const lastSegment = segments[segments.length - 1];
if (lastSegment.getPathCommand() !== slides.PathCommandType.Close) {
return false;
}
}
return hasNonemptyPath;
}
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Rectangle, 100, 100, 200, 100);
const closed = isGeometryClosed(shape);
console.log(closed);
} finally {
presentation.dispose();
}
Estrarre e Ispezionare gli Elementi della Forma
L’utilizzo di GeometryShape.createShapeElements consente di ispezionare una forma esistente come elementi contenenti punti di percorso e tipologie di punti. Utilizzare ciascun ShapeElement restituito per recuperare gli array di punti e tipi tramite i metodi getPathPoints e getPathTypes. Questa rappresentazione è utile per l’analisi del contorno o per passare la geometria a strumenti di disegno personalizzati.
L’esempio apre input.pptx, trova la prima forma geometrica direttamente nella prima diapositiva e stampa i suoi segmenti di percorso. Utilizzare una presentazione contenente una forma con segmenti dritti e curvi per vedere entrambi i tipi di output. Non ricerca all’interno dei gruppi.
const slides = require("aspose.slides.via.java");
const java = require("java");
const presentation = new slides.Presentation("input.pptx");
try {
const slide = presentation.getSlides().get_Item(0);
let shape = null;
for (let index = 0; index < slide.getShapes().size(); index++) {
const candidate = slide.getShapes().get_Item(index);
if (java.instanceOf(candidate, "com.aspose.slides.GeometryShape")) {
shape = candidate;
break;
}
}
if (shape == null) {
console.log("No geometry shape found on the first slide.");
} else {
for (const shapeElement of shape.createShapeElements()) {
const points = shapeElement.getPathPoints();
const types = shapeElement.getPathTypes();
console.log("Shape element:");
for (let i = 0; i < points.length; i++) {
const pointType = types[i] & 0x07; // Mantieni il tipo di segmento, escludendo i flag.
switch (pointType) {
case 0:
console.log("Start figure at " + points[i]);
break;
case 1:
console.log("Line to " + points[i]);
break;
case 3:
console.log("Cubic Bezier: controls " + points[i] + ", " + points[i + 1] + "; end " + points[i + 2]);
i += 2; // Consume both control points and the endpoint.
break;
}
if ((types[i] & 0x80) != 0) {
console.log("Close subpath back to its starting point.");
}
}
}
}
} finally {
presentation.dispose();
}
Gli array corrispondono per indice: points[i] è un punto e types[i] descrive il suo ruolo. Il tipo 0 avvia una figura, e il tipo 1 traccia una linea dal punto precedente al punto corrente. Un segmento Bézier cubico inizia dall’estremità precedente e utilizza tre voci consecutive di tipo 3: due punti di controllo seguiti dal nuovo punto finale. Il ciclo consuma queste tre voci insieme e controlla la chiusura del punto finale.
I tipi di punto contengono anche flag. Mascherare con 0x07 per identificare il tipo di segmento e testare 0x80 separatamente per rilevare un sotto‑percorso chiuso. Per esempio, 129 (0x81) indica un punto finale di linea che chiude un sotto‑percorso, e 131 (0x83) indica un punto finale Bézier che lo chiude. Java memorizza questi flag in byte con segno; la mascheratura preserva i valori di bit desiderati. Confrontare il valore grezzo solo con 1 o 3 farebbe perdere questi casi. Altri flag, come dash (0x10) e marker (0x20), non modificano il tipo di segmento di base.
Coordinate e trasformazioni. I punti sono misurati in punti (1/72 di pollice), con X che aumenta verso destra e Y che aumenta verso il basso. Per una forma non raggruppata, le coordinate estratte includono già la posizione restituita da getX e getY e riflettono la sua larghezza e altezza attuali. Per esempio, un rettangolo non ruotato a (100, 200) con dimensioni 120 × 80 ha i limiti del contorno (100, 200)–(220, 280). Non aggiungere nuovamente la posizione della forma. Sottrarre X e Y per ottenere coordinate relative al suo riquadro non ruotato.
I punti estratti non applicano la rotazione della forma, restituita da getRotation, né i ribaltamenti orizzontali e verticali. Per riprodurre il contorno visualizzato, applicare tali trasformazioni attorno al centro della forma. Per le forme raggruppate, considerare anche la mappatura delle coordinate del gruppo e le trasformazioni; non supporre che i punti estratti siano le coordinate finali della diapositiva renderizzate o applicare una traslazione o scala due volte se è già riflessa nel riquadro del figlio.
Ispezione vs modifica. Gli array estratti descrivono il contorno; modificarli non aggiorna la forma originale. Scegliere questo approccio quando la tua analisi o il codice di disegno richiedono array di punti/tipi. Usa getGeometryPaths quando hai bisogno dei comandi di geometria nel sistema di coordinate locale della forma o desideri modificare la sua geometria. Applica i percorsi modificati tramite setGeometryPath o setGeometryPaths.
Convertire una Forma Java AWT in GeometryPath
Questo esempio combina un contorno rettangolare con testo convertito in geometria. Il metodo setFillMode del contorno disabilita il suo riempimento. Un GlyphVector crea il contorno del testo in un java.awt.Shape. Il suo PathIterator fornisce segmenti di spostamento, linea, quadratico, cubico e di chiusura, che l’esempio riproduce su un GeometryPath.
Il bridge Java utilizza valori espliciti di tipo float e byte per i parametri Java corrispondenti. L’iteratore scrive le coordinate in un array float Java; il riflesso legge i valori aggiornati di nuovo in JavaScript. Il testo utilizza un font Arial da 40 punti. Il contorno è spostato di 20 punti orizzontalmente e posizionato con la sua parte superiore visiva 10 punti sotto il bordo superiore della forma. Il percorso del testo è riempito, mentre il rettangolo originale rimane un contorno. L’applicazione di entrambi i percorsi con GeometryShape.setGeometryPaths produce una singola forma contenente il rettangolo e il testo.
const slides = require("aspose.slides.via.java");
const java = require("java");
const presentation = new slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const shape = slide.getShapes().addAutoShape(slides.ShapeType.Rectangle, 100, 100, 300, 100);
const originalPath = shape.getGeometryPaths()[0];
originalPath.setFillMode(java.newByte(slides.PathFillModeType.None));
const font = java.newInstanceSync("java.awt.Font", "Arial", java.getStaticFieldValue("java.awt.Font", "PLAIN"), 40);
const image = java.newInstanceSync("java.awt.image.BufferedImage", 100, 100, java.getStaticFieldValue("java.awt.image.BufferedImage", "TYPE_INT_ARGB"));
const graphics = image.createGraphics();
let graphicsPath;
try {
const fontContext = graphics.getFontRenderContext();
const glyphVector = font.createGlyphVector(fontContext, "Text in shape");
const textBounds = glyphVector.getVisualBounds();
const baseline = java.newFloat(-textBounds.getY() + 10);
graphicsPath = glyphVector.getOutline(java.newFloat(20), baseline);
} finally {
graphics.dispose();
}
const textPath = new slides.GeometryPath();
const pathIterator = graphicsPath.getPathIterator(null);
const coordinates = java.newArray("float", [0, 0, 0, 0, 0, 0]);
while (!pathIterator.isDone()) {
const segmentType = pathIterator.currentSegment(coordinates);
const points = [];
for (let i = 0; i < 6; i++) {
const coordinate = java.callStaticMethodSync("java.lang.reflect.Array", "getFloat", coordinates, i);
points.push(java.newFloat(coordinate));
}
switch (segmentType) {
case 0: // Sposta a.
textPath.moveTo(points[0], points[1]);
break;
case 1: // Linea a.
textPath.lineTo(points[0], points[1]);
break;
case 2: // Curva Bézier quadratica.
textPath.quadraticBezierTo(points[0], points[1], points[2], points[3]);
break;
case 3: // Curva Bézier cubica.
textPath.cubicBezierTo(points[0], points[1], points[2], points[3], points[4], points[5]);
break;
case 4: // Chiudi figura.
textPath.closeFigure();
break;
}
pathIterator.next();
}
textPath.setFillMode(java.newByte(slides.PathFillModeType.Normal));
const paths = java.newArray("com.aspose.slides.GeometryPath", [originalPath, textPath]);
shape.setGeometryPaths(paths);
} finally {
presentation.dispose();
}

FAQ
Cosa succederà al riempimento e al contorno dopo aver sostituito la geometria?
Lo stile rimane associato alla forma; cambia solo il contorno. Il riempimento e il contorno vengono applicati automaticamente alla nuova geometria.
Come ruotare correttamente una forma personalizzata insieme alla sua geometria?
Utilizzare il metodo setRotation della forma; la geometria ruota con la forma perché è legata al sistema di coordinate della forma stessa.
Posso convertire una forma personalizzata in un’immagine per “bloccare” il risultato?
Sì. Esporta l’area della diapositiva richiesta o la forma stessa in un formato raster; questo semplifica ulteriori lavori con geometrie complesse.