p5.js-svg
p5.js-svg copied to clipboard
Any way to create group inside svg
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 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.
@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.
@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.
@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
@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.
@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.