Drag and Drop 1: objects within scenes

If your configurator has options to position items, then give your user the ability to position those items visually by dragging them directly in the scene.

This walkthrough will guide you step-by-step in making a draggable component in your 3D Scene, constraining its movement with rules, and sharing its position with the configurator using message rules.

Understanding Drag and Drop

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:

  1. one or more components of the configurable product have a range of position options.

  2. the customer must select one of these positions from that defined range of choices.

As a user, that’s pretty simple. But as a scene designer and configuration engineer, 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.

Step-by-step guide

In this basic walkthrough, we will…

  1. Learn the basics of the draggable block by adding a single draggable object to the scene (a landscaping tree next to our building).

  2. Use messaging rules to inform our configurator about the user’s dragging activities in the scene, so we can store the tree’s location.

  3. Add simple constraints to the draggable object: a “snap to grid” feature.

  4. 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.

Prerequisites

In this example, we're re-using the configurator and scene from another walkthrough on creating nested configurators and scenes. You can follow those instructions, or create your own Building configurator, Building scene, relate the two to each other, and in the scene create a building mesh.

Add a simple draggable object

Let’s get started!

To begin learning how dragging works, let’s add a pine tree to our parent “Building” scene, and then make it draggable.

  1. 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? Meshes > Create Primitive > Create Plane. Give it the name "Plane."

  2. Add a new cone object (Meshes > Create Primitive > Create Cone) with the name "Cone".
    Apply a greenish material to the cone, and scale it to be smaller than the plane. position it somewhere near the edge of the plane. You may have other objects in your scene already to provide realism like the car seen here: that’s fine.

  3. 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.

  4. 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.



  5. Detour: using groups for positioning.
    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 group. Groups 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 group, then that object will follow the group around if the group is moved in space. Think of the group like a file folder: if you move it, you move everything within it as well.

  6. Return to the scene, and create a new group (right-click Meshes in the node tree, then select Create Group). Here, we gave this group the name "Null." The group appears in the node tree, but in the 3D scene it is invisible. You can make it appear in the scene by selecting it in the node tree on the left, then selecting the move gizmo.

  7. Use the move gizmo or properties pane to move the group to the same location as your cone.

  8. Finally, in the object explorer, drag your cone on top of the group: the cone will become indented in the tree, showing it is a child of the group.

  9. Drag your group around: you’ll see the cone comes along for the ride.

  10. Now that you have a nice group handle to drag with, update your scene rule to use that group for dragging, instead of the cone:

  11. Test your work: the tree is now positioned as you would expect, thanks to the group container.

    Using a group to position one or many other objects is a useful technique. The group is invisible, renamable, and gives you a way to control one or many other scene objects 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 themselves.

  1. 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. On the “Add draggable” block click the “+” mutation handle to add a “Dropped” slot. The code in this new slot 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. An example “ObjectBeingDragged” message could look like this:
    { "object": "tree", "x" : 8.666532706801227, "z" : 12.829922634805804 }
  2. Next, in your Building configurator, create two new fields to store this incoming data: 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.

  3. 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.

  4. 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.

  5. Finally, it’s good practice to “close the loop” between configurator and scene. Up to this point, moving the group 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 group in the scene.

    In the Building scene, add a new scene rule that updates the position of the group 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.

 

As your user interacts with the scene, keep in mind the data you need to gather. Dragging objects is one of many interactions that you need to save using this technique. Others can include:

  • Dragging objects (store the position in the configurator)
  • Dragging nested configurators (store the position in the parent configurator)
  • Sketching paths (store path data in the configurator)

When you save this data using message rules, it'll be available for the user later:

  • When they open the configuration again
  • When they submit their configuration, and the workflow renders the scene into an image for the quote

 

Apply Simple Constraints: “snap to grid” and constrain to one axis

Just because your user wants the tree somewhere doesn’t mean that position is valid. 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 they’re 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 their 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.

  1. In your “Building” scene rule, mutate the “add draggable” block to add the Dragging slot.

  2. 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 they plant the tree in a bad location.

  1. 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.)

  2. 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.

Was this article helpful?