Methods to Move DOM Element - javascript

I am programming a Javascript game as an exercise in objects and AJAX. It involves movement of wessels around a nautical-themed grid. Although the wessels are in an array of objects, I need to manipulate their graphical representation, their sprites. At the moment I have chosen, from a DOM perspective, to use 'img' elements within 'td' elements.
From a UI continuity perspective, which method of programmatically moving the elements with Javascript would be recommended:
(a) deleting inner html of 'from' cell (td element) and rewriting inner html of 'to' cell,
(b) clone the img node (sprite), delete the original node from its parent, and append it to the 'to' cell, or
(c) using positioning relative to the table element for the sprite, ignoring the td's alltogether (although their background [color] represents the ocean depth).

I would definitely stick with moving the sprite from cell to cell rather than using relative positioning to the table. My reasoning is that the table cell size might vary from browser to browser (given variances in the way padding, margins etc. are rendered - especially with annoying IE) and calculating the exact location to position the sprite in order for it to line up within a given cell might get complicated.
That narrows it down to (a) or (b) for your options. Here let's eliminate option (a), as deleting the HTML from inside is not a clean way of manipulating the DOM. I like the idea of storing the node in an object, and then appending it to the 'to' cell, and then deleting the original node, which your option (b) suggests. This way, you are still dealing with the high-level 'objects' and not the low-level 'text' needlessly. You don't need to mess with the text - for such an application, that would be the dirty 'hackish' way of doing it if you didn't know about the DOM manipulation functions JavaScript already offers.
My answer is (b). However, if you absolutely require speed - though for your game I don't know if you'll really need the extra boost - you may consider option (a). A few sources, such as http://www.quirksmode.org/dom/innerhtml.html contend that the DOM manipulation methods are generally slower than using innerHTML. But that's the general rule with everything. The lower the level you go, the faster you can make your code. The higher the level, the easier to understand and conceptualize the code is, and in my opinion, since speed will not make a huge difference in this case, keep it neat and go with (b).

There's no need to clone the img node, delete the old one and append the clone. Just append the img node to the receiving td. It will automatically be removed from the td it was previously in. Simple, effective and fast.

Related

What kind of performance optimization is done when assigning a new value to the innerHTML attribute

I have a DOM element (let's call it #mywriting) which contains a bigger HTML subtree (a long sequence of paragraph elements). I have to update the content of #mywriting regularly (but only small things will change, the majority of the content remains unchanged).
I wonder what is the smartest way to do this. I see two options:
In my application code I find out which child elements of #mywriting has been changed and I only update the changed child elements.
I just update the innerHTML attribute of #mywriting with the new content.
Is it worth to develop the logic of approach one to find out the changed child nodes or will the browser perform this kind of optimization when I apply approach two?
No, the browser doesn't do such optimisation. When you reassign innerHTML, it will throw away the old contents, parse the HTML, and place the new elements in the DOM.
Doing a diff to only replace (or rather, update) the parts that need an update can be worth a lot, and is done with great success in rendering libraries that employ a so-called virtual DOM.
However, they're doing that diff on an element data structure, not an HTML string. Parsing that to find out which elements changed is going to be horribly inefficient. Don't use HTML strings. (If you're already sold on them, you might as well just use innerHTML).
Without concdering the overhead of calculating which child elements has to be updated option 1 seems to be much faster (at least in chrome), according to this simple benchmark:
https://jsbench.github.io/#6d174b84a69b037c059b6a234bb5bcd0

Should I detach elements from the DOM while I apply many styles to them?

I'm concerned about performance and best practices.
So I'm building graphical UI and learned that I shouldn't call jQuery.append() a gazillion times when creating many small elements. So I got that covered by document.createDocumentFragment(). I'm adding elements to that, then once done, I insert the fragment to the DOM (with appendChild),
Then, in another pass I calculate where each element should be. Everything is absolutely positioned and will receive x and y values via CSS transform. Unfortunately, for these calculations I need the elements in the DOM since some of them contan random length text, and I need to measure widht/height. Otherwise I would perform step 3 on the document fragment directly, before it's even inserted into the DOM.
In the final pass I apply the calculated styles over everything with jQuery.css() (will likely replace with setAttribute instead of jQuery) as part of a loop (many calls to that, unfortunately - every element has different x/y). Should I detach the container that holds all my elements while I apply the styles, then reattach it to the DOM?
Due to lack of interest I decided to test it myself. Pulling an element of 700+ articles (15000 nodes), applying various CSS on the majority of them, then putting the element back into the page was actually slower by 50%. Let the browser do its job by only showing the results of changed attributes when Layout is needed.
I read the advice somewhere to remove the element from the DOM while working on it. While this could be true when appending elements to it, this does not hold true for style manipulations.

Determine effective z-index (vertical stack position) of each element in the DOM?

I'm writing a tool that uses javascript to do something like convert an HTML document into SVG.
That requires knowing which elements could overlap other elements, and thus the overall z-index stacking order of the entire document.
So I want to assign each element in the source page a number such that if I rearranged all the elements to overlap one another, the number would reflect their position in that stack, with 1 being the top (or bottom), 2 being the next, etc.
This is of course influenced by z-index values but is not directly related to them.
I know there's a way to do this myself using careful DOM traversal and sorting, but it would be tricky.
Is there an existing approach that's easier?
I can use any necessary library, though understanding how to do it in vanillaJS would be helpful.
Thanks!
Edit: as I look into rolling my own, the CSS entry on painting order is at https://www.w3.org/TR/CSS21/zindex.html, with a healthy discussion at http://vanseodesign.com/css/css-stack-z-index/
Untested idea:
Massage the entire DOM tree with CSS transform: translate() styles until all visible elements are stacked in a way that their bounding boxes overlap at a particular point, e.g. at the top left corner of the document.
obtain the top-most element with document document.elementFromPoint
style the element with pointer-events:none;, this excludes it from the element retrieval
goto 2
That should give you the total ordering.
Well, honestly, this is a hard one to answer you say:
This is of course influenced by z-index values but is not directly related to them.
But, if I simply answer the question in the title:
Determine effective z-index (vertical stack position) of each element in the DOM?
If you know the id (or name) of the elements then it is relatively easy to get the zIndex as you can get the z-index of any dom element with:
document.getElementById('someID').style.zIndex;
For any additional answers, you will need to narrow down your requirements.

Is it always necessary for overlay elements to be located in end of HTML body?

I have noticed that in javascript frameworks elements such as dialogs, tooltips and alerts mostly appear at end of body.
I'm making my own implementation of these elements and trying to make it failproof. I'm repeating some techniques like using transparent iframe to overlay embeded objects in old browsers, and so on.
What restrictions could I face if I place my dialog/tooltip somewhere deep inside of the DOM tree with {position: fixed}? I'm afraid if there are some dangers to this approach, because big frameworks never use it.
I want to support IE8+.
Aside from z-ordering that is a very valid point made by Teemu, another major consideration in JS frameworks is speed of execution / speed of lookup.
The DOM in JS terms is one large object. The deeper into an object javascript needs to go to get what it's being asked for, the less performant the script gets, take a look at this answer.
Therefore it makes sense to keep everything that is probably going to be cloned or deep copied at a sensible nesting level and in the correct z-order. That happens to be toward the end of the body and usually wrapped by at most one containing element.
There may be other reasons but the depth / nesting sprung to mind as a consideration I'd take into account.
Short answer - very few techniques like this are "always necessary". JavaScript can easily remove items from their natural position in the DOM and relocate them at will.
Long answer - I don't think approaching this from a JavaScript first angle is correct. Look at it in terms of where the content belongs naturally within the hierarchy of the rest of the DOM.
For example, if you are talking about a modal dialog, then the chrome (the container elements) usually do not belong within the rest of the DOM - they exist only to contain and provide modal overlay functionality for the content within. This chrome does not participate in the outline of the DOM and the rest of the content. In that case, unless you are able to load them separately via ajax or embed the chrome HTML within the JavaScript, then the closest you will come to removing them from the main DOM is to append them to the bottom of the main DOM content. Note that this disregards the upcoming TEMPLATE element (http://www.html5rocks.com/en/tutorials/webcomponents/template/) which is designed for just this purpose.
However, the content of your dialog might very well belong within the main content of the DOM - either as an element, or as an attribute (i.e. title or data-) to an associated element. This would especially be true for tooltip text.

Should I use transform instead of redraw?

I have several charts I do redraw everytime I zoom/pann using d3 brushes.
But, when I have tons of rendered elements, redrawing starts to be a little bit slow.
Instead of redrawing all elements everytime I move my brush, I was wondering whether or not it's feasible to transform (translate) the already drawn elements, and only redraw whenever I need to update my data.
I think it would increase my visualization performance a lot whenever panning to right/left, wouldn't it ?
Any insights ?
In general, the less you touch the DOM the better your performance will be. The details are browser and platform specific, but in general this is the pecking order of performance at a very high level (ordered from most expensive to least):
Creating and removing DOM elements.
Modifying properties of existing DOM elements.
In memory JavaScript (that is, not involving DOM at all... e.g. Array iteration).
So if you can get the result you want by simply modifying a targeted subset of existing elements with a transform attribute, I would guess you will be much better off.
Of course, it's impossible to say anything with certainty without seeing the actual code and use case.

Categories

Resources