Monday, July 7, 2014

HTML 5 Canvas Zoom

Pretty much since my first day at Motorola I have been working with HTML 5 canvases.  I have been mostly working on creating a charting framework from scratch because the existing frameworks don't perform well enough.

Without going into too much detail, one of the newer pieces of functionality that I added was the ability to zoom into a section of the chart by dragging your mouse over a given area.  JS Fiddle Link.  

The first challenge was to figure out where on the canvas the mouse event is happening.  All of the mouse events (move, down, etc) use the same event object so I created a helper function that would get the current coordinates from the current event object.
function getCursorPosition(e) {
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = e.target;
    do {
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while (currentElement = currentElement.offsetParent)
    canvasX = e.pageX - totalOffsetX;
    canvasY = e.pageY - totalOffsetY;
    return {
        x: canvasX,
        y: canvasY
    }
}
The crux here is to make sure to keep getting the offset of the each element because the parent might not be the window.  Another thing I ran into with the mouse events was since I was handling the mousedown and mouseup events I had to add a flag on mousemove to indicate whether or not if the mouse action was a click event or not.

The next piece of logic is the actual zoom function.

function zoom(point1, point2) {
    var canvas = document.getElementById('myCanvas');
    var translation = {
        x: point2.x,
        y: point2.y
    };
    var canvasMax = {
        x: point1.x,
        y: point1.y
    };
    if (point1.x < point2.x) {
        translation.x = point1.x;
        canvasMax.x = point2.x;
    }
    if (point1.y < point2.y) {
        translation.y = point1.y;
        canvasMax.y = point2.y;
    }
    currentTranslation.x += 1 / canvasScale.width * translation.x;
    currentTranslation.y += 1 / canvasScale.height * translation.y;
    canvasScale.width = canvasScale.width * canvas.width / (canvasMax.x - translation.x);
    canvasScale.height = canvasScale.height * canvas.height / (canvasMax.y - translation.y);
    drawPicture();
}

In he function I choose the upper left hand point of the rectangle as the points of the translation.  I then figure out what the position should be based on the current zoom.  Next we have to figure out the new scale based on the current scale, and the size of the rectangle that we selected.  Once we have generated the scale and translation we can just plug them in our paint function.

While this code gave me a good start on what I needed, the actual implementation for the charting functionality is a bit more complicated due to having to scale the numbers on the graph without actually scaling the axis canvas.  

Saturday, July 5, 2014

New Job At Motorola

I wanted to write a post about my new job at Motorola Solutions (the part not bought by Google/Lenovo), but I figured by waiting for about about a month into the new job I would have a better perspective and not have as many emotions about the transition (also I've been pretty lazy about it).  After being somewhere after 8 years and seeing it grow from 11 people to 100 it is hard not to have many emotions.  My new job title at Motorola Solutions is Sr. Software Engineer, but I am going to be a front end developer.  This alone is a pretty big change.  After being focused mostly on the .Net platform and full stack development most of my career, I am going to be doing mostly UI work in JavaScript and Java for some older front-ends.  There will also be a sort of a UX/UI component to this position which I am looking forward to as well.

I'll start off by talking about why I was looking to leave Sonoma Partners after 8 years.  Overall I will look fondly at my time there.  I have met a lot of really awesome people who I hope to keep in touch with and some that left before me that I already do.  I also got to do some things that I wouldn't have been able to do in other jobs like manage people, leadership stuff, and manage project teams.  While everyone has different priorities for what they look for in a job (upward mobility, security, salary, day to day, etc.), I would say the biggest things that I was looking for were the following: move away from the Microsoft stack, go back to more of an IC role, learn new skills, and do more interesting things to push my boundaries.  While these were the main factors, they weren't the only.  In the end my good days were outweighed by the bad and I needed to do something new and get a new perspective.

So far the new job is going really well and I don't have any regrets about the decision I have made.  I have learned a ton of new things since I have started, and already done some really cool things.  In one month I have picked up the following technologies and use them on a daily basis:  angular, node, bower, protobuf, yeoman, selenium, grunt, jasmine, web sockets, canvas, sass, and more.  I find myself being really engaged on a daily basis, have the day go by a ton quicker, and most importantly being excited about work that day.  Besides the actual work improvement I have also started to get into shape since they have an onsite gym there.  Since I have started there I have hit the gym every day (was able to watch the world cup :) ), or played ultimate frisbee.


I hope to start to get back to blogging more often.  I have some really interesting things that I have worked on that I hope to blog about.  I may also blog about the actual job hunting process which was interesting as well.  I probably won't be doing much more Ruby stuff for a while, but there will be plenty of new and interesting things to talk about as well.