@Craig - If you draw everything on the same canvas, the zoom/scale works on 
everything on that canvas. it limits what you can do with that canvas. If 
you want to scale or zoom everything, yes then it doesn't matter. So yes 
you are right, it depends on the project.

This isn't true, it only applied on the operations that take place while it 
is set. You can call scale(1, 1) to go back to 1:1, or you can use the 
save()/restore() that Craig mentioned. You can also clip to keep the zoomed 
content within certain bounds.

@Colin - With multiple layers I would also need multiple canvas's and 
overlay them right? 

Correct - each would have its own frame buffer, and could be cleared/drawn 
independently.
 

We wrote a single adapter widget that uses a single canvas. This adapter 
widget knows what the zoom level is. Objects that are drawn on that widget 
of a certain type get zoomed, whilst others of a different type do not. It 
is super simple and easily explained to new devs. Everyone on the team can 
add views or objects and the type determines how these are displayed. Even 
devs without exact knowledge of how the canvas works can develop and 
maintain objects to be displayed.

I guess it's also a development style/preference thing. If you code the 
view of the canvas in a single class or single method, the solution is 
likely to have to rely more on the technological capabilities of the 
canvas. Working with an adapter then does not really make a lot of sense. 
If you have more of an OO style of development, you express more in 
functional blocks. Then you have to rely less on the technical capabilities 
as you can translate what needs to be done on the basis of what your 
objects are before you hit the canvas. Then the zooming/scaling happens 
in the object, not on the canvas so to speak.
So the required functionality of the canvas remains fairly basic.

I don't make these suggestions lightly - if you are happy with how canvas 
performs and the quality of the output, then you may well never need them, 
but it can be fun to know they exist.

I don't much care about OO vs FP styles for this - building an API around 
these features should be straightforward within whatever paradigm you 
prefer. For most projects we ended up with roughly two layers of 
abstractions - the "shapes that get drawn on the screen via canvas 
commands" abstraction (iterate through "shapes", respect their "z-index" or 
other relative positioning, capture clicks and figure out which "shape" was 
clicked on, redraw only changed "shapes" and those that intersect them, 
etc), and the "business logic drives what shapes to draw" abstraction ("I 
want a pie chart in the corner, compute slices based on data", "these 
buttons over here control those axes", "Labeled items in the legend will 
drive which stars/circles in the chart are highlighted when hovered"). It 
feels natural to someone who is used to working with a DOM (esp SVG), and 
can handle thousands of items without much trouble. 

Zoom can appear at either level here - multiple coord systems, or make the 
"zoom" part of the "shape" API. You're totally correct that scaling need 
not happen at the "canvas level" - while the MDN link I gave seems to imply 
that, it really is just trying to make it easier for the developer to not 
need to think about one more "layer" of ways that their data needs to be 
transformed. From a certain perspective, you might want to just have a 
transform matrix that you apply to each shape, and compose your 
zoom-because-zoom-widget, translate-because-panning, rotate, etc operations 
all at that level, and just apply the transform once when drawing (or even 
apply to the coords before you call in to canvas). None of it matters as 
long as the math is correct.

If you need more power, odds are you can find pretty quickly where the 
"unnecessary" O(n^2) or O(n lg n) operations are taking place (sorted 
insertion by z-index, solving for intersections, etc), and can do a better 
job partitioning "shapes" or go all out and drop down to just "business 
logic drives canvas commands" where it is required.

 

performance wise, I've done fully animated person relation networks and 
animated dashboards in large canvases for nearly a decade now. 
We've never ran into any performance issues. 
That being said, I think the views and on-screen actions we used were 
somewhat limited when compared to developing a game with full world 
rendering or something similar. 
 
Did I already say I love this gwt group? It makes me think a lot more about 
what I am doing and why I am doing it. 
Plus the input from the GWT devs usually give me insights I haven't thought 
about before or didn't know existed.

If you can stand the stream of discussion, you may also enjoy 
https://matrix.to/#/#gwtproject_gwt:gitter.im. It tends to be more 
conversational, and can get into the weeds in unrelated topics like this.
 

On Sat, Feb 8, 2025 at 2:56 AM Colin Alworth <co...@colinalworth.com> wrote:

I'm sorry if my message confused the two kinds of 'zoom' being discussed 
here - there's the one where the pixels on the physical monitor don't match 
the pixels of your display (this covers both HDPI and ctrl +/-), and 
there's the one where the user clicks the + icon (drawn on the canvas) to 
make everything inside a specific rectangle bigger.

The context2d.scale() method can do both, but I was mostly referring to the 
first, adapting to the user's current monitor+settings at any given time. 
Note that in this context, scale() does _not_ make things blurry when you 
zoom, but effectively multiplies all your coordinates by the scale. The 
canvas "height" and "width" (the "actual size" in the link's code sample) 
are what makes things blurry or super precise.

In the second case, scale() can still be totally appropriate, especially if 
coupled with a "panning" feature, or if data is updating. Odds are very 
high that in those cases, the parts of the canvas outside the "rectangle" 
aren't moving - all the various controls, the rectangle itself. Avoiding 
redrawing whatever you can each frame is important for performance. Or, you 
can just adjust your coordinate system when projecting on to the canvas, 
multiplying by your current zoom factor for each position - as above, it is 
doing the same thing.

While we're discussing it, clipping (with save/restore or without) still 
also be helpful to conserve rewrites too - if you had a single canvas 
element, you would clip to inside the rectangle, clear, and redraw only 
what is in there - save() and restore() are a valid way of handling that, 
or just reapply state at each pass. If you're careful, you could even just 
redraw a subset of the rectangle's contents - solve for which items 
actually changed (doing some intersection math), and clip+clearRect just 
that section, then redraw just what is in there. If you "draw" a little 
outside the clip in any of these cases, no big deal - it will get clipped 
out (but you'll still pay for the code to run, it just won't have any 
overdraw).

If you think about this like "partitioning" the drawing area with clip, 
there are two other ways to partition too - you can "tile" canvases, 
selectively redrawing their entire contents if they are affected, and you 
can "layer" them, using transparency to enable lower layers or higher 
layers to remain intact when other layers need to be cleared and repainted. 
Tiling can also work with non-homogenous blocks - the "rectangle" above 
could be one canvas, and the "controls" could be in their own.

On Friday, February 7, 2025 at 5:11:41 PM UTC-6 ma...@craig-mitchell.com 
wrote:

> *I would not use the scale functionality as it applies to the whole 
canvas. *

Whatever works for your project is best, however, the scale only applies 
when you set it.  And you can always reset it.  Eg:

// Save the current state
context2d.save();

// Apply zoom
context2d.scale(xxx, xxx);

// Draw zoomed stuff
...

// Reset the zoom
context2d.restore();

This also lets browsers use the GPU to render (although, I'm not actually 
sure if the scaling is done on the CPU or the GPU).

On Friday, 7 February 2025 at 5:02:17 pm UTC+11 Leon Pennings wrote:

I would not use the scale functionality as it applies to the whole canvas. 
I'd prefer to apply an adapter pattern for determining actual coordinates 
on the canvas. 
Then you can still have a toolbar, location display or slider for the zoom 
factor in it's normal proportions and just have the actual content you want 
to show in a different scale. 

Op donderdag 6 februari 2025 om 13:33:12 UTC+1 schreef Colin Alworth:

No problem - I wanted to be sure I didn't make a mistake, since I haven't 
myself used canvas "in anger" in many years, and only loosely keep track of 
resources and advice on it.

SmartGWT's "Draw" examples make the API look very similar to the GXT "draw" 
packages - it isn't really a raster API at all, but a vector API that just 
happens to be built on top of a canvas implementation. 

My recollection is that for fewer than around 1k-10k drawn items, SVG is 
faster and simpler to understand than canvas, and canvas's benefits only 
start kicking in when the DOM gets too heavy to manipulate quickly each 
frame. Looking briefly at the example page you shared a few weeks ago, if 
you were interested in getting into the low level details of how to do the 
drawing, your case perhaps could stand being remade in plain SVG - always 
high resolution. The benefits may be mostly for your own understanding 
rather than any real observed performance improvements from running the 
page (that said: dropping SmartGWT would appear to drop almost 8mb of JS 
out of your 9+mb page).

On Wednesday, February 5, 2025 at 9:46:51 PM UTC-6 ne...@propfinancing.com 
wrote:

> Neil, I'm not sure where I appeared to have said that.

 

I am sorry, I did not intend to put words in your mouth.

That was my understanding from your previous email stating
that  canvas is a raster format.  I misinterpreted your statements.

 

I apologize for that.

 

Thank you,

 Neil 

 

--

Neil Aggarwal, (972) 834-1565, http://www.propfinancing.com

We offer 30 year loans on single family houses!

-- 
You received this message because you are subscribed to a topic in the 
Google Groups "GWT Users" group.
To unsubscribe from this topic, visit 
https://groups.google.com/d/topic/google-web-toolkit/E3P4xZ8SFCg/unsubscribe
.
To unsubscribe from this group and all its topics, send an email to 
google-web-tool...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/google-web-toolkit/0e1b79f7-fa2e-482f-899b-65c5e9ca3e72n%40googlegroups.com
 
<https://groups.google.com/d/msgid/google-web-toolkit/0e1b79f7-fa2e-482f-899b-65c5e9ca3e72n%40googlegroups.com?utm_medium=email&utm_source=footer>
.

-- 
You received this message because you are subscribed to the Google Groups "GWT 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to google-web-toolkit+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/google-web-toolkit/c66862dd-bcfc-4516-b2bf-c5dc17a73deen%40googlegroups.com.

Reply via email to