Why sometime scrollTop/scrollLeft not writable? - javascript

I'm using dhtmlx Gantt Chart UI component which have task list and graphical chart. Task list and graphical chart are contained in two separate div element which synchronized for parallel scrolling. By scrolling the chart area, task list is automatically scrolled resulting the task row position matches the Gantt line position.
Inspecting the component source code, I found the sync is implemented by the following code :
this.oData.onscroll = function() {
self.panelTime.scrollLeft = this.scrollLeft;
self.panelNames.scrollTop = this.scrollTop;
};
All HTML markup in the UI control are generated dynamically by JavaScript. All is working well except it takes too long time to render 800-ish task list.
To improve rendering time, I decide to built my own server side rendering module to generate the HTML markup identical with that originally generated client side. This markup is fetched from client side using ordinary jquery $.get() and injected to page using $(el).html(). Then I put the necessary event handler as the original client side version.
The problem now is parallel scrolling doesn't work. I could capture the scroll event on the chart area, but I couldn't set the scrollTop property of the task list area. I test in firebug to manually force the scrollTop property, but the value didn't change. It seems that scrollTop property is read-only.
Is there any explanation for this ?

You can't scroll down below the bottom (or past the right) of the element's contents. If the element has overflow: visible (the default), or is at least as large as its contents, then both scroll properties will be stuck at 0. Similarly, even if there is something hidden to scroll into view, then you won't be able to scroll past the end; if you set the scrollTop or scrollLeft to a larger value than makes sense, it will decrease to the largest value that makes sense.
My guess is in your case you're trying to scroll the div before its content is loaded, and it's refusing to scroll because there isn't anything to scroll into view.

Related

Test simulated html element width with javascript

Use case
I want to detect if html tables get too wide, and if so, I want to flip the table header cells to become vertical (e.g. with writing-mode: vertical-lr;).
I want to update this on resize: If the viewport gets bigger, the text in the cells might become horizontal again.
The flip condition is whether the original table with horizontal labels would be wider than its container.
Question
How do I determine the width a table would have with horizontal labels, without changing the table itself?
Thoughts
My current idea would be to make an invisible copy of the table with horizontal labels, and use it as a "sensor". But I am afraid this will pollute the DOM and cause side effects somewhere. Also I would need to keep this copy updated all the time.
Is there a "best practice" or a known pattern to solve this problem?
It is actually quite simple:
We can change the css on the table during the script run. Once we query a property like element.width, this will cause a reflow during the script execution, but it won't cause a repaint. So this means we can do the test without the need for a cloned DOM element, and without visible changes.
See https://developers.google.com/speed/docs/insights/browser-reflow

Web Element "Grows" After Being Scrolled into View

I recently posted a question on SO where I observed a different element height and width being returned by Chrome Inspector tool vs. Selenium WebDriver when calling element.getSize().getWidth() and element.getSize().getHeight(). With Chrome Inspector I get dimensions of w = 979, h = 1961. With Selenium I get dimensions of 979 and 1461 respectively.
Code I'm using to retrieve element:
String URL = "https://www.amazon.com/dp/B07G9RZD14";
driver.navigate().to(URL);
String XPath = ".//*[#id='aplus']/div";
WebElement element = driver.findElement(By.xpath(XPath));
I've repeated this experiment several times and each time I got the same result. Some have suggested that I was changing the size of the browser however this is not the case. I always performed my test in maximized mode from start to finish.
I did experiment further and it turn out that if I inspect the element with Chrome Inspector immediately after the page loads (without scrolling down to element so it is put into view) the dimensions returned matches the dimensions returned by Selenium (1461). It is only after I scroll element into view that the element height "grows" to 1961.
When I inspect the HTML in the above URL I see a script executing an "expander" function.
I have three question.
1) How does this function work? (Looks like it's using Javascript)
2) Is it possible to get the real dimensions of the said element (1961) without scrolling element into view? Or it would be required to scroll into view element with this kind of function attached?
3) If it is required to scroll such elements into view, is it possible for us to know which elements have this function and need to be scrolled into view or I would have to scroll all elements into view as a precaution?
Thanks
Amazon product pages are quite complex, and include a lot of lazy-loaded images and other elements. It's likely that your element is growing in size because new content is being rendered lazily as you scroll down the page.
To answer your question, you will certainly need to scroll down the entire page and allow all elements to finish rendering if you want completely accurate dimensions.

In Chrome, SVG elements constructed too far off-screen do not render when brought into view

I am creating a web-site that drives content for a large 2D area off a CMS, so I have a system that runs on a timer, examines the part of the area that is currently on-screen, and loads content that is close enough to the view area that it might soon come into view.
This all seems to work quite nicely, apart from one small glitch.
Some of my content is SVG elements created procedurally via JS (the load mechanism feeds data from the CMS into JS functions, which create the using document.createElementNS and insert it into a div in the correct absolute position).
This content appears fine if is on-screen at the time it is loaded (this happens when the page is initially loaded).
And it also appears if it loaded while an animation is moving the visible area (animation is used to follow paths across the 2D space).
HOWEVER, if I am manually moving the visible area (which I have implemented via click+drag) then the SVG elements are added to the document tree, but when they come into view they do not render.
If I do something to "nudge" the renderer, such as hiding an unrelated element via DevTools, or resizing the window slightly, then they appear.
I am thinking this may be a bug in Chrome? e.g. where it has initially decided the elements need not be drawn and does not reprocess correctly when that needs reconsideration? Or maybe I am missing something, I am only semi-experienced in manipulating HTML documents via JS (but after a quick look I do not see the same behaviour in firefox...)
I am moving the visible area by changing the (left, top) of a parent element (I do not want to use scrolling for that as the size of the 2D space is not defined in advance...)
Otherwise, is there some way I could trick the browser into recalculating what should be drawn? I was wondering about having a small transparent element on screen that I show and hide on a timer, although a workaround that prevents the problem in the first place would be preferable...
Thanks for any advice!
Ian
p.s. I cannot instantly produce demo code for this as the code-base is moderately large, but I will spend time to make a simpler example if that proves necessary...

Horizontal scrolling to a specific element

I made the following component in Angular.
It's basically a kind of tree component.
Please note the following:
The tree has several branches.
It consists of nodes in alternating colors.
And the selected node is marked by a blue dot.
The tree does not fit the screen, that's why there's a horizontal scroll bar.
Each node has a unique id (i.e. <div id="...">)
This component works fine, however. I don't know how to add the following feature:
When the focus changes, (in other words, a different node becomes active), I want this node always to be visible on the screen. That means that the webbrowser has to scroll to the left or right, automatically whenever a node is selected. It has to scroll or jump until the specific <div> is visible.
How can this be done using javascript or typescript ?
EDIT:
I want to use this javascript is the base for better navigation tools.
button to move back and forth in the tree
button to jump 10 nodes to left/right.
button to jump to the back.
button to jump to the start.
Also when a new node is added to the back of the tree, right now the user has to scroll all the way to the right, manually. I want it to be visible immediatly, automatically.
Those are my real objectives :)
If the only scroll mechanism you need is the automatic one, I would avoid trying to use the browser's built in scrolling mechanism altogether and just use ElementRef of the node to get its horizontal position relative to its container, and then apply a CSS 'translate' to move it as needed. It will be much easier this way to have it look "nice" with CSS transitions and animations. But if you would still need manual scroll behavior (i.e, the user still needs to be able to scroll with a scrollbar) youd have to program a scrollbar directive / solution as well, which may end up being more effort than the problem demands.
This page has a sort of hacky workaround for horizontal scrolling - https://css-tricks.com/pure-css-horizontal-scrolling/
The problem for me in the past with 'scrollTop' and 'scrollLeft' is you can't apply transitions to those attributes, so they end up looking very jerky without implementing custom easing functions in javascript.

angularJS routing - Finding element positions on page

I'm trying to do some translating of existing code functionality to angular and routing.
Currently, I have it such that mouse position tracks relative distance to some divs (each div counts as a 'color,' the closer the mouse, the brighter that color).
I found how to track mouse position in angular, now I'm having trouble getting element coordinates - specifically since the elements are part of the routed pages. I'm not sure if I need to use getBoundingClientRect and getElementBy[id/class/etc] to select the elements or if there is some other way that angular routing requires or would function better with.
edit - clarification: I can select elements on the routed page just fine... after the routed page loads. I'm scouring the documentation for a one-time ng-event that can find the element after the route loads. Currently, I can find things on page load (but before route loads), or I can try to bind it to something like mousemove (i.e. constantly re-evaluating the position of non-moving parts).

Categories