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

Dynamic FillStyle and LineStyle #23

Closed
SupremeTechnopriest opened this issue Jun 12, 2021 · 19 comments
Closed

Dynamic FillStyle and LineStyle #23

SupremeTechnopriest opened this issue Jun 12, 2021 · 19 comments

Comments

@SupremeTechnopriest
Copy link

Hello,

Thanks for the module. Its exactly what I needed. Was wondering if there is a way to dynamically set the fill and line style outside of the actual SVG. I've tried updating SVGStage.root.children[0].fill with no luck. Would like to avoid having to use a filter if possible.

Thanks!

@SupremeTechnopriest
Copy link
Author

Also, if you could unpin the peerDependencies that would be great. I get errors when trying to install with Pixi 6.0.3. You can probably set it to 6.x.x and be ok or 6.0.x if you are paranoid about compatibility.

@SupremeTechnopriest
Copy link
Author

Nevermind, I figured it out. I can set tint on the child as long as the svg has a white fill. That will work.

I found a few issue with typedefs:

svg.root.children[0].tint = 0x03A9F4

It says tint isn't on type DisplayObject, which it isn't, but this is an SVGNode.

Also:

const data = await fetch(url)
const SVGMarkup = await data.text()
const SVG = new DOMParser().parseFromString(SVGMarkup,'image/svg+xml').documentElement
const svg = new SVGScene(SVG)

Here you need to get the response as text not JSON. You should update the docs to reflect this.
Also, SVGScene is expecting a SVGSVGElement but the parsed DOM element is an HTMLElement and cant be cast to an SVGElement

Hope this helps.

@ShukantPal
Copy link
Owner

image

The documentation already tells you to fetch as text()

@ShukantPal
Copy link
Owner

SVGPathNode is a Graphics object. You can override fill as for any graphics:

graphics.geometry.graphicsData[0].fillStyle.color = 0;
graphics.geometry.invalidate();

@ShukantPal
Copy link
Owner

I'll fix the dependency pinning.

@SupremeTechnopriest
Copy link
Author

Awesome! Could you update those types as well possibly?

@SupremeTechnopriest
Copy link
Author

SupremeTechnopriest commented Jun 12, 2021

Hmm doesnt look like fillStyle exists on svg.root.children[0].geometry. It does exist on svg,root.children[0].fill, however changing it doesnt seem to do anything. I tried calling svg.root.children[0].geometry.invalidate() but nothing happens.

On that note, if I change the alpha on the container svg.root.alpha = 0.5 the alpha doesnt update until something moves in the stage. Is there a method I can call to recalculate styles?

@ShukantPal
Copy link
Owner

You forgot the graphicsData

@ShukantPal
Copy link
Owner

For the alpha, where's the code?

@SupremeTechnopriest
Copy link
Author

SupremeTechnopriest commented Jun 13, 2021

Awesome! I have a function to change the fill of a SVGScene that works well now.

const changeColor = (entity: SVGScene, color: string) => {
  // @ts-ignore
  entity.root.children[0].geometry.graphicsData[0].fillStyle.color = utils.string2hex(color)
  // @ts-ignore
  entity.root.children[0].geometry.invalidate()
}

For alpha I'm setting svg.root.alpha = 0.5 (on the container). I'm also using pixi-viewport, so my hack to make the alpha update is:

if (history && settings.alpha !== history.alpha) {
  viewport.moveCorner(
    viewport.corner.x + 0.0000000001,
    viewport.corner.y + 0.0000000001
  )
}

I tested alpha updates without using a SVGScene to rule out pixi-viewport being the problem and it updates immediately, which leads me to believe the issue is in @pixi-essentials/svg.

@SupremeTechnopriest
Copy link
Author

I tried setting the alpha directly on the SVGScene but it didn't change at all. The highest up in the tree that would work is on the Container. If I set alpha on any of the children of the container it works as well, just doesn't update without something else updating in the scene.

@ShukantPal
Copy link
Owner

ShukantPal commented Jun 13, 2021

I found the issue:

// Don't update transforms if they didn't change across frames. This is because the SVG scene graph is static.

I tried setting the alpha directly on the SVGScene but it didn't change at all. The highest up in the tree that would work is on the Container.

This is kind of a bug. I could change the scene to set its worldAlpha onto the root.

The scene is a wrapper around the root; root isn't a child of the scene however - it is disconnected.

If I set alpha on any of the children of the container it works as well, just doesn't update without something else updating in the scene.

@pixi-essentials/svg has an optimization - it doesn't update the transforms in the internal scene tree if you haven't changed the world-transform of the scene (root). Unfortunately, PixiJS also updates the worldAlpha in the Container#updateTransform method. An easy workaround here is to emit nodetransformdirty on the node you change (scene.root is not a node, it's a normal container; for that, you can set scene._transformDirty to true even though its protected).

@SupremeTechnopriest
Copy link
Author

Worked like a charm. Thanks for all the insight! Here's what I ended up with:

const changeColor = (entity: SVGScene, color: string) => {
  // @ts-ignore
  entity.root.children[0].geometry.graphicsData[0].fillStyle.color = utils.string2hex(color)
  // @ts-ignore
  entity.root.children[0].geometry.invalidate()
}

const changeAlpha = (entity: SVGScene, alpha: number) => {
  entity.root.alpha = alpha
  // @ts-ignore
  entity._transformDirty = true
}

If you could fix the typedefs that would be sweet, but using // @ts-ignore isn't a deal breaker.

Let me know if you link the scene alpha to the container alpha and I can make the change in my source as well. As it is this will be fine for me to continue development.

Thanks again!

@SupremeTechnopriest
Copy link
Author

SupremeTechnopriest commented Jun 15, 2021

Hey @ShukantPal,

Looks like there's also an issue with SVGScene.visible. Setting it doesn't seem to do anything. I have to set it on SVGScene.root. This would be fine, but I'm trying to cull things outside the viewport using pixi-cull and it sets visible on the SVGScene. The result is that the svg renders in the middle of the stage with no scale applied.

// SVGScenes are added to the entity container
const entityContainer = new Container()

const cull = new Simple()
cull.addList(entityContainer.children)

app.current.ticker.add(() => {
  if (viewport.current.dirty) {
    cull.cull(viewport.current.getVisibleBounds())
    viewport.current.dirty = false
  }
})

@ShukantPal
Copy link
Owner

ShukantPal commented Jun 15, 2021 via email

@SupremeTechnopriest
Copy link
Author

Thanks buddy! Appreciate it!

@ShukantPal
Copy link
Owner

You mentioned pixi-cull - try using @pixi-essentials/cull :) https://api.pixijs.io/@pixi-essentials/cull/Cull.html

@SupremeTechnopriest
Copy link
Author

Awesome thanks for that! I will test it out and let you know. Will also try out @pixi-essentials/cull!

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

No branches or pull requests

2 participants