Force Touch for Safari in Javascript

First I explored Force Click on the Mac. Now it is on the web with javascript in Safari. There has long been hooks for touches and gestures on Safari for iOS devices. Now we have a new paradigm for the web from these new force touch enabled Macbook Pros. My demo does not work currently with the new 3d Touch enabled iPhone 6s' but I suspect these additions will make their way to the phone sooner than later.


Safari has long been a hotbed
of new DOM and javascript features that may or may not trickle down to other browsers. It allows web apps and html 5 app (gross) to have some of the features that are easily accessible in native programming. The bad part about these new features is that it takes a long time for them to get to other browsers so for now it is only on Safari. At WWDC this year Apple presented new features in Safari and
they mention the force touch features at 33:40 in this video
.

This newest additions gives us access to force touch in a way that is very close to what we have on Mac OS X. It is accessible for html elements in two different ways. You can apply the callback hook in javascript or define it inline in the html.

The first way is to add event listeners to an element. The
syntax for this
is:

element.addEventListener(event, function, useCapture);

The event to monitor is a string, the function is the actual name of a function and the useCapture defines whether the function is called at the beginning or the end of the event cycle. It is much like the Responder chain in iOS or Mac OS X programming. The events are offered to the child element and then 'bubbled' back to the enclosing parent elements.

var aButtonElement = document.getElementById("aButton");
  aButtonElement.addEventListener("webkitmouseforcewillbegin", prepareForForceClick, false);
  aButtonElement.addEventListener("webkitmouseforcedown", enterForceClick, false);
  aButtonElement.addEventListener("webkitmouseforceup", endForceClick, false);
  aButtonElement.addEventListener("webkitmouseforcechanged", forceChanged, false);

So you'd need accompanying functions like:

function prepareForForceClick(event) {}

The other way to invoke these callback hooks are to define them like I have in my demo, right inline:

<div id="touchArea"
  onmousedown="mouseDown(event);"
  onmousemove="mouseMoved(event);"
  onWebkitmouseforcewillbegin="forceWillBegin(event);"
  onWebkitmouseforcedown="forceDown(event);"
  onWebkitmouseforcechanged="forceChanged(event);"
  onWebkitmouseforceup="forceUp(event);" >

The object 'even't that is passed back then has many member variables that define things like how hard the force touch was tapped.

mouseEvent member variables

The member variable we're looking for is event.webkitForce. With a normal mouse when you click this variable gets a value of 1. This mirror's apple's constant for regular clicking and is the value in this constant:

MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN

There is another constant that has the value of a force click mouse down event:

MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN;

Apple says to use these constants because they could change at any time. The second constant's value is 2 currently. That means that when not clicking webkitForce is 0 and with a regular mouse on click that value is set to 1. With a Force Touch trackpad it goes right to 1 on click and then with more pressure builds to 2 and you feel a 'tap'. It then will build all the way to 2.999.

In this demo with a regular mouse the yellow circle will just stay yellow and will follow the mouse because we are tracking it in the mouseDown(event) and mouseMoved(event) functions.

function mouseDown(event) {
circleSize(event.webkitForce);
circleMove(event.clientX, event.clientY);
updateTextReadout(event.webkitForce);
}
 
function mouseMoved(event) {
var force = (event.webkitForce==0)? 1: event.webkitForce;
//since I am basing the size of the circle on this variable 
//I am limiting it to 1 so that the circle is always visible.
circleSize(force);
circleMove(event.clientX, event.clientY);
updateTextReadout(event.webkitForce); //this prints the recorded value though
}

This screen cap shows that a regular mouse, or in this case my external Apple trackpad can only get to a webkitForce of 1. Basically if you don't have a Force Click touchpad on a newer machine then this is what you'll see.

Force Click on Safari with a Force Touch Trackpad

With a fancy Force Click trackpad you will see the yellow circle instantaneously go beyond wekitForrce 1 and turn blue on its way to a value of 2 and then over 2 it will turn red. This could easily be adapted to provide the width of a brush drawing or some other neatly secretive and powerful action.

Force Click with a regular mouse

Luke, use the force click. Check out the code on github.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.

About the Author