Navigating to the top of the workspace

79 views
Skip to first unread message

Max Stephen Russell

unread,
Nov 1, 2025, 8:00:58 PM (5 days ago) Nov 1
to Blockly
What is the simplest or best way to return the view to where the top block is positioned at the top left of the workspace?

Thank you.

Steve Russell

epas...@google.com

unread,
Nov 3, 2025, 12:27:40 PM (3 days ago) Nov 3
to Blockly
The easiest way is probably going to  be using getTopBlocks and scrollBoundsIntoView: 

```
let topBlocks = workspace.getTopBlocks(true);
if (topBlocks.length > 0) {
    workspace.scrollBoundsIntoView(topBlocks[0].getBoundingRectangle());
}
```

Ben Henning

unread,
Nov 3, 2025, 12:59:58 PM (3 days ago) Nov 3
to blo...@googlegroups.com
Alternative option: it's worth noting that 'scrollBoundsIntoView' might not specifically put the top block in the upper left (I believe it will only scroll horizontally or vertically enough to bring it on screen). To get the exact effect you're looking for Max you may need to implement a custom version of 'scrollBoundsIntoView' using WorkspaceSvg's 'scroll' function.

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/blockly/37ceb267-1b37-4bb6-ab24-3c987a62d8bbn%40googlegroups.com.

Maribeth Moffatt

unread,
Nov 3, 2025, 3:59:30 PM (3 days ago) Nov 3
to Blockly
There are a couple other methods in `workspace_svg` that might also work depending on what you want to do.

- scrollCenter will scroll back to the center of the workspace, to where it was when the workspace started. but depending on where the user placed their blocks, they would not necessarily be in the top left.
- centerOnBlock will put the given block in the center of the workspace (I know not the top left like you're asking)
- cleanUp will actually move all the blocks to put them in a nice column and put the first one in the top left

Hope that helps!

Max Stephen Russell

unread,
Nov 3, 2025, 8:20:32 PM (3 days ago) Nov 3
to Blockly
Thank you all very much for your kind and informative responses. The following callback has evolved from pretty harsh testing so far. To my surprise, our results appear to be perfect. The relative positions of unconnected, randomly-placed blocks are not disturbed.

ws.registerButtonCallback('returnToTop', () => {
  const ws = Blockly.getMainWorkspace();
  const main = ws.getTopBlocks(false)[0];  // first connected stack
  if (main) {
    main.moveTo({ x: 0, y: 0 });
    ws.scroll(0, 0);
    ws.getToolbox().setSelectedItem(null);  // close flyout
  }
});

-Steve Russell

Max Stephen Russell

unread,
Nov 4, 2025, 9:59:45 PM (2 days ago) Nov 4
to Blockly
Or more properly,

function returnToTopBtnCallback() {
  const ws = Blockly.getMainWorkspace();
  const main = ws.getTopBlocks(false)[0];
  if (main) {
    main.moveTo({ x: 0, y: 0 });
    ws.scroll(0, 0);
    ws.getToolbox().setSelectedItem(null);
  }
}

ws.registerButtonCallback('returnToTopBtn', returnToTopBtnCallback);

Mark Friedman

unread,
Nov 5, 2025, 12:56:05 PM (yesterday) Nov 5
to blo...@googlegroups.com
Just curious why you are explicitly passing false to getTopBlocks? I would think that you would want to rely on the blocks being ordered (see the doc for getTopBlocks). 

-Mark


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.

Max Stephen Russell

unread,
Nov 5, 2025, 3:35:35 PM (24 hours ago) Nov 5
to Blockly
Mark,

In answer to your question, my app uses a logical flow from start to finish, including instances of previousStatement and nextStatement. An immovable hat block always sits as the top of the stack. If a user plays around and positions an unconnected block above the stack, and I pass true to getTopBlocks, that unconnected block will be moved in front of my hat block and will share the top left position.

Your question led to some further testing here and seeming confirmation of our method. Thank you.

-Steve

Mark Friedman

unread,
Nov 5, 2025, 5:15:13 PM (22 hours ago) Nov 5
to blo...@googlegroups.com
I think I understand.  When you said that you wanted the "top block" to be positioned in the upper left I thought you meant the top block as Blockly understands it.  But you actually meant the top block as you understand it, i.e. your "immovable hat block".  That makes sense, but if I were you I'd worry that there is no guarantee that calling getTopBlocks(false) will always return your immovable hat block as its first entry.  It might do so right now, but the order of the blocks is technically undetermined when you pass false to getTopBlocks, so that might change as your app changes or as Blockly changes. To be safe, I would suggest iterating through the array of blocks that getTopBlocks returns until you get your immovable hat block, or provide some other way to keep track of your immovable hat block.  That would help future-proof your app.

Hope this helps.

-Mark


Max Stephen Russell

unread,
Nov 5, 2025, 5:27:40 PM (22 hours ago) Nov 5
to blo...@googlegroups.com
We almost did what you suggest here, and now we will follow your advice. I had forgotten to mention that my immovable hat block is always the first block created. Thanks again, Mark.

-Steve Russell


Mark Friedman

unread,
Nov 5, 2025, 5:50:41 PM (22 hours ago) Nov 5
to blo...@googlegroups.com
On Wed, Nov 5, 2025 at 2:27 PM Max Stephen Russell <maxsr...@gmail.com> wrote:
We almost did what you suggest here, and now we will follow your advice. I had forgotten to mention that my immovable hat block is always the first block created.

Yeah, that's probably why it appears first, but there's no guarantee of that in the future.

Thanks again, Mark.
You're very welcome!

-Mark

Max Stephen Russell

unread,
Nov 5, 2025, 7:47:23 PM (20 hours ago) Nov 5
to Blockly
And so the solution for returning to the top of the stack, for my app, appears to be:

function returnToTopBtnCallback() {
  const ws = Blockly.getMainWorkspace();
  const headliner = ws.getBlocksByType('headliner_rtl')[0]; // immovable hat block
  if (headliner) headliner.moveTo({ x: 0, y: 0 });
  ws.scroll(0, 0);
  ws.getToolbox().setSelectedItem(null); // close Action flyout, which contains 'Return to Top' button
}

ws.registerButtonCallback('returnToTopBtn', returnToTopBtnCallback);

-Steve

Mark Friedman

unread,
Nov 5, 2025, 7:55:47 PM (19 hours ago) Nov 5
to blo...@googlegroups.com

Maribeth Moffatt

unread,
2:27 PM (1 hour ago) 2:27 PM
to Blockly
A few optional suggestions:

If you just put the block at 0,0 to start with and then it's immovable, you don't need to go searching through all the blocks to find that one nor move it to 0,0 again in this callback. Simply scroll to 0,0. This assumes that you specify the coordinates of the block when you load it onto the workspace initially, so maybe it doesn't work depending on what you're doing.

Also, you might want to consider `ws.hideChaff()` instead of `ws.getToolbox().setSelectedItem(null);`

`hideChaff` will close the flyout without affecting the toolbox's memory of which item was selected. This will help keyboard users if you decide to enable keyboard navigation, as pressing `T` to open the toolbox will remember the last category that was opened.

Maribeth
Reply all
Reply to author
Forward
0 new messages