Following on from yesterdays post, now I know how to measure the framerate of my application, I need to simulate the dragging behavior of the user on maps.ovi.com.
One can do this in something like selenium or webdriver, but i’d like to do mine in javascript, which actually turns out to be not so difficult. All we need to do, is create a drag path, generate some HTML events and fire them on the correct object. For this example I will use the jQuery draggable page.
First things first, we need to get some key points. What does the drag path look like? Where do I want my draggable item to go?
For the HTML mouse events as a minimum for dragging, I need to know 4 variables, screenX, screenY and clientX and clientY. Lets write a quick jQuery (for this article I am being a lazy javascripter) function that allows me to click on the screen and output the mousemove data to the console and then end.
$(document).mousedown(function() {
$(document).mousemove(function(event) {
console.log("["+event.screenX
+","+event.screenY
+","+event.clientX
+","+event.clientY
+"],");
});
$(document).mouseup(function() {
$(document).unbind("mousemove");
});
});

The output I get from that gives me a set of arrays of points where my drag animation must go to:
[[749,437,749,320],
[750,437,750,320],
[756,437,756,320],
[763,436,763,319],
[777,434,777,317]...
So first lets declare that in another array:
var dragPoints = [
[[749,437,749,320],
[750,437,750,320],
[756,437,756,320],
[763,436,763,319],
[777,434,777,317]...
];
Ok, so what next. Well, now we need a function to fire the html events.
var dispatchHTMLMouseEvent = function(mouseEventType, coords, target) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(mouseEventType, true, true, window, 0,
coords[0], coords[1], coords[2], coords[3], false, false, false, false, 0, null);
target.dispatchEvent(evt);
};
This function takes 3 arguments: the event type, which for us, is mousedown, mousemove and mouseup, the coordinates to move to and the element to target when firing the event.
So finally we need the timer function to periodically fire the events.
var sendMouseDrag = function(element, dragPoints) {
dispatchHTMLMouseEvent("mousemove", dragPoints[i], element);
i++;
if(i < dragPoints.length-1) {
setTimeout(function() {
sendMouseDrag(element, dragPoints);
}, 10);
} else {
dispatchHTMLMouseEvent("mouseup", dragPoints[i], element);
}
};
And then the code that calls it all:
var i = 1;
var element = document.getElementById("draggable");
dispatchHTMLMouseEvent("mousedown", dragPoints[0], element);
sendMouseDrag(element, dragPoints);
And that’s it! Now if you plug that code into the console of chrome or firefox, on that page, then you will see the draggable box magically fly itself around. If you want the full executable source code it’s below.
var dragPoints = [
[749,437,749,320],
[750,437,750,320],
[756,437,756,320],
[763,436,763,319],
[777,434,777,317],
[792,431,792,314],
[807,429,807,312],
[833,423,833,306],
[854,419,854,302],
[875,414,875,297],
[893,409,893,292],
[904,407,904,290],
[921,405,921,288],
[937,402,937,285],
[954,402,954,285],
[972,402,972,285],
[983,402,983,285],
[997,405,997,288],
[1006,406,1006,289],
[1020,408,1020,291],
[1028,409,1028,292],
[1031,409,1031,292],
[1033,410,1033,293],
[1034,416,1034,299],
[1035,426,1035,309],
[1038,439,1038,322],
[1039,451,1039,334],
[1040,461,1040,344],
[1040,468,1040,351],
[1040,477,1040,360],
[1040,485,1040,368],
[1040,491,1040,374],
[1040,495,1040,378],
[1039,501,1039,384],
[1036,507,1036,390],
[1032,513,1032,396],
[1028,519,1028,402],
[1023,526,1023,409],
[1016,532,1016,415],
[1009,537,1009,420],
[999,545,999,428],
[989,553,989,436],
[982,558,982,441],
[973,566,973,449],
[963,574,963,457],
[955,579,955,462],
[948,583,948,466],
[938,588,938,471],
[935,589,935,472],
[931,591,931,474],
[929,592,929,475],
[928,592,928,475],
[927,592,927,475],
[927,594,927,477],
[927,595,927,478],
[925,595,925,478],
[925,596,925,479],
[921,603,921,486],
[915,610,915,493],
[913,610,913,493],
[908,610,908,493],
[903,611,903,494],
[896,613,896,496],
[882,618,882,501],
[873,621,873,504],
[861,625,861,508],
[849,629,849,512],
[837,631,837,514],
[819,633,819,516],
[805,635,805,518],
[777,637,777,520],
[754,638,754,521],
[731,638,731,521],
[709,638,709,521],
[696,638,696,521],
[682,636,682,519],
[675,634,675,517],
[670,633,670,516],
[666,632,666,515],
[662,631,662,514],
[660,629,660,512],
[659,627,659,510],
[658,625,658,508],
[658,624,658,507],
[658,622,658,505],
[658,621,658,504],
[658,620,658,503],
[658,618,658,501],
[657,616,657,499],
[657,614,657,497],
[656,611,656,494],
[656,609,656,492],
[655,606,655,489],
[655,603,655,486],
[655,601,655,484],
[655,599,655,482],
[655,597,655,480],
[655,595,655,478],
[655,592,655,475],
[655,590,655,473],
[655,585,655,468],
[657,582,657,465],
[658,578,658,461],
[660,575,660,458],
[662,572,662,455],
[663,570,663,453],
[664,569,664,452],
[665,567,665,450],
[667,565,667,448],
[670,562,670,445],
[674,559,674,442],
[678,555,678,438],
[683,549,683,432],
[688,543,688,426],
[692,540,692,423],
[696,536,696,419],
[701,532,701,415],
[704,530,704,413],
[707,529,707,412],
[709,529,709,412],
[710,529,710,412],
[713,529,713,412],
[716,529,716,412],
[719,529,719,412],
[726,530,726,413],
[732,530,732,413],
[740,531,740,414],
[751,532,751,415],
[759,533,759,416],
[766,533,766,416],
[774,533,774,416],
[778,533,778,416],
[781,533,781,416],
[783,533,783,416],
[785,533,785,416],
[786,533,786,416],
[787,533,787,416],
[788,533,788,416],
[789,533,789,416],
[790,533,790,416],
[792,531,792,414],
[795,529,795,412],
[798,527,798,410],
[801,525,801,408],
[803,524,803,407],
[805,523,805,406],
[806,523,806,406],
[808,521,808,404],
[809,520,809,403],
[811,519,811,402],
[813,518,813,401],
[814,517,814,400],
[816,516,816,399],
[817,516,817,399],
[819,515,819,398],
[822,512,822,395],
[825,511,825,394],
[827,509,827,392],
[829,508,829,391],
[831,508,831,391],
[832,508,832,391],
[832,509,832,392]
];
var sendMouseDrag = function(element, dragPoints) {
dispatchHTMLMouseEvent("mousemove", dragPoints[i], element);
i++;
if(i < dragPoints.length-1) {
setTimeout(function() {
sendMouseDrag(element, dragPoints);
}, 10);
} else {
dispatchHTMLMouseEvent("mouseup", dragPoints[i], element);
}
};
var dispatchHTMLMouseEvent = function(mouseEventType, coords, target) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(mouseEventType, true, true, window, 0,
coords[0], coords[1], coords[2], coords[3], false, false, false, false, 0, null);
target.dispatchEvent(evt);
};
var i = 1;
var element = document.getElementById("draggable");
dispatchHTMLMouseEvent("mousedown", dragPoints[0], element);
sendMouseDrag(element, dragPoints);
Where to put your CSS hacks - conditioning your conditionals.
Wednesday, March 3rd, 2010I’ve had/heard/seen this argument many times on blog after blog. So I thought it would be a useful blog post to highlight to upsides and down sides to each argument.
Conditional Comments
Conditional commenting is the practice of putting code in special comments in your HTML document that get executed only in specified IE browers, it usually looks something like this:
Pro’s
Con’s
Inline CSS Hacks
Inline CSS hacks are where you write *hacked* attribute, property pairs in your CSS using combinations of ascii characters to take advantage of bugs in different CSS parsers, looking something like this:
Pro’s
Con’s
Ultimately it’s a preference thing and you can spin these pro’s and con’s either way to support your chosen method of development, but once it’s been chosen all developers need to stick with it. I think the important thing is that everyone needs to be vigilant that both are used with extreme caution and care as a last last resort in the CSS.
I see two useful things that could be created to follow this up to create the desired behaviour:
Personally I opt of the conditional method, but that’s because I have a bizarre obsession with automated validation of CSS. See CSSOrder.
Tags: automated testing, best practice, conditional comments, CSS, hacks
Posted in javascript/css | No Comments »