Skip to content

Instantly share code, notes, and snippets.

@hlvoorhees
Last active December 16, 2015 04:19
Show Gist options
  • Save hlvoorhees/5376764 to your computer and use it in GitHub Desktop.
Save hlvoorhees/5376764 to your computer and use it in GitHub Desktop.
d3 x3dom event test

Testing D3 mouse events with X3dom elements.

The x3dom canvas captures onclick events, so just defining a 3d event handler on an x3dom element does not work. Hence, clicking the red cube does nothing.

A workaround is to define an onclick handler which calls the 3d 'click' event handler with the event, as demonstrated by clicking on the blue sphere. Note that x3dom event members differ from d3's, so d3.mouse() function does not work.

Another solution, applied to the green cone, is to call addEventListener("click",...).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>d3 x3dom event test</title>
<script type="text/javascript" src="http://x3dom.org/x3dom/dist/x3dom.js"></script>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://www.x3dom.org/download/dev/x3dom.css"></link>
</head>
<body>
<div id="divX3d">
<X3D xmlns="http://www.web3d.org/specifications/x3d-namespace" id="x3d" x="0px" y="0px" width="500px" height="500px">
<Scene>
<Viewpoint centerOfRotation="0 0 0" position="0 0 15" orientation="0 1 0 0" />
<Background skyColor='.95 .95 .95' />
<Group>
<Transform translation='-3 0 0'>
<Shape>
<Appearance>
<Material diffuseColor="1 0 0" specularColor=".5 .5 .5" />
</Appearance>
<Box id="Red cube"/>
</Shape>
</Transform>
<Transform translation="0 0 0">
<Shape>
<Appearance>
<Material diffuseColor="0 0 1" specularColor=".5 .5 .5" />
</Appearance>
<Sphere id="Blue sphere"/>
</Shape>
</Transform>
<Transform translation="3 0 0">
<Shape>
<Appearance>
<Material diffuseColor="0 1 0" specularColor=".5 .5 .5" />
</Appearance>
<Cone id="Green cone"/>
</Shape>
</Transform>
<Transform translation="5 0 0">
<Billboard axisOfRotation="0 0 0">
<Shape>
<Text solid="true" string="Click Me">
</Text>
</Shape>
</Billboard>
</Transform>
</Group>
</Scene>
</X3D>
</div>
<script type="text/javascript">
document.onload = function()
{
// This will not work by itself because the x3d canvas captures onclick methods
d3.select('Box').on('click', showAlertWithEventCoordinate)
// This works. Note however that in the javascript string assigned to 'onclick', the function
// forwardClick must be globally, not locally scoped.
d3.select('Sphere').on('click', showAlertWithEventCoordinate)
d3.select('Sphere').attr('onclick', "forwardClick(event)")
// This works too.
d3.select('Cone').node().addEventListener('click', showAlertWithEventCoordinate)
d3.select('Text').node().addEventListener('click', showAlertWithEventCoordinate)
function showAlertWithEventCoordinate(event) {
var pagePt = invertMousePosition(event);
alert(d3.select(event.target).attr('id') + ' picked at:\n'
+ 'world coordinate (' + event.hitPnt + '),\n'
+ 'canvas coordinate (' + event.layerX + ', ' + event.layerY + '),\n'
+ 'page coordinate (' + pagePt.x + ', ' + pagePt.y + ')' )
}
}
// Call the 'click' handler with event. Note that event member variables differ from
// what d3 expects. In particular d3.mouse() will not work.
//
function forwardClick(event) {
d3.select(event.target).on('click')(event);
// Is possible to instead construct a new event with members that d3 requires? e.g.,
//var e=document.createEvent('mouseEvent');
//var screenX = 0, screenY = 0; // TODO: compute
//e.initMouseEvent('click', event.bubbles, event.cancelable, window, event.detail,
// screenX, screenY, event.layerX, event.layerY,
// event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, event.button, null);
//d3.select(event.target).node().dispatchEvent(e);
}
// inverse of coordinate transform defined by function mousePosition(evt) in x3dom.js
//
function invertMousePosition(evt)
{
var convertPoint = window.webkitConvertPointFromPageToNode;
var pageX = -1, pageY = -1;
if ( "getBoundingClientRect" in document.documentElement ) {
var elem = d3.select('#divX3d').node();
console.log('elem:', elem)
var box = elem.getBoundingClientRect();
var scrolleft = window.pageXOffset || document.body.scrollLeft;
var scrolltop = window.pageYOffset || document.body.scrollTop;
var paddingLeft = parseFloat(document.defaultView.getComputedStyle(elem, null).getPropertyValue('padding-left'));
var borderLeftWidth = parseFloat(document.defaultView.getComputedStyle(elem, null).getPropertyValue('border-left-width'));
var paddingTop = parseFloat(document.defaultView.getComputedStyle(elem, null).getPropertyValue('padding-top'));
var borderTopWidth = parseFloat(document.defaultView.getComputedStyle(elem, null).getPropertyValue('border-top-width'));
pageX = Math.round(evt.layerX + (box.left + paddingLeft + borderLeftWidth + scrolleft));
pageY = Math.round(evt.layerY + (box.top + paddingTop + borderTopWidth + scrolltop));
} else if (convertPoint) {
var pagePoint = convertPoint(evt.target, new WebKitPoint(0, 0));
x = Math.round(point.x);
y = Math.round(point.y);
} else {
x3dom.debug.logError('NO getBoundingClientRect, NO webkitConvertPointFromPageToNode');
}
return { x: pageX, y: pageY };
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta HTTP-EQUIV="REFRESH" content="0; url=./d3_x3dom_event_test.xhtml">
</head>
</html>
@coderextreme
Copy link

Can you show how to add event listeners to a d3,selectAll() that returns shapes. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment