Tag Archives: css

Resizing, Moving, Snapping Windows with JS & CSS

Imagine you have a widget written in CSS, how would you add some code so it would get some ability to resize itself? The behaviour is so ingrained with our present windows managers or GUI that its quite easily taken for granted. While, it’s quite possible that there might be some plugins or framework which does this, but the challenge I gave myself was to do it in vanilla javascript, and to handle the resizing without adding more divs to the dom. (I thought adding additional divs to use as a draggable bar is pretty common).

Past work
Which reminds me, I wanted this similar behaviour for ThreeInspector, and while hacking the idea, I went with the approach of using the CSS3 resize property for the widget. The unfortunate thing was that min-width and min-height was broken for a really long time in webkit (the bug was filed long ago in 2011, and I’m not entirely sure what the status is now). Being bitten by the bug, I become hesitant every time I think of the css3 resize approach.

Screenshot 2014-11-15 09.31.08

JS Resizing
So, for own my challenge, I start with a single purple div and add a bit of js.

resize1

Done within 100 lines of code, this turns out not to be difficult. The trick is adding a mousemouse handler to document (not document.body, as it fails in FF), and calculate when the mouse is within a margin from the edge of the div. Another reason to always add handlers to document instead of a target div is when you need mouse events even if the cursor moves out of the defined boundary. This is useful for dragging and resizing behaviours, and especially in resizing, you wouldn’t want to waste time hunting bugs because the events and divs resizing are not in sync.

Also for my first time, I made extensive use of document’s event.clientX, event.clientY, together with div.getBoundingClientRect(). It does get me almost everything I need to deal for handling positions, size and events, although it’s a possibility that getBoundClientRect might not be as performant as getting offsets.

What’s nice about using JS vs a pure CSS3-resize is that you get to decide which sides of the div you wish to allow resizing. I went for the 4 sides and 4 corners, and the fun just started, so next I started implementing moving.

Moving
Handling basic moving / dragging just needs a few more lines of code. Pseduocode: Mousedown, check that cursor isn’t on the edge (reserved for resizing), store where the cursor and the bounds of the box is. Mousemove, update the box’s position.

Still simple, so let’s try the next challenge of snapping the box to the edges.

Snapping
Despite the bad things Mac might say to PC, one thing that is pretty good since Windows 7 is its snap feature. On my mac I use Spectacle, which is the replacement for Window’s windows docking management. I took inspiration of this feature in Windows and implemented this with JS and CSS.

resize2

One sweet detail in Snap is the way a translucent window shows where the window would dock or snap into place before you release your mouse. So in my implementation, I used an additional div with a slight transparency one z-index lower than the div I’m dragging. Css animation transition property was used for a more organic experience.

There’s slight deviations to the actual Aero’s experience that Windows users may notice. In Windows, dragging a window to the top snaps the window full screen, while dragging the window to the bottom of the screen has no effect. In my implementation, the window can be docked to the upper half or lower half, or the fullscreen if the window get dragged further beyond the edge of the screen. In Windows, a vertical half is only possible with the keyboard shortcut.

Another difference is that Windows snaps happen when the cursor touch the edge of the screen. My implementation snaps when the div’s edge touches the browser window edge. I thought this might be a better, because users typically use less movements for non-operating-system gesutures. One last difference is that Windows’ implementation sends tiny ripples at the point the cursor touches the screen. Ripples are nice (I noticed they are an element used frequently in Material Design), but I’ll leave it to be an exercise for another time.

As after thoughts, I added touch support and limit mousemove updates to requestAnimationFrame. Here’s the demo, feel free to try and check out the code on codepen.

See the Pen Resize, Drag, Snap by zz85 (@zz85) on CodePen.

Virtual Rendering The Million Items Roundup

Some days I’m unproductive, some other days I explore, discover random stuff too quickly that I easily forget stuff I do. So in this post, I intent to round up the experiment started in my previous post of “Virtual Rendering 1,000,000 Items Efficiently”.


The Canvas Approach

In the last post, I showed how one could implement a virtual scroll bar and the display of 1,000,000 row items in a virtual scrollpane quickly. That was done by creating dom elements when they get scrolled in the view and removing them and they get scrolled out of view. In this post, I would talk about how the HTML5 Canvas element could be used instead for rendering the contents. This would not be about which approach is superior, as both have its pros and cons, but I’ll just note down aloud some thoughts I observed in Canvas implementation and the differences of both approaches.


Can you spot the visual differences?

Since this prototype hack was created quickly on Chrome, it has probably been tested in these browsers, still different versions, differenent computers and different OS typically give different results.

– most computers typically redraw the scrollpanes less than 20ms (and under 10ms most of the time), which I think is a satisfying result.
– both seems to be performing on par in the above comparison jsdo.it fiddle.
– The Canvas approach is typically much faster over the DOM approach when the scroll viewport is huge – eg. 1600×900 as the DOM approach seems to slow down more considerably in the bigger view port.
– There are certain things much simpler to implement in DOM vs in Canvas. For example, dashed borders could be written in a line of css, but the Canvas approach require some custom coding esp when dashed line drawing hasn’t been supported in the Canvas API.
– In implementing custom code to mimic the dashed borders, the Canvas rendering slows down to.
– At first, I was making these expensive calls, because paint calls were made after every dash stroke (eg. lineTo for a 3px line, stroke, move to a 3px gap)

	//After every row
	var ww = 0;
	while(ww < w ) {
		ctx.beginPath();
		ctx.moveTo(ww,~~item.y + 0.5);
		ctx.lineTo(ww+3,~~item.y + 0.5);
		ctx.closePath();
		ctx.stroke();
		ww+=6;
	}

– after I discovered it would be more efficient doing it in this manner.

	//After every row
	var ww = 0;
	ctx.beginPath();
	while(ww < w ) {
		ctx.moveTo(ww,~~item.y + 0.5);
		ctx.lineTo(ww+3,~~item.y + 0.5);
		ww+=6;
	}
	ctx.closePath();
	ctx.stroke();

– Here stroke calls are batched, rendering speeds up, but falls behind the browser native css rendering. An exception is that Chrome on windows seems to match both the CSS and custom rendering speeds pretty close.
– In canvas, an advantage might be that drawing custom objects would be one step easier, compared to creating new dom objects and placing custom objects in there.
– Some rendering done in canvas could be quicker than using complex css rules which the browser might requires reflow calculations.
– Using a canvas approach, one might find sub-pixels or anti-aliasing issues. For drawing a 1 pixel line cleanly on Canvas might have to resort to tricks like ~~(y_position) + 0.5;

Its interesting making things work in both approach, but as seen above, there are too many variables and this is not intended to be performance comparison test, but a documentation of observations. Depending on one’s use case, either approach might fit the developer better.

Working with Canvas brings many possibilities but brings many challenges at the same time. While there were many interesting projects that used Canvas for rendering, some didn’t have good endings.

Examples
1. Google Wave – I believed they used canvas for rendering the custom elements, scrollbars, cursors, etc . Those who have used Google wave might have already waved it goodbye.
2. Mozilla Thunderhead – This was the custom library used to developed Mozilla Bespin, a realtime collaborative editing and development platform. Many of its UI components were Canvas drawn – esp for handling its text editor, showing multiple cursors while multiple users were editing collaboratively. Sadly, the developers left mozilla, Bespin became Skywriter, and now uses the ACE library (more DOM based) which is also used in the cloud9 IDE.
3. Blossom – An RIA library which attempts to use HTML5 canvas for rendering. This is another library spin off from the Sproutecore library, and while this library seems to have some potential, it also seems to be at its infancy.
4. xgui.js – Certainly it doesn’t mean a gloomy end for custom Canvas UI components, and I think xgui.js, a handly controls gui , is a good example that useful and innovative libraries can be built on the 2D Canvas.

So, whether is DOM, CSS, Canvas, there are practical use cases and interesting possibilities. I’ll pause this experimentation at this point, but when I have the need for some huge data and virtual scrolling, I’ll be back.

Sweeter As The Years Go By

Here’s something that has kept me a little occupied over the past weeks.

Howmean.com Main Page

To find out, head over to http://howmean.com. This site belongs to the couple to be, Caleb and How Mean. And no, rather than its perceived adjective “how mean!”, I hope one experience some sweetness visiting the site.

There are several talented people behind the making of this site. Graphics and concept were designed by Grace Wong, and the web design was done by Meng Lung of Gold Coast Web Design. My little contributions would be some subjective augmentations to the site and one might make intelligent guesses to what I did by spotting non-traditional elements on the site. For those who aren’t guessing, here’s a list

+ Mouse over the dandelions near the footer, and one may see little particles floating away. On most modern browsers except IE, these particles are drawn with html 5 canvas elements. In unsupported browsers, 1 pixel rendering with css are used instead.
+ Meant to be an easter egg, rolling the mouse wheel renders lighter dandelions particles around the screen.
+ Ajax calls are used for navigation when possible to prevent disruption of the background music
+ To support browsers not running flash (the iPhones and Androids mainly!), flash objects degrade gracefully
+ To degrade the photo gallery for non flash clients, the xml used by the flash slideshow player is parsed and rendered with jquery.
Howmean.com on the android
+ A small widget (which dates back to my legendary ORD count down wallpaper) is used to display the time till or from the wedding date in the credit page.

Of course all these would not be present if not for the weds-to-be.

So this’s my 1st post of the new year, and its a great reminder to reflect whether each passing day gets sweeter. A blessed new year for you readers!