How I can group by shapes with PptxGenJS?
Hello. Could you help me? Maybe you know Can I group 2 shapes with PptxGenJS?
Thanks a lot. Have a good day.
Hi @sensone,
That feature does not exist as of yet.
This is a planned future feature?
I've been digging around how to implement a few features in PptxGenJS. One thing I'd like to do is group shapes. Underneath the root p:spTree element in the slide XML, there are two child elements: p:nvGrpSpPr and p:grpSpPr (each with their own child elements). Following that is a bunch of p:Sp elements that contain the actual shapes / other elements.
To implement a group, I think it's as "simple" as creating a p:grpSp as a child of the p:spTree element, adding the group properties (i.e. p:nvGrpSpPr and p:grpSpPr), and then adding child p:Sp elements.
There are two tricky things to this though:
- If you don't calculate the bounding box of the child elements correctly, PowerPoint will draw the boundary for the group in the default location (i.e. top left corner)
- To do this properly, it would make sense to treat the slide as a special case of a group, and then move the xml generation for the slide objects into a method for a group.
I'm actually hacking away at this right now, but it's going to require refactoring that XML generation code. Before I get too deeply into this, what do you think @gitbrent ? I think the wacky bounding box for a group is something that can be lived with, but the refactoring could be quite fragile?
The api could work something like
let mygroup = slide.addGroup()
mygroup.addShape(...)
mygroup.addText(...)
slide.data.length == 1
mygroup.data.length == 2
Hi @hirenj
Thanks for the analysis. I have not researched grouping enough to understand what was required for a grouping API.
Is calculating a bounding box the only way to create groups? That sounds really cumbersome.
If you can come up with a group API that would be a great contribution, so I appreciate your time working on this.
- Be sure to check the OOXML shape spec
- Be sure you're working with the version-3.0 branch which is typescript and is much easier to patch (it'll be out soon)
I think bounding box is the only way to do it, but I also don't think it is strictly necessary to do. I can attach a generated file with the broken bounding box, and you can see that PowerPoint seems to correct it once you select, or group/ungroup.
I made progress on this last night, and have the basic implementation working right now. I'm pretty sure things like master slides and the table functionality might be broken. Do you have tests for these features that I can run?
Also, I'd like to decompose the xml generation into separate files just to make it easier to see what the overall logic is. I was thinking of a subfolder of src called genxml , and encapsulating all the table stuff in one, text in another etc.
I've created another top level class called Group: the Slide class had a field called rootGroup and it no longer has a data field. The methods to e.g. addShape on the slide now proxy to the rootGroup, that contains the actual implementation of the method.
I'm a bit worried about memory leaks with the rootGroup field, and associated ownerSlide field on the groups. Ideally this should be implemented as entries in a WeakMap that are wrapped up in accessors.
Hi, I've done the decomposition for the XML generation into seperate files too - all of this is sitting in the groups branch of my fork. I'm going to hold off on doing any more changes for now until this gets tested on to make sure that I haven't introduced any regressions.
At least for the most basic use case, it looks like it works pretty nicely (with the proviso that the bounding box for the groups is completely off).
var PptxGenJS = require('./src/bld/pptxgen.cjs');
var pptx = new PptxGenJS();
var slide = pptx.addNewSlide();
var group = slide.addGroup();
group.addText('Hello World!', { x:1.5, y:1.5, fontSize:18, color:'363636' });
group.addText('Hello World!', { x:2.5, y:1.5, fontSize:18, color:'FF3636' });
group.addShape(pptx.shapes.LINE, { x:4.15, y:4.40, w:5, h:0, line:'FF0000', lineSize:1 });
slide.addShape(pptx.shapes.LINE, { x:1, y:4.40, w:5, h:0, line:'FFFF00', lineSize:1 });
pptx.writeFile('Sample Presentation').then( done => console.log(done) );
I think the code re-factoring that I did was a necessary step so that the types of objects that can be added in can be cleanly scaled up. The structure opens the door for things like centralising id generation for objects and adding new shape types (e.g. arbitrary polygons!). The first of those things is a prerequisite for tackling the big thing I'd like to put in - rudimentary animation support.
Hey @hirenj , do you think you'll continue to work on your branch, or do you have any information about when / if it could potentially be merged into master?
I've just taken a quick look at merging the changes in from the branch into master. Unfortunately it's not a clean merge (which I expected as it's mucking around with internals). I don't have the time right now to merge it in, although I do have a pretty good idea of what tasks need to be done to realise the merge (since the pptx stuff is already figured out). I can come back to this in maybe a month or two? Or I'm happy for someone else to implement this directly upon master if you want to discuss the design / approach in this thread?
Any help landing this feature would be appreciated.
Hi @hirenj, @gitbrent, We are looking for grouping feature. Could you please let us know the way forward?
I'm afraid I haven't had the time to do anything with this - but would some documentation as to what I was trying to achieve help at all? I'd imagine that my changes will be very much out of sync with the current codebase now, and it'll be easier to implement it from scratch again?
Hi all, any progress since the summer? Seems like a lot has been figured out already.. not sure if I am able to contribute (don't know the codebase at all..) but I would be able to provide feedback or have a look at any changes. Is https://github.com/hirenj/PptxGenJS/commits/groups still the most recent branch?
One thing to note is that in PowerPoint you can set rotation for a group and it rotates the items in the group (but all together, not individually). Might be something to keep in mind. As far as I can see there are no other things to be configured for a group (other than position and size obviously).
The addition of grouping functionality requires quite a bit of plumbing on the back-end that has not been designed or developed.
Hi,
Yeah this is I think the major point holding up implementation. Basically when I was working on this, I moved internals around so that you could treat a group the same as a top level object that you add slide elements to. This enabled recursive groups etc.
I would expect that the backend design has changed since then, so I can’t estimate how long it would take to add this to the design. My trick back then was to switch around the object hierarchy so that the methods to add things to slides sit in a class that both slide and group classes inherit from.
Unfortunately, because of waves hand at general state of world everything, I can’t commit to proposing a finished redesign for Brent to simply sign off on.
I guess the way to make progress on this is that Brent suggests an appropriate forum to talk about a redesign (another gh issue, or email?), and then I can participate in that, and then hopefully there is someone lined up to implement it?
On Mon, 7 Dec 2020 at 04.33, Brent Ely [email protected] wrote:
The addition of grouping functionality requires quite a bit of plumbing on the back-end that has not been designed or developed.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/gitbrent/PptxGenJS/issues/307#issuecomment-739642199, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABF7VOGEE3KGV5PZCDEPRDSTREJPANCNFSM4EVDNVUQ .
Hi, I also need this functionality and I have a working POC here: groups branch in lukevella/PptxGenJs. The API is based on what @hirenj suggested.
Example Usage
const group = slide.addGroup()
group.addText("Hello", { x: 1, y: 1, w: 3, h: 1 })
group.addText("World", { x: 2, y: 2, w:3, h: 1 })
The main change that allows this to happen is that I updated the parameters for functions that generate object definitions so that the target and slide are separate parameters. target is now a type Container which is an object that holds a list of slide objects – in this case it can be either a Slide or a Group.
- export function addTextDefinition(target: PresSlide, text: TextProps[], opts: TextPropsOptions, isPlaceholder: boolean) {
+ export function addTextDefinition(target: Container, slide: PresSlide, text: TextProps[], opts: TextPropsOptions, isPlaceholder: boolean) {
The other change is splitting the xml generation function so that we can recursively generate XML for grouped slide objects. For this I created slideItemObjsToXml(). Besides generating XML for a list of slide objects this function also returns position and size values that can contain the slide objects in the list. This is needed when creating groups since the position and size of the group object is based on its contents.
There's still some work to be done to get this ready but if @gitbrent is interested in this approach I'm happy to polish this up a bit further and publish a PR.
Hey @lukevella Thanks for adding group functionality. Do you have any timeline on when we can merge this PR to master. I am waiting for this feature. cc: @gitbrent
@ishantmehta012 I'm just waiting for feedback from @gitbrent. If he's happy with this direction I'm happy to help get this ready.
@lukevella This looks like a great implementation! Glad to see that someone picked this up.
@gitbrent @lukevella Are either of you guys still planning on merging in https://github.com/gitbrent/PptxGenJS/pull/929 ?
Hi, first of all, thanks for the great library. PPTXGenJS is the de-facto standard to generate a PPTX in JS. AWESOME Job. Group would be a good piece of functionality nice to have. Are you planning to merge it? I'm working on a React renderer based on Yoga Layout, (something like react-pdf but for pptx) and Grouping is something i'm interested in. Thanks
Thanks @marcog83 !
The ability to group objects will be in Version 4.0. You can keep track of the feature via the Discussions tab.
@gitbrent thanks a lot for the feedback, it is actually a great news. as I said I'm working on a react renderer you can find here... https://github.com/marcog83/pptx-renderer it is still a POC. i wish I could make it as stable as possible and share it with the community