Triggering responsive behavior when dynamically resizing amCharts 4 chart - javascript

The most recent version of amCharts (I'm using v4.7.8) includes a couple of mechanisms to allow for responsive chart designs. I'm trying to take advantage of the chart.responsive.rules feature, which allows for different chart property values based on the size of the chart (and/or inner chart elements).
At the same time, we've implemented a "zoom" feature on all of our charts. Each chart is wrapped in a "zoomable" container element, and the charts are styled to be 95% of the container width. When the "zoom" icon-button is clicked, the container is set to position: fixed; top: 3rem; right: 3rem; bottom: 3rem; left: 3rem;, mostly filling the screen.
The problem is that the chart just... doesn't seem to notice this. If I create the chart at the zoomed size, it uses the correct ruleset, but if I create the chart at a smaller size, then resize it to be large, it continues to use the "small" ruleset. I've tried calling chart.appear, chart.invalidate, and chart.deepInvalidate after resizing, but the result is always the same: the chart renders with whatever ruleset it was originally initialized with.
The one thing that makes me think that at least SOMETHING is happening (though mis-timed) is the fact that when I zoom in (so the chart is fullscreen) and then use the horizontal scrollbar, the scrollbar moves faster than my mouse cursor - almost as if it thinks it's smaller than it is. That holds up with my initial impressions. However, once I resize the chart BACK to being small, the scrollbar moves slower than my mouse cursor, as if it thinks the chart is BIGGER than it is.
This whole thing is all done with multiple LitElement web components, so it's difficult to provide a fiddle/codepen example, but if necessary I can mock up an example that should at least demonstrate the problem. I'm not sure if that would be necessary, as I suspect someone who knows what they're talking about would know the answer to this offhand, but if you think it'll help, let me know and I'll see what I can do.
Edit: I've found a workaround, but it's hardly ideal. I found that if I completely dispose of the existing chart on zoom in/out and completely recreate it at the new size, then it behaves the way I want, but it is SERIOUSLY processor intensive to recreate some of these charts. I'd still very much prefer to find a solution that can take advantage of the current chart and just recalculate its layout.

try using setTimeout(()=>{chart.responsive.enabled = false;chart.responsive.enabled = true; }) after resize

Turns out, the answer is that amCharts 4 does not support the actual properties I'm trying to change via the responsive rules. The properties in question are groupData and groupCount. Support tells me that the logic surrounding those features was considered too complex to support dynamic updates. I asked them to please reconsider that decision. We shall see if they do.
What I've done in the meantime to solve my problem is to create two charts, one configured for the larger size and one for the smaller size, and I just swap out which one is displayed when zooming in/out.

Related

How can I add a scroll bar on a chart from LighteningChart Library?m

I'm currently trying to add a horizontal scroll bar below x-axis to control data displayed along x-axis.
The chart that I'm using is the following link.
https://arction.com/lightningchart-js-interactive-examples/examples/lcjs-example-0904-3dSpectrogramBox.html?theme=lightNew&page-theme=light
[3d Box Series Spectogram]
Unfortunately, there is not much information I can find on the API documentation about adding a scroll bar.
The closest api is 'setScrollStrategy' API.
Thus, I've added the following code snippet.
this.chart.getDefaultAxisX().setScrollStrategy(AxisScrollStrategy.progressive)
But it didn't make any noticeable change..
If Anyone has similar experience to share with me to implement such functionality, I'd be grateful.
At least I can say that there is no built-in functionality for this kind of scroll bar in 3D.
Programmatically you can alter the Axis interval like this
chart3D.getDefaultAxisX().setInterval(20, 40, false, true)
However, this is probably what you are after, since this just affects the positioning and scaling of the data, the samples outside this interval are not clipped out.
Connecting some sort of slider component to this interval would be straightforward, whereas adding this slider inside the 3D view under the X axis sounds tricky.

How to programmatically zoom to Elements in D3 in responsive map?

I have an SVG which I have imported using d3.xml and I am trying to zoom in when I have clicked one of the ellipses in my SVG. This almost works, though I am missing some functionality of locating the elements when the size of the SVG changes. Here is the code I am using to zoom:
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity
.translate(widthContainer/2 , heightContainer/2)
.scale(2)
.translate(-d3.select(this).attr('cx'), -d3.select(this).attr('cy')),
d3.pointer(event, svg.node())
);
This works when the size of the browser window represents the size in which the svg was created, because the cx and cy values of the ellipses then can be used to locate them, though when I increase the size of the browser window this of course doesn't work anymore because the cx and cy values are now way off. How can I center and zoom to an element independent of the current context? I'm guessing there is a way to find out the current scale of the parent div and then calculate the translate parameters from there but I haven't found anything after a couple hours of trying.
I found a solution to my problem, my biggest error was assuming that to make my map responsive I would need to update my vars widthContainer and heightContainer (which are used to make calculations in my code for the zoom position etc.) with the current viewport width when the page is loaded and on resize. This introduced a bunch of very weird behavior and led to me spending hours on debugging that could have been avoided.
The solution to making a map with zoom features responsive is to have these two vars set to fixed values. If you are using an SVG that you are reading as xml with d3, then use the values that are set in the SVG's viewbox attribute, e.g. viewBox="0 0 657.58 344.67".
Then you can handle your container, where your SVG element is in, as usual in css and set your width to 100% or whatever you please, and the map should act responsively. I'm a total noob in d3 and JS so this behaviour didn't seem logical to me, especially because the documentation on d3's zoomIdentity is very poor. To regular d3 users this probably seems obvious but I hope this reaches fellow d3 beginners out there.

Pan and zoom on an "infinite" graph paper background in js

For a project I'm working on I would like to have a background that I can pan around indefinitely, zoom in and out of and position and move around elements on that background.
The closest example I can think of is this: https://www.desmos.com/calculator. Additionally I will position different elements on top of that grid and move them around. For that I plan to use React and that isn't going to be much of a problem. The main issue I have is how to build the said background so that it can check all my requirements. I'm able to draw a grid but for moving around and zooming in and out (such that all the elements "on top" of the grid also scale up and down) is proving challenging for me. I would also like it if it can be done without the use of any specific drawing libraries and just pure JS but i'm open to suggestions. Any help will be appreciated.
P.S. I'm looking for general guidelines to how I can achieve my goal. For example different technologies or methods and not concrete solutions. I apologise if the question is too vague or badly formatted as it's the first time I'm asking here.
Desmos uses canvas to draw the "infinite" grid. You can achieve this using something like three.js or konva.js. One drawback of canvas is that you cannot place HTML elements on the grid.
Edit: Using three JS, you can use the gridHelper function and set the rotation about the x-axis by Pi. This should give you a "2d" grid. However, I found gsap and the Draggable plugin were better suited for this.
https://codepen.io/osiv/pen/gOwxmvO
This is definitely a work-in-progress, but it gives the idea of what I am working for. Zooming is basically preventing the default wheel behavior and changing the background image size:
handleWheelEvent(e) {
e.preventDefault();
let el = document.getElementById("grid-container");
let currengBackgroundSize = this.getPixelStringAsInteger(getComputedStyle(el).backgroundSize);
if(e.deltaY < 0) {
// decrease size
} else {
// increase size
}
}

if i pre-render d3js charts on the server, how will their width/height be calculated?

I have a website which sends about 7 megs of json data to the client, where d3 (actually dimplejs) charts are rendered. The page is getting to be pretty slow and simply doesn't work in some browsers.
I'm thinking of rendering the svg in the server, instead of having the client browser do it. I've seen several references this technique. However, since labels, bar widths and so many elements depend the pixel height and width of the chart, and these dimensions are not known until client's browser renders the page, how do people handle such issues?
I'm not a web/front-end developer normally so I don't know if I'm missing something obvious or if my assumptions are wrong.
The simplest thing is to take the rendered <svg> and add a viewBox attribute to it. That allows you to specify how you want the browser to scale/stretch or crop the <svg> when it's placed inside a parent container (eg <div>).
Anything beyond that — like selectively scaling or repositioning text or rects or axes — can only be achieved the "hard" way; i.e. with code that has some awareness of the chart's semantics and programmatically alters certain svg attributes to react to container size.
Finally, and this is a long-shot: If you have full control of the output (I'm guessing your don't, since you're using dimple), you could attempt using a combination of absolute and percentage units to size and position things, as conceptually demonstrated here

OpenLayers features redraw only after mouse moveend

In this case I use Map control from OpenLayers 2.10. On map I have base layer
which is OpenLayers.Layer.OSM and OpenLayers.Layer.Vector with custom features. Now when I move map using mouse the features that weren't previously visible won't redraw until release of mouse button. I have noticed the same issue in all OpenLayers examples. Can anyone provide some kind of work around to change this behaviour? What I want to achieve is to draw features immediately after feature becomes visible or always draw all features (I work with small number of features so performance of map control isn't critical).
My current idea is to handle some specific events on map (like mouse move with click) and force features redraw.
Update
The SVG2 renderer was introduced in v2.11, and then immediately deprecated in v2.12 for reliability reasons (See this pull request). For OL >= 2.12, set the layer's ratio property to have it render all features within a wider area as a ratio of the screen size. The trade-off is performance, and if your user "throws" their map in some direction, they will fly past the features, but at that point they probably expect to have some rendering delays.
new OpenLayers.Layer.Vector("My Layer", {
ratio: 2
});
Original Answer
From http://lists.osgeo.org/pipermail/openlayers-dev/2011-March/007345.html :
the new OpenLayers.Renderer.SVG2 renderer does what you are requesting. It is available on trunk (and will be in 2.11). To use it, configure the renderers array for your OpenLayers.Layer.Vector like this:
new OpenLayers.Layer.Vector("My Layer", {
renderers: ["SVG2", "VML", "Canvas"]
});
Or set it on the prototype:
OpenLayers.Layer.Vector.renderers = ["SVG2", "VML", "Canvas"];
Note that VML (used in IE6,7,8) and Canvas (used on Android devices) behave like Renderer.SVG and don't draw features while panning.
With OpenLayer v6.4.3 you can set the following property of VectorLayer:
updateWhileAnimating boolean (defaults to false) When set to true, feature batches will be recreated during animations. This means that no vectors will be shown clipped, but the setting will have a performance impact for large amounts of vector data. When set to false, batches will be recreated when no animation is active.
updateWhileInteracting boolean (defaults to false) When set to true, feature batches will be recreated during interactions. See also updateWhileAnimating.
I don't have a solution, but made an observation. Looking at this example on Vector Behavior on the OL Examples website, if features are partially visible (i.e. placed on the border of the viewport), they remain partially hidden when dragged into full view. Only fully visible upon release of the mouse button. My point being that it seems to be a display issue more than a load issue, if that wasn't apparent already...
Will keep an eye on the question, curious to the answer. :-)
Just in case anyone stumbles across this question (as I did) OpenLayers 2.11 resolves this issue. I tested it on my web application and it now redraws vector features instantly, whereas with an older version of OL installed it would do what was written above. Something I had never noticed before either so nice one for spotting it!
Here are the release notes.
http://trac.osgeo.org/openlayers/wiki/Release/2.11/Notes
This sort of shows it in action. Best example I could find I'm afraid :P
http://openlayers.org/dev/examples/rotate-features.html

Categories

Resources