Just about everyone understands drag and drop: by clicking and holding your mouse on an item, you can move it around (“drag”) until you let go of the mouse (“drop”). But what does this mean in the context of a configurable product? Usually, it means two things:
one or more components of the configurable product have a range of position options.
the customer must select one of these positions from that defined range of choices.
As a user, that’s pretty simple. But as a configurator administrator, it’s a little more complicated. You need to be sure of some other things, too:
What is the range of acceptable choices?
Does that set of acceptable choices change, if other fields of the product are adjusted by the user?
If the user’s choice is suddenly no longer acceptable, should we leave the component in its bad position and warn the user? Or should we automatically correct its position?
As you can see, creating an intuitive and easy interface for your user requires planning on your end. We’ll discuss these points below.
In this basic walkthrough, we will…
Learn the basics of the Draggable block by adding a single draggable object to the scene (a landscaping tree next to our building).
Use messaging rules to inform our configurator about the user’s dragging activities in the scene, so we can store the tree’s location.
Add simple constraints to the draggable object: a “snap to grid” feature.
Add more complex constraints to the tree, so it meets business rules. Specifically, we’ll make sure the tree is not accidentally dragged too close to the building.
Plan your design
Before starting work, review the requirements for the application.
Our walkthrough will add some power to an existing configurator that helps people configure their own building. That configurator is based on a nested setup, where a "Building" configurator can contain one or more "Building Floor" nested configurators. We will add a simple tree object to that "Building"configurator, so our users can decide how they want to customize their landscaping. In the next drag-and-drop walkthrough, we’ll learn how to make multiple objects, like the nested configurators, draggable.
Let’s get started!
Add a simple draggable object
To begin learning how dragging works, let’s add a pine tree to our parent “Building” scene, and then make it draggable.
In your “Building” parent scene, confirm that you already have a plane object that represents the ground. We’ll need it soon. Don’t have one? “Insert → Polymesh → Plane.”
Add a new cone object (Insert → Polymesh → Cone). Apply a greenish material to the cone, and scale it about 5-10 units tall. position it somewhere near the edge of the plane that’s already in your scene. You may have other objects in your scene already to provide realism like the car seen here: that’s fine.
In that same parent scene, create a new scene rule. In the rule, add a “draggable” block with the settings below. This block will make the “Cone” object draggable along the surface of the “Plane” object.
Test your work. Now, when the mouse is over the cone, the cone gets a highlight color. If you click and drag the cone, you can drag it anywhere on the plane.
Did you notice that the cone was re-positioned vertically? When you clicked it to start dragging, it sunk half-way down into the plane. This is because our “add draggable” rule has aligned the cone’s origin to the surface of the plane. Every object in a scene has an origin point, and that origin is usually at the mathematical center of the object (although you can change it). So, since the origin of the cone is halfway up its height, and the “add draggable” is aligning the cone by that point, the cone was pushed halfway into the plane.
Let’s fix the appearance of the tree by adding a null. Nulls are invisible points in space which help you logically organize other objects: if you make any object a child of another object in the scene’s explorer pane, like a null, then that object will follow the null around if the null is moved in space. Think of the null like a file folder: if you move it, you move everything within it as well.
Return to the scene, and create a new null (create → helper → null). The null appears as yellow cross-hairs.
Use the translate gizmo to move the null in the scene to the same location as your cone.
Finally, in the object explorer, drag your cone on top of the null: the cone will become indented in the tree, showing it is a child of the null.
Drag your null around: you’ll see the cone comes along for the ride.
Now that you have a nice null handle to drag with, update your scene rule to use that null for dragging, instead of the cone:
Test your work: the tree is now positioned as you would expect, thanks to the null container:
Using a null to position one or many other objects is a useful technique. The null is invisible, renamable, and gives you a way to control one or many other elements easily.
Use messaging rules to inform our configurator
We can drag and drop our pine tree anywhere in the big plane of our scene. But there’s nothing saving the location of that tree. For example, if the configurator is closed and re-opened, any of the user’s dragging selections in the scene will be lost. How can we fix that? The configurator is designed to store information in fields, so if we can inform the configurator about the changes the user is making in the scene, then those changes can be saved.
So, how do we send a message to the configurator, telling it that the tree has been moved? There’s a rule for that, called a Message Rule. If the scene sends a message to the configurator using a “Send Message” Snap block, and your configurator is listening for that message in a Message Rule, then information will flow from the scene back into the configurator.
This is perfect for us. Our Building scene can send a message back to the Building configurator, telling the configurator where our user is dragging the tree. After that, the configurator can use this information in various ways – such as writing that data into a field – just as though a user typed it in herself.
First, let’s send a message from the scene to the configurator. In your “Building” scene, edit the scene rule you’ve been working on. Mutate your “add draggable” block to add a “Dropped” connector. The code in this new connector will be run the instant your draggable item is dropped. In our example, we want to send a message to the configurator, informing the configurator about the new location of the tree. We’ll create a map to store that information, and then serialize the map into a text string to transmit it.
Curious about what that map looks like? Use your debugger to see the log file as it’s being made. But an example “ObjectBeingDragged” message could look like this:
Next, create two new fields in the configurator to store the Tree Position X and Tree Position Z (the location of the tree along these two dimensions). These are number fields. You might consider placing them on their own page, but it doesn’t matter where they are in the configurator UI.
Finally, let’s teach our configurator to listen for that message from the scene, and write the information into the tree position fields. Message rules are not part of the rule cycle: they are only run when a message event has been received. In the context of message rules, the Get block has access to an object that doesn’t exist in any other rule: the message object. Using the Get block, you can access the name of the message as well as the data inside it and other attributes.
So, in your “Building” configurator, create a new Message Rule. The Snap code shown here watches for a specific message called “ObjectBeingDragged”. If it sees this message come in, it will take the data from the message, de-serialize it into a map, and then write the correct information from that map into those two fields.
Test your work. When you drop the pine tree in the scene, you should see the default values of the Tree Position fields be overwritten with data from the scene.
Finally, it’s good form to “close the loop” between configurator and scene. Up to this point, moving the null container in the scene updates the fields in the configurator. But we haven’t done the reverse: we should ensure that editing the fields in the configurator moves the null in the scene.
In the Building scene, add a new scene rule that updates the position of the null handle for our cone, based on the data from the configurator:
Now your user can move the tree by either dragging it around in the scene, or by editing the position numbers in the configurator. Everything works.
Apply Simple Constraints: “snap to grid” and constrain to one axis
Just because your user wants the tree somewhere doesn’t mean it’s a valid position. Instant feedback is important here: we want our user to understand immediately that dragging is only allowed in one axis, and only to certain points. This is what the “Dragging” mutation of the Draggable block is for: those simple quick adjustments you want to make to what the user’s doing, while she’s doing it. Code placed in the Dragging connector runs many times per second as the user is dragging, so keep the code here to a minimum: depending on the device your user’s on, you can bog down her browser.
On the X axis, let’s constrain the tree to every half-meter. We can do this in the draggable rule itself by getting the position the user dragged it to, and simply overwriting that position with the same position rounded to the nearest .5
On the Z axis, let’s prevent any changes at all. Again in the draggable rule, we simply overwrite the new value with the starting value. This results in the object not being draggable in that dimension, like it’s sliding along an invisible track.
In your “Building” scene rule, mutate the “add draggable” block to add the Dragging connector.
In that new space, add the following two lines:
You’ll see how the object is constrained during the dragging, and the coordinates are sent to the configurator when the object is dropped. For the rest of this exercise, you can comment out or remove those two lines in orange above, so you have more flexibility in playing with some advanced constraints.
Apply advanced Constraints: implement business rules and warnings
For constraints more complex than some simple math, we’ll turn to the configurator. Since the configurator knows where the tree is, the configurator can compare the tree’s position to other data in the configurator, and give the user a warning if she plants the tree in a bad location.
In your configurator, add a new value rule called “Constrain Landscaping” to keep the position of the tree within a portion of the plane.
(your values may vary, depending on the size of your building, the size of the cone representing your tree, etc.)
Add a new validation rule, warning the user if the tree is too close to one side of that area.
Congratulations! You’ve added drag-and-drop functionality, and made sure it meets your business rules with constraints and warnings.