Jump to content
Search Community

Scaled canvas to fit and match an SVG container

katerlouis test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I need to recreate this animation devices feeling the need to go to the moon (fans go crazy..) https://www.telekom.de/zuhause/heimvernetzung/mesh-technologie (disclaimer, I have nothing to do with the version you see there :D)

 

Canvas should be way more performant, right? And I've always wanted to dive into canvas! Perfect opportunity

How hard could it be? Place an inline SVG. Put the canvas below, and animate some growing circles. 

 

Well.. turns out there are quite some challanges, and I don't wanna bother you with all of them.

 

Biggest problem so far is this:

I need/want to place the circles with the same coordinates as in my delivered SVG, and of course it needs to be crisp on higher resolution screens, aaaand of couuurse has to handle viewport resizes properly. 

I ended scaling the entire canvas-context and was pretty happy with the result .. until I drew more than one frame and saw this.

 

image.png.0f341627bbf6357f438a9e68adb0a74a.png

 

What happens is: I clear the entire canvas with `c.clearRect(0, 0, canvas.width, canvas.height)` – but because the context is scaled down, the circle would start at another position and extends beyond the canvas' boundaries. This means the circle doesn't get cleared completely, which makes a part of remain visible. 

 

Now I could just do `c.clearRect(0, 0, 99999, 99999)` or go `canvas.width * 100` .. but .. I'd like to find a clean solution for this issue.

 

 

So my actual question is:

How do I properly match a canvas with an overlaying svg coordinate system?

 

Another question is:

How would you guys get the best performance out of this?

(Because an inline svg overlaying the canvas performs noticably worse than an overlaying img tag referencing the svg file .. which I can't have, because I will need to animate the lines with DrawSVG)

 

 

I'm thrilled to hear your thoughts on that.

 

Thanks!

 

 

See the Pen JqVGWQ by katerlouis (@katerlouis) on CodePen

Link to comment
Share on other sites

8 hours ago, kreativzirkel said:

How do I properly match a canvas with an overlaying svg coordinate system?

 

You have to figure out how much the coordinate system is scaled. Here's a demo I made using only HTML.

 

See the Pen 3fdc4c75dbc38e9cfc06c7723588e79d by osublake (@osublake) on CodePen

 

 

Muh canvas view box

 

See the Pen gvEvaP by osublake (@osublake) on CodePen

 

 

Muh Scalable Vector Graphics

 

See the Pen WzbKLQ by osublake (@osublake) on CodePen

 

 

8 hours ago, kreativzirkel said:

How would you guys get the best performance out of this?

 

I would only use an SVG to pull values from. I would render any SVG assets using canvas. Either by caching it as an image, or using Path2D if it needs to be redrawn, e.g. animating a stroke like DrawSVG.

 

The key to performance is how you manage the graphics. Can canvas draw 1500 circles simultaneously? Sure. Will it be performant? Probably not. It would be much better to cache a circle as an image, and just use it like a rubber stamp.

 

Bitmaps FTW!

 

See the Pen EOeBdm by osublake (@osublake) on CodePen

 

 

  • Like 3
Link to comment
Share on other sites

Very interesting! I didn't know canvas is also struggling with drawing multiple circles ...

So– knowing that I won't need to draw more than 30-40 circles at a time, would you say this should work with actual canvas-arcs?

 

If I used an image for that, it needs to be quite large, since we obviously want it to look crisp on 27'' retina iMacs. How does that look performance wise?

And iiif I used an image, how would the color change work? It's important to hit these exact hex values.

 

–––

 

but as for the scaling issue, I don't understand how your ball-and-image-example can help me :(

and in your viewbox codepen (4x4 grid), only scale up and never draw outside of the canvas. 

 

I'm pretty sure the key advice is in these demos, but I just don't see it :D – the whole "canvas scale in a dom container trying to match the svg coordinate system" is too much for me :(

  • css makes the canvas html element stretch to fit it's container 
  • then I need to tell canvas in JS to match the elements size (or larger for higher resolutions)
  • then the canvas is 

Writing it down like this .. I'm wondering why the circles position correctly in my example... because in my pen the scaleFactor doesn't take the ratio into account, only the relation between the svgViewbox.width and the canvas.width– Hah! The ratio is already applied to the canvas.width, which makes it influence the scale aswell. Learning as I'm writing! Bam!

 

Hmm, maybe it's better to not scale the canvas, but recalculate the x, y, and radius values on draw. It felt more convenient to just draw using values relative to the svg viewbox and scale the whole thing. It's tedious to recalculate all values for new elements. Would all these calculations impact performance negatively?  

 

-> Just tried the recalculation of values.. this would require to scale the clipping-path aswell.

 

So I fixed the clearRect issue with "reversing the scale" when clearing, like so: `c.clearRect(0, 0, canvas.width / scaleFactor, canvas.height / scaleFactor)`

See the Pen vwMdEx by katerlouis (@katerlouis) on CodePen

 

This still feels like a workaround, though ... 

 

Could you fork my pen and add what you meant with your demos?

 

 

 

Thanks!

Link to comment
Share on other sites

48 minutes ago, kreativzirkel said:

Very interesting! I didn't know canvas is also struggling with drawing multiple circles ...

So– knowing that I won't need to draw more than 30-40 circles at a time, would you say this should work with actual canvas-arcs?

 

Well, that demo is drawing 1500 circles, so 30-40 circles should be okay.

 

 

2 hours ago, kreativzirkel said:

Could you fork my pen and add what you meant with your demos?

 

I can later, but how about we start off by making your demo perform better? You need to use save() and restore() when using clip paths.

 

See the Pen 454cd75ed34c216a06e4f71114a1aee0 by osublake (@osublake) on CodePen

 

 

  • Like 1
Link to comment
Share on other sites

Why does saving and restoring make the thing more perform better?! :D

When focusing on performance, would you still say drawing these svg strokes with canvas is the way to go? Remember: I will need to animate the drawing.

(And I will switch out the lil mesh-device with a repeater, which lies right behind it :D)

Link to comment
Share on other sites

21 hours ago, kreativzirkel said:

Why does saving and restoring make the thing more perform better?! :D

 

If you don't understand how save and restore work, here's a little post I made.

 

 

Without saving and restoring, every time you call your draw function, it will add a new clip path to previous clip path, building it up over time, causing your app to get slower. So if everything is running at 60 fps, your canvas is going to have 60 clip paths after 1 second.

 

 

21 hours ago, kreativzirkel said:

When focusing on performance, would you still say drawing these svg strokes with canvas is the way to go?

 

Canvas should be faster in theory because there is less overhead. Here's a demo that show how to draw strokes.

 

See the Pen xJWOmB by Sahil89 (@Sahil89) on CodePen

 

 

And the trick to scaling stuff is to convert all the values you're going to use as a ratio. So you have a x value at 584. As a ratio that will be 997.3 / 1921 = 0.5191566892243623. Then you can multiply that value by the current width of the canvas element.

 

See the Pen 8af36c03a3718f89cc58d127d9df7f01 by osublake (@osublake) on CodePen

 

 

The same thing needs to be done for the clip path values, but I didn't have time to break it apart.

  • Like 4
Link to comment
Share on other sites

Thank you very much!

 

My way of scaling seems to work right now and is more convenient to work with, in my opinion. Are there any issues with scaling the context to fit the coordinates of the svg viewbox that I don't see?

 

Can't wait to show you the final result!

 

The line draw has been descoped, surprise suprise ;)

 

 

Thanks again,

 

kater

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...