Draggable blocks across divs

659 views
Skip to first unread message

tushar mhaskar

unread,
Aug 10, 2018, 6:41:36 PM8/10/18
to Blockly
In the below picture all green boxes are <div> tags. What I want to do is make the blockly blocks draggable across neighbouring <div>'s
Any help will be appreciated.

Screen Shot 2018-08-10 at 3.40.09 PM.png

picklesrus

unread,
Aug 13, 2018, 1:38:06 PM8/13/18
to Blockly
Do you want to drag a block out of the Blockly workspace into another generic, non-Blockly, div on your site?  You can make the block drag outside the Blockly workspace div by changing the z-ordering of the thing being dragged and changing the overflow property of the div.  Scratch 3 does something like this.  Check it out here: https://beta.scratch.mit.edu

Do you want to be able to drop the block outside the Blockly workspace? If so, what do you want to happen?

-picklesrus

tushar mhaskar

unread,
Aug 13, 2018, 1:51:25 PM8/13/18
to Blockly

Thanks for the reply picklesrus. I will try out the scratch 3. 

I am developing a feature with a flow and other divs represent specific part of the flows. Thats the reason i want the configurability of moving the blockly blocks outside the blockly workspace.

picklesrus

unread,
Aug 13, 2018, 4:33:23 PM8/13/18
to Blockly
I'm still not quite sure I totally understand what you're up to, but the CSS to get the blocks to drag outside the div is:
  • Remove the overflow:hidden (or change it to overflow:visible) from blocklySvg and injectionDiv classes.  
  • Change the z-index of either the blocklyBlockDragSurface or blocklyToolboxDiv so that blocklyBlockDragSurface is higher of blocklyToolboxDiv.
That won't let you actually drop it outside though - when you let go at the end of a drag, the block will end up back in the workspace.  Changing that part is a little trickier :)

-picklesrus

tushar mhaskar

unread,
Aug 16, 2018, 12:45:10 AM8/16/18
to Blockly
Thanks!! Any suggestions for implementing the drop part?

Timo Herngreen

unread,
Aug 16, 2018, 9:13:07 AM8/16/18
to Blockly
I've got you back!

You can draw the SVG of the block in another div!

for example, here is the code to make it draw all the blocks:

[div here].innerHTML = "<svg id='blocksvg'></svg>" //creates the svg (with id blocksvg) inside the div

var svg = workspace.getParentSvg().getElementsByClassName("blocklyWorkspace")[0].getElementsByClassName("blocklyBlockCanvas")[0].getElementsByClassName("blocklyDraggable blocklySelected")[0]
svg
.setAttribute("transform","") //getting rid of the transform property

[div here].children.blocksvg.innerHTML = svg.outerHTML //sets the SVG to the block's svg


I hope this helps.


Op donderdag 16 augustus 2018 06:45:10 UTC+2 schreef tushar mhaskar:

picklesrus

unread,
Aug 16, 2018, 7:41:10 PM8/16/18
to Blockly

If you want the block to disappear from the Blockly workspace when you drop it in the other div, you'll also need to fiddle with the event handlers so that you catch the end of the drag action and tell Blockly to delete the block (I'd try https://developers.google.com/blockly/reference/js/Blockly.WorkspaceSvg#removeTopBlock) instead of doing the usual thing.

-picklesrus

tushar mhaskar

unread,
Aug 19, 2018, 1:56:31 AM8/19/18
to Blockly
I tried https://developers.google.com/blockly/reference/js/Blockly.WorkspaceSvg#removeTopBlock as well as https://developers.google.com/blockly/reference/android/com/google/blockly/model/Workspace#addBlockToTrash(com.google.blockly.model.Block). Both of them do not work
Below is my code.

<!DOCTYPE html>
<html>
   
<head>
     
<meta charset="utf-8">
     
<title>Blockly Demo: Custom Dialog</title>
     
<script src="../../blockly_compressed.js"></script>
     
<script src="../../blocks_compressed.js"></script>
     
<script src="../../msg/js/en.js"></script>
     
<script src="blocks.js"></script>
     
<link rel="stylesheet" href="style.css">
     
<script>
       
function allowDrop(ev) {
            ev
.preventDefault();
       
}


       
function drag(ev) {
            ev
.dataTransfer.setData("text", ev.target.id);
       
}


       
function drop(ev) {
            ev
.preventDefault();
           
var data = ev.dataTransfer.getData("text");
            ev
.target.appendChild(document.getElementById(data));
       
}


       
function login() {
           
var y = document.getElementById("submit");
            y
.innerHTML="Logged In";
            document
.getElementById("email").disabled = true;
            document
.getElementById("pwd").disabled = true;
       
}
     
</script>
   
</head>
   
<body>
     
<div id="blocklyDivMain" style="position:fixed;top:0;left:0;right:0;bottom:0">
       
<div id="upperDiv" style="height:25%;width:100%;top:0;left:0;position:absolute;border: 1px solid #0099FF;"
           
ondrop="drop(event)" ondragover="allowDrop(event)">
           
<div id="login" style="height:30%;left:10%;width:50%;position:absolute;margin-left:15%; padding: 5px;">
               
<img src="logo.png" alt="Smiley face" height="70" width="120"/><br>
               
<input id="email" type="text" name="fname" value="usbuyer@abc.com" ><br>
               
<input id="pwd" type="text" name="lname" value="***********" style="margin-top:3px;"><br>
               
<button id="submit" type="submit" value="Submit" style="background-color:#009cde;width:131px;margin-top:13px;" onclick="login()">Submit</button><br>
           
</div>
           
<div id="centerDiv" style="height:30%;left:50%;width:15%;position:absolute;">
             
<br><br>
             
<input type="radio" name="gender" value="male" class="radioRight"/><br>
             
<input type="radio" name="gender" value="male" class="radioRight"/>
             
<input type="radio" name="gender" value="male" class="radioRight"/>
           
</div>
           
<div id="topRightDiv" style="height:60%;left:65%;width:34%;position:absolute;">
             
<img src="ryp.png" alt="Smiley face" height="35" width="120"/><br>
           
</div>
           
<div id="topRightDivBottom" style="height:10%;left:65%;width:50%;top:80%;position:absolute;">
             
<button id="submit" type="submit" value="Pay" style="background-color:#009cde;width:131px;margin-top:13px;" onclick="login()">Pay</button><br>
           
</div>
       
</div>


       
<div id="leftDiv" style="height:65%;width:50%;top:25%;left:0%;position:absolute;border: 1px solid #0099FF"></div>
       
<div id = "rightDiv" style="height:65%;width:50%;top:25%;left:50%;position:absolute;border: 1px solid #0099FF;"></div>
       
<button id="blocklyDivButton" style="text-align:center">
             
<div id="div1" style="height:10%;width:100%;top:90%;left:0%;position:absolute;border: 1px solid #0099FF;
              background
-color:#ffffb3;text-align:center;vertical-align: middle;line-height: 90px;
              font
-family: Arial, Helvetica, sans-serif;font-size:30px;font-weight:bold;">
         
<b>Payments Platform</b>
             
</div>
       
</button>
       
   
</div>
     
<xml id="toolbox">
           
<block type="payment_options_list"></block>
           
<block type="user_identifier"></block>
           
<block type="account_number" name="accnum">
               
<value name="MESSAGE">
                 
<block type="text">
                     
<field name="TEXT"></field>
                 
</block>
               
</value>
           
</block>
           
<block type="email_address"></block>
           
<block type="amount"></block>
           
<block type="constraints"></block>
           
<block type="preferences"></block>
     
</xml>
     
<script>
         
var primaryWorkspace = Blockly.inject('leftDiv',
             
{
               media
: '../../media/',
               toolbox
: document.getElementById('toolbox'),
             
});
         
         
// Inject secondary workspace.
         
var secondaryWorkspace = Blockly.inject('rightDiv',
             
{media: '../../media/'});


       
// Inject secondary workspace.
       
var topRightWorkspace = Blockly.inject('topRightDiv',
           
{media: '../../media/'});
         
         
// Listen to events on primary workspace.
         primaryWorkspace
.addChangeListener(mirrorEvent);
         secondaryWorkspace
.addChangeListener(getCoordinates);
         document
.getElementById("blocklyDivButton").addEventListener("click", getJson);
         
var json = "";
         
function mirrorEvent(primaryEvent) {
           
if (primaryEvent.type == Blockly.Events.UI) {
             
return;  // Don't mirror UI events.
           
}
           
// Convert event to JSON.  This could then be transmitted across the net.
           json
= primaryEvent.toJson();
         
}


         
var blockId = "";
         
function getCoordinates(secondaryEvent) {
           
if (secondaryEvent.type == Blockly.Events.UI) {
             
return;  // Don't mirror UI events.
           
}
           
if (secondaryEvent.type == Blockly.Events.BLOCK_MOVE) {
             
if(secondaryEvent.newCoordinate.y < -2) {
                movedBlockId
= secondaryWorkspace.getBlockById(secondaryEvent.blockId).type;
                generateBlock
(movedBlockId);
                secondaryWorkspace
.removeTopBlock(movedBlockId);
             
}
           
}
         
}


         
function generateBlock(blockId) {
           
var newBlockResponse =
           
{   "blockId" : "2",
               
"type" : "create",
               
"xml" : "<block type=\"" + blockId + "\"></block>"
           
};
           
var newEvent = Blockly.Events.fromJson(newBlockResponse, topRightWorkspace);
            newEvent
.run(true);
           
         
}
         
         
function getJson() {
           
var response =
           
{   "blockId" : "1",
               
"type" : "create",
               
"xml" : "<block type=\"options_response_list\"><value name=\"payment_option_id\"><block type=\"po_id\"\/></value><value name=\"funding_options\"><block type=\"funding_options_list\"><value name=\"mastercard\"><block type=\"mastercard\"\/></value><value name=\"visa\"><block type=\"visa\"\/></value><value name=\"balance\"><block type=\"balance\"\/></value><value name=\"boa\"><block type=\"boa\"\/></value><value name=\"chase\"><block type=\"chase\"\/></value></block></value></block>"
           
};
           
var secondaryEvent = Blockly.Events.fromJson(response, secondaryWorkspace);
           secondaryEvent
.run(true);
         
}
     
</script>
   
</body>
</html>

tushar mhaskar

unread,
Aug 19, 2018, 2:53:07 AM8/19/18
to Blockly
With the above mentioned code I was able to drag it and put it in new workspace, but then i am unable to delete the dragged block from the first workspace. Any pointers to that?

Rachel Fenichel

unread,
Aug 21, 2018, 2:31:21 PM8/21/18
to Blockly
You may actually need to delete the old block and create a new block on the second workspace, positioned in exactly the same spot.  This is what we do when dragging from the flyout to the workspace, for instance.  RemoveTopBlock removes the block from the list of top blocks in the workspace, but not from the block db or anything else.  Also, moving a block and keeping its ID may cause ID conflicts.

If you really want to do it without deleting and creating the block, you'll have to disentangle all references from the block to the workspace and vice versa.  I would look at block (and blockSvg) constructors and dispose functions to figure out exactly what references those are.  They will include the workspace's blockDB, the block's workspace reference, and the same for any connected blocks.  I don't think there's a function that will do only that, so you'll need to write it.

Hope that helps,
Rachekl
Reply all
Reply to author
Forward
0 new messages