Welcome!

Open Source Cloud Authors: Elizabeth White, Zakia Bouachraoui, Liz McMillan, Pat Romanski, Yeshim Deniz

Related Topics: Open Source Cloud, Release Management

Open Source Cloud: Blog Feed Post

Event Handling in SproutCore 1.0 - Part 2 - Dragging a View

Adding event handlers to drag a view around the window

In my last post I introduced event delegation in SproutCore and the basics of how to handle events.   In this post I’m going to build on this foundation to show you how you can add event handlers to drag a view around the window.*

Introducing the Mouse Events

As I noted in the first post, SproutCore recognizes several different types of mouse events.  Most of these events are essentially the same events sent by most browsers, though some differ significantly in order to give you tighter control.

Remember that to listen for events, you just need to add a method to your view with the same name.  Here is a quick rundown of the different methods you can add to your view:

  • mouseDown() - Called when the mouse button is pressed while over your view.   You must return YES (i.e. true) from this method for mouseDragged() or mouseUp() to be called.
  • mouseDragged() - Called when the mouse is moved while the button is pressed.  This is only called if you returned YES from mouseDown().
  • mouseUp() - Called when the mouse button is released.  Only called if you returned YES from mouseDown().
  • mouseOver() - Called when the mouse enters the view’s visible area.
  • mouseOut() - Called when the mouse leaves the view’s visible area.
  • mouseMoved() - Called whenever the mouse is moved while over the view.

It’s important to note that all of these events, except for mouseDragged() and mouseUp() are sent first to the view that is directly under the mouse pointer at the time of the event.  mouseDragged() and mouseUp() only happen after a mouseDown() event.  They are always sent first to the view that implemented mouseDown() AND returned YES (or true) from that method.

Events do bubble up your view hierarchy using something called a Responder Chain, but that will be the subject for another post.

Event handler methods are always passed an SC.Event object describing the event.  This class provides a consistent cross-platform API for accessing event info.  In general, it follows the API conventions for the built-in Event object on Firefox.

Listening For Dragging

So, let’s say we want to create a view that can be dragged around the screen.  To do this, we need to implement three of the above event handlers: mouseDown(), mouseDragged() and mouseUp().

Let’s start with mouseDown().  The primary purpose of this method is to setup any information we need to save to handle dragging and, of course, to return YES so that we get our other calls.  Here’s some good starter code:

MyApp.MyDragView = SC.View.extend({

  mouseDown: function(evt) {
    var layout = this.get('layout');
    this._mouseDownInfo = {
      pageX: evt.pageX, // save mouse pointer loc for later use
      pageY: evt.pageY,
      left:  layout.left, // save layout info 
      top: layout.top
    };
    return YES; // so we get other events
  }

});

The mouseUp() handler is also pretty simple.  It just needs to do some cleanup.  Basically delete the mouseDownInfo hash and return YES to indicate that the event has been handled:

  mouseUp: function(evt) {
    // apply one more time to set final position
    this.mouseDragged(evt); 
    this._mouseDownInfo = null; // cleanup info
    return YES; // handled!
  }

Note that this method also calls mouseDragged().  This is the same method that will be called whenever the mouse is moved with the button pressed.  The reason you want to call this method again here is to give the view one last chance to position itself with the position mouse location.  Otherwise you might find your view will occasionally “miss” your last drag just before you release the mouse.

So with mouseDown() and mouseUp() handled, we just need to add the dragging support.  This is where the magic happens.  All we do in this method is compare the current location of the mouse against the original location of the mouse at mouseDown().  We then adjust the location by this same delta from the original position.  Here’s how this looks in code:

  mouseDragged: function(evt) {
    var info = this._mouseDownInfo,
        loc;
 
    // handle X direction
    loc = info.left + (evt.pageX - info.pageX);
    this.adjust('left', loc);

    // handle Y direction
    loc = info.top + (evt.pageY - info.pageY) ;
    this.adjust('top', loc);

    return YES ; // event was handled!
  }

One interesting thing to pay attention to here is the way we calculate the new location of the view.  Most developers write dragging code for the first time by examining the current mouse location against the last time mouseDragged() was called.  Then they adjust the top/left by the delta.  This code instead saves the mouse and view location at mouseDown() and compares against that.

Note also the use of adjust().  This method is an easy way to adjust one or more layout parameters on your view without having to generate a whole new layout object.  It is very efficient for rendering.

The reason we take this approach here is because you want the offset of the mouse, relative to the view, to always remain fixed while you drag around.  Sometimes when you just look at the delta between events, this won’t happen.  It is usually always better to write UI code using this kind of “instantaneous point” approach - where calling a method with the same params will always have the same results, regardless of how it was called in the past.

Putting It All Together

So that’s all there is to it.  Three methods and you’ve added nice professional draggable views to your UI.  To help finish this example out, I’m going to add a property called “isDragging” and update the render() method of the view to add/remove a class name when that changes.  This will allow you to draw the view highlighted.  Here’s how the view looks when you put it together:

MyApp.MyDragView = SC.View.extend({

  // ..........................................................
  // DISPLAY
  // 

  // class name is added to the output HTML  
  classNames: 'my-drag-view',
  
  // becomes YES when a drag becomes.
  isDragging: NO,
  
  // make sure view will auto-rerender.
  displayProperties: 'isDragging'.w(),
  
  render: function(context, firstTime) {
    // add/remove class name.  Use CSS rule like this to style:
    // .sc-view.my-drag-view.dragging 
    //
    context.setClass('dragging', this.get('isDragging'));
  },

  // ..........................................................
  // EVENT HANDLING
  // 
  
  mouseDown: function(evt) {
  
    // indicate dragging - rerenders view
    this.set('isDraggin', YES);
    
    var layout = this.get('layout');
    this._mouseDownInfo = {
      pageX: evt.pageX, // save mouse pointer loc for later use
      pageY: evt.pageY,
      left:  layout.left, // save layout info 
      top: layout.top
    };
    return YES; // so we get other events
  },
  
  mouseUp: function(evt) {
  
    // no longer dragging - will rerender
    this.set('isDragging', NO);
    
    // apply one more time to set final position
    this.mouseDragged(evt); 
    this._mouseDownInfo = null; // cleanup info
    return YES; // handled!
  },
  
  mouseDragged: function(evt) {
    var info = this._mouseDownInfo,
        loc;
 
    // handle X direction
    loc = info.left + (evt.pageX - info.pageX);
    this.adjust('left', loc);

    // handle Y direction
    loc = info.top + (evt.pageY - info.pageY) ;
    this.adjust('top', loc);

    return YES ; // event was handled!
  }
  

});

Now you know how to do basic mouse event handling. Next we’re going to head into keyboard land. Before that, however, you’ll need to learn another key concept with events: the Responder Chain

* Note that SproutCore also has a generic facility for drag and drop called SC.Drag.  SC.Drag is better for complex operations and will eventually integrate with the browser-based drag/drop events in HTML5.  But that is a topic for another day.

Read the original blog entry...

More Stories By Charles Jolley

Charles Jolley is the creator of SproutCore and CEO of Sproutit, which provides consulting and software services for building SproutCore applications on the web. He has helped build some of the most popular RIAs on the web today.

IoT & Smart Cities Stories
The platform combines the strengths of Singtel's extensive, intelligent network capabilities with Microsoft's cloud expertise to create a unique solution that sets new standards for IoT applications," said Mr Diomedes Kastanis, Head of IoT at Singtel. "Our solution provides speed, transparency and flexibility, paving the way for a more pervasive use of IoT to accelerate enterprises' digitalisation efforts. AI-powered intelligent connectivity over Microsoft Azure will be the fastest connected pat...
There are many examples of disruption in consumer space – Uber disrupting the cab industry, Airbnb disrupting the hospitality industry and so on; but have you wondered who is disrupting support and operations? AISERA helps make businesses and customers successful by offering consumer-like user experience for support and operations. We have built the world’s first AI-driven IT / HR / Cloud / Customer Support and Operations solution.
Codete accelerates their clients growth through technological expertise and experience. Codite team works with organizations to meet the challenges that digitalization presents. Their clients include digital start-ups as well as established enterprises in the IT industry. To stay competitive in a highly innovative IT industry, strong R&D departments and bold spin-off initiatives is a must. Codete Data Science and Software Architects teams help corporate clients to stay up to date with the mod...
At CloudEXPO Silicon Valley, June 24-26, 2019, Digital Transformation (DX) is a major focus with expanded DevOpsSUMMIT and FinTechEXPO programs within the DXWorldEXPO agenda. Successful transformation requires a laser focus on being data-driven and on using all the tools available that enable transformation if they plan to survive over the long term. A total of 88% of Fortune 500 companies from a generation ago are now out of business. Only 12% still survive. Similar percentages are found throug...
Druva is the global leader in Cloud Data Protection and Management, delivering the industry's first data management-as-a-service solution that aggregates data from endpoints, servers and cloud applications and leverages the public cloud to offer a single pane of glass to enable data protection, governance and intelligence-dramatically increasing the availability and visibility of business critical information, while reducing the risk, cost and complexity of managing and protecting it. Druva's...
BMC has unmatched experience in IT management, supporting 92 of the Forbes Global 100, and earning recognition as an ITSM Gartner Magic Quadrant Leader for five years running. Our solutions offer speed, agility, and efficiency to tackle business challenges in the areas of service management, automation, operations, and the mainframe.
The Jevons Paradox suggests that when technological advances increase efficiency of a resource, it results in an overall increase in consumption. Writing on the increased use of coal as a result of technological improvements, 19th-century economist William Stanley Jevons found that these improvements led to the development of new ways to utilize coal. In his session at 19th Cloud Expo, Mark Thiele, Chief Strategy Officer for Apcera, compared the Jevons Paradox to modern-day enterprise IT, examin...
With 10 simultaneous tracks, keynotes, general sessions and targeted breakout classes, @CloudEXPO and DXWorldEXPO are two of the most important technology events of the year. Since its launch over eight years ago, @CloudEXPO and DXWorldEXPO have presented a rock star faculty as well as showcased hundreds of sponsors and exhibitors! In this blog post, we provide 7 tips on how, as part of our world-class faculty, you can deliver one of the most popular sessions at our events. But before reading...
DSR is a supplier of project management, consultancy services and IT solutions that increase effectiveness of a company's operations in the production sector. The company combines in-depth knowledge of international companies with expert knowledge utilising IT tools that support manufacturing and distribution processes. DSR ensures optimization and integration of internal processes which is necessary for companies to grow rapidly. The rapid growth is possible thanks, to specialized services an...
At CloudEXPO Silicon Valley, June 24-26, 2019, Digital Transformation (DX) is a major focus with expanded DevOpsSUMMIT and FinTechEXPO programs within the DXWorldEXPO agenda. Successful transformation requires a laser focus on being data-driven and on using all the tools available that enable transformation if they plan to survive over the long term. A total of 88% of Fortune 500 companies from a generation ago are now out of business. Only 12% still survive. Similar percentages are found throug...