Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any way to create group inside svg #243

Open
psicomante opened this issue May 26, 2023 · 6 comments
Open

Any way to create group inside svg #243

psicomante opened this issue May 26, 2023 · 6 comments
Assignees
Labels

Comments

@psicomante
Copy link

psicomante commented May 26, 2023

Hello everybody,

I would like to easily add a SVG Group during drawing, I found the following method:

let g = P5.SVGElement.create("g");
rootGroup.appendChild(g.elt);
ctx.__currentElement = g.elt;

where P5 is the global P5 instance or the P5 imported using Typescript or modules:

import P5 from "p5";

Any better way is available?
Thanks

@psicomante psicomante changed the title Any way to create layers inside svg Any way to create group inside svg May 26, 2023
@zenozeng
Copy link
Owner

zenozeng commented Jun 3, 2023

@psicomante May I ask if there is any specific reason why this must be done? Typically, the details inside an SVG are managed by the svgcanvas library. Manually modifying them could potentially create issues.

@bkuri
Copy link

bkuri commented Jun 5, 2023

@zenozeng personally I would love to be able to create groups (and specify their id) since that is the way to set a rendering order and visibility when sending plots to my axidraw.

@psicomante
Copy link
Author

@zenozeng I share the goal with @bkuri, I need to plot them separately, using different pens; groups is the best method to create this kind of separation inside svg.

@psicomante
Copy link
Author

@zenozeng i know this approach could lead to severe issues, but if I use a single group my plot ideas cannot be plotted in any way.

maybe I could create a new method exposing this approach and write some tests? Do you know any specific issues this approach is creating?

thanks

@zenozeng
Copy link
Owner

@psicomante @bkuri I now understand your scenario and there may be a new API in future versions to specify the group. Currently, there is no particularly good and safe way to specify where the next drawing should occur within a group, and it may also require modifications to the implementation details of svgcanvas.

@zenozeng zenozeng self-assigned this Jun 11, 2023
@jakkopieterdejong
Copy link

@bkuri @psicomante I share your goal, but solved it a different (maybe bit cumbersome) way: I keep an array of Graphics objects as a sort of layers, and assign parts of my drawing to different layers. When I save my file, I save every Graphics layer separately, and clear the canvas in between. This way I can plot each layer as a separate svg (or as different layers in Inkscape).

I wrote a LayerManager class that does this stuff:


class LayerManager{
    constructor(num_layers) {
        this.N = num_layers;
        this.layers = this.create();
        return new Proxy(this, {
            get(target, prop, receiver) {
                if (!isNaN(prop) && prop in target.layers) {
                    return target.layers[prop];
                }
                return Reflect.get(...arguments);
            }
        });
    }

    create(num_layers = this.N) {
        let layers = [];
        for (let l=0; l<num_layers; l++){
            layers.push(createGraphics(width, height, SVG));
        }
        return layers;
    }

    applyToLayers(fn, layers = this.layers) {
        for (let l of layers) {
            fn(l);
        }
    }

    nofill(layers = this.layers) {
        this.applyToLayers(layer => layer.noFill(), layers);
    }

    paint(layers = this.layers) {
        this.applyToLayers(layer => image(layer, 0, 0), layers);
    }

    clear(layers = this.layers) {
        this.applyToLayers(layer => layer.clear(), layers);
    }

    save(fname, layers = this.layers) {
        for (let [index, layer] of layers.entries()) {
            clear();
            image(layer, 0, 0);
            let filename = `${fname}_${index}.svg`;
            save(filename);
        }
    }
}

I use th layer manager in a sketch like this:

let lm

function setup() {
    createCanvas(200, 300, SVG);
    noLoop();

    lm = new LayerManager(3);
    lm.nofill();
    lm[0].stroke(255, 0, 0);
    lm[1].stroke(0, 255, 0);
    lm[2].stroke(0, 0, 255);
}

function draw() {
    background(255)
    lm[0].rect(width/4, height/4, 25, 25);
    lm[1].rect(width/2, height/2, 35, 25);
    lm[2].rect(width/2, height/4, 25, 45);

    lm.paint()
}

function keyPressed() {
    if (key == "s") {
      lm.save('test_svgs')
    }
  }

Let me know if this works for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants