Highstock Navigator plugin doesn't render in firefox - javascript

I'm having an issue with a little plugin I wrote for the Highstock Navigator. It's meant to just style the navigator outside the bounds of what their built in options allow. The plugin looks like this:
(function (H) {
H.wrap(H.Scroller.prototype, 'init', function (proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
//console.log("drawing scroller: ", this);
});
H.wrap(H.Scroller.prototype, 'drawHandle', function (proceed) {
//console.log("drawing handle: ", this);
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
H.each(this.handles, function (handle,index) {
var element = handle.element
var offsetX = -8
var centerPoint = 0;
if(index == 0) {
///topleft//// ///topright//// ///middleright//// ///bottomright//// ///bottomleft/// ////middleleft
$(element).html('<path fill="#333333" d="M '+(7+offsetX)+' 0 L '+(15+offsetX)+' 0 L '+(8+offsetX)+' 9.5 L'+(15+offsetX)+' 20 L '+(7+offsetX)+' 20 L'+(0+offsetX)+' 9.5" stroke-width="0"></path>')
// element.innerHTML = '<polygon fill="#333333" points="'+(7+offsetX)+',0 '+(15+offsetX)+',0 '+(8+offsetX)+',9.5 '+(15+offsetX)+',20 '+(7+offsetX)+',20 '+(0+offsetX)+',9.5"/>'
}
else {
offsetX = -14 ///topleft//// ///topright//// ///middleright//// ///bottomright//// ///bottomleft/// ////middleleft
$(element).html('<path fill="#333333" d="M '+(7+offsetX)+' 0 L '+(15+offsetX)+' 0 L '+(22+offsetX)+' 9.5 L '+(15+offsetX)+' 20 L '+(7+offsetX)+' 20 L '+(14+offsetX)+' 9.5" stroke-width="0"></path>')
//element.innerHTML = '<polygon fill="#333333" points="'+(7+offsetX)+',0 '+(15+offsetX)+',0 '+(22+offsetX)+',9.5 '+(15+offsetX)+',20 '+(7+offsetX)+',20 '+(14+offsetX)+',9.5"/>'
}
$(element).bind('mouseover',function() {
$(this).find('path').attr('fill', '#50504e');
})
$(element).bind('mouseout',function() {
$(this).find('path').attr('fill', '#333333');
})
$(element).attr('transform', "translate("+handle.translateX+','+(handle.translateY-2)+')')
//$(element).addClass('custom_scroll_handle');
})
});
}(Highcharts));
This plugin works fine in Chrome, it draws the navigator as a solid box with two arrows for the left and right handles. It looks like this:
However in Firefox, the same svg block fails to render. I've verified that the actual svg looks identical in the code inspector, and there are no apparent style additions in firefox that would cause it not to display. I've also tried copying and pasting the default handle svg into the plugin to see if the issue was with the way the svg coordinates were set up, but even the default handle svg fails when drawn by the plugin in firefox. When i hover over the left or right handle path element in firefox it shows it as being positioned in the upper right corner of the svg stage with a height and width of 0. Here is a picture of the same page in firefox:
Does anyone have any insight as to what might be causing it not to appear?

Ok I found the problem in case anyone else runs into this issue.
The issue was with the way the svg was being appended by the plugin. Because i was using either innerHTML or jquery.html() to append the content Firefox was apparently treating it like an unstyled custom html tag rather than an svg element. Using the parseSVG method with appendChild from this answer jquery's append not working with svg element? fixed the issue in firefox.
Here is the working plugin:
(function (H) {
H.wrap(H.Scroller.prototype, 'init', function (proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
//console.log("drawing scroller: ", this);
});
H.wrap(H.Scroller.prototype, 'drawHandle', function (proceed) {
//console.log("drawing handle: ", this);
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
H.each(this.handles, function (handle,index) {
var element = handle.element
var offsetX = -8
var centerPoint = 0;
if(index == 0) {
element.innerHTML = '' ///topleft//// ///topright//// ///middleright//// ///bottomright//// ///bottomleft/// ////middleleft
element.appendChild(parseSVG('<path fill="#333333" d="M '+(7+offsetX)+' 0 L '+(15+offsetX)+' 0 L '+(8+offsetX)+' 10 L'+(15+offsetX)+' 20 L '+(7+offsetX)+' 20 L'+(0+offsetX)+' 10" stroke-width="0"></path>'))
}
else {
element.innerHTML = ''
offsetX = -14 ///topleft//// ///topright//// ///middleright//// ///bottomright//// ///bottomleft/// ////middleleft
element.appendChild(parseSVG('<path fill="#333333" d="M '+(7+offsetX)+' 0 L '+(15+offsetX)+' 0 L '+(22+offsetX)+' 10 L '+(15+offsetX)+' 20 L '+(7+offsetX)+' 20 L '+(14+offsetX)+' 10" stroke-width="0"></path>'))
}
$(element).bind('mouseover',function() {
$(this).find('path').attr('fill', '#50504e');
})
$(element).bind('mouseout',function() {
$(this).find('path').attr('fill', '#333333');
})
$(element).attr('transform', "translate("+handle.translateX+','+(handle.translateY-2)+')')
})
});
}(Highcharts));

Related

Animate svg paths on hover in all browsers

Im new to SVG and paths on HTML5 and I have some issues with an animation im trying to do:
In the next link its a preview of what im trying to do: http://jsfiddle.net/fxwL68hr/1/
The problem is: only works on Google Chrome and Firefox Developer Edition.
In summary: When I hover the SVG, all the triangles do an animation. However triangles 3 and 4 actually change the paths coords to create a bigger triangle. How I can animate this change of coords in those triangles without using css d: path() so it can work in all (or at least the majority of) browsers.
The next link is a : CodePen with my solution
I'm not very sure you will like it.
In the HTML I'm adding a defs element with the target path for triangles 3 & 4:
<svg id="svg" class="svg_bg" width="50%" viewBox="0 0 100 75">
<defs>
<path id="t3Target" d="M 100 75 L 0 0 L 0 75 Z" />
<path id="t4Target" d="M 100 75 L 100 0 L 0 0 Z" />
</defs>
<path id="triangle1" class="triangle1" d="M 17.5 28.5 L 55 75 L 81 75 Z"></path>
<path id="triangle2" class="triangle2" d="M 36.5 8 L 54.5 75 L 87 75 Z"></path>
<path id="triangle3" class="triangle3" d="M 110 -25 L 38 75 L 77 75 Z"></path>
<path id="triangle4" class="triangle4" d="M 49 75 L 84 75 L 120 41.5 Z"></path>
</svg>
For the triangles 3 & 4 I'm using JavaScript.
let rid = null;
let shapesRy = [];
class Shape{
constructor(path_a,path_b,morphingPath){
this.target = getArgsRy(path_a);
this.vals = getArgsRy(path_b);
this.morphingPath = morphingPath;
this.memory = [];
for(let i=0; i < this.vals.length; i++){
this.memory[i] = [];
this.memory[i][0] = this.target[i].slice();
this.memory[i][1] = this.vals[i].slice();
this.updatePath();
}
}
updateValues() {
for(let i = 0;i < this.memory.length; i++){
let dist_x = this.target[i][1] - this.vals[i][1];
let vel_x = dist_x/10;
this.vals[i][1] += vel_x;
let dist_y = this.target[i][2] - this.vals[i][2];
let vel_y = dist_y/10;
this.vals[i][2] += vel_y;
}
let dist_x = this.target[0][1] - this.vals[0][1];
if (Math.abs(dist_x) < .01) {
if(rid){window.cancelAnimationFrame(rid);
rid = null;
}
}
}
updatePath() {
let d=`M${this.vals[0][1]},${this.vals[0][2]}`;
for(let i = 1;i < this.vals.length -1; i++){
d += `L${this.vals[i][1]},${this.vals[i][2]}`
}
d +="Z";
this.morphingPath.setAttributeNS(null, "d", d);
}
}
shapesRy.push(new Shape(t3Target,triangle3,triangle3));
shapesRy.push(new Shape(t4Target,triangle4,triangle4));
function Frame() {
rid = window.requestAnimationFrame(Frame);
shapesRy.map((s) => {
s.updateValues();
s.updatePath();
})
}
svg.addEventListener(
"mouseover",
function() {
if (rid) {
window.cancelAnimationFrame(rid);
rid = null;
}
shapesRy.map((s) => {
for(let i = 0;i < s.memory.length; i++){
s.memory[i].reverse();
s.target[i] = s.memory[i][1].slice();
}
})
Frame();
},
false
);
svg.addEventListener(
"mouseout",
eAction,
false
);
function eAction(){
{
if (rid) {
window.cancelAnimationFrame(rid);
rid = null;
}
shapesRy.map((s) => {
for(let i = 0;i < s.memory.length; i++){
s.memory[i].reverse();
s.target[i] = s.memory[i][1].slice();
}
})
Frame();
}
}
function getArgsRy(path) {
let d = path.getAttribute("d").replace(/\r?\n|\r/g, ""); //remove breaklines
if (d.charAt(0) == "m") {
d = "M" + d.slice(1);
}
let argsRX = /(?=[a-zA-Z])/;
let args = d.split(argsRX);
let ArgsRy = [];
args.map(arg => {
let argRy = arg
.slice(1)
.replace(/\-/g, " -")
.split(/[ ,]+/);
argRy.map((p, i) => {
if (p == "") {
argRy.splice(i, 1);
}
});
for (let i = 0; i < argRy.length; i++) {
argRy[i] = parseFloat(argRy[i]);
}
argRy.unshift(arg[0]);
ArgsRy.push(argRy);
});
return ArgsRy;
}
This is a blog post where I'm explaining the code: Morphing in SVG - first steps
There is an additional problem with the CSS animation for the triangles 1 & 2 (your CSS) since CSS transforms on SVG elements are extremely buggy.
You may want to read this article: Transforms on SVG Elements
Alternatively you may want to use JavaScript for all 4 triangles.
There always is a finite transform from one triangle to another. The math behind that is non-trivial, but with a bit of fiddling around with the grafical transformation tool for example of Inkscape, you can find it. That way, I got to the following:
triangle 3: matrix(0, 1.92308, -1,0.634615, 75, -120.673)
triangle 4: matrix(0, -2.14286, 2.98507, -2.30277, -123.881, 352.708)
Addendum: I have done the appropriate math now. I've even described it already in the context of another answer: Draw circle svg orthogonal projections. While in that answer, three points were used to describe a square that then underwent an orthogonal projection, the mathematical content is just this: take three separate points (not in one line) as source and another three points (same constraints) as target, and the function generate() quoted in that answer will give you the transform matrix.
The animation has to run between the neutral matrix(1, 0, 0, 1, 0, 0) and the one above as a transform property. See it working in this fiddle.
Downside: according to Can I Use, IE does not support CSS transforms on SVG elements, but that was also true for your first two triangles.
In addition, why don't you use a CSS transition instead of an animation? You go from one state to a second and back. Describe the base state and the hover state and transition: transform 1s ease does the rest.

Obtaining rendered borders of a crooked svg-object

I need to know whether an svg-object is adjacent to another one or not. Therefore I need to get its borders.
Those objects can be a rect or a path. This is fairly easy when they are straight, but I don't know how to do this when they're curved or crooked.
An example of what I mean can be found here or a short example here:
<svg id="mysvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 200 512 512">
<path d="m 223.40414,282.21605 35.53211,-3.88909 0,-18.73833 -19.79899,-0.17678 c -5.83251,7.19542 -10.70707,15.0451 -15.73312,22.8042 z" id="pB"></path>
</svg>
If I use the Box corners, I create a virtual straight rectangular, which adjacent objects are not equal to the adjacents of the rendered object.
How can I do that?
The Snap library offers some nice utilities for your problem. Your question does not define what "adjacent" should really mean. Here is a function that sets a threshold for the maximal distance between to paths:
var threshold = 1;
function isAdjacent (id1, id2) {
var s = Snap("#mysvg");
var first = s.select('#' + id1);
var second = s.select('#' + id2);
var len = first.getTotalLength(first);
var p1, p2;
for (var at = 0; at <= len; at += threshold) {
p1 = first.getPointAtLength(at);
if ( Snap.closestPoint(second, p1.x, p1.y).distance <= threshold) {
return true;
}
}
return false;
}
JsFiddle

Animating multiple SVG paths on scroll with canvas

I'm trying to extend the JS from this Codrops article:
https://tympanus.net/Development/StorytellingMap/
I'm attempting to animate multiple SVG lines to "split" the SVG path. To simulate it I created multiple paths overlaid on one another. The pertinent SVG code is as such (for reference, example):
<g id="trail-path" display="none">
<path display="inline" d="M1058.75,817.41a159.76,159.76,0,0,0,11.15-18.24c1.16-2.23,2.31-4.72,1.75-7.17-.64-2.81-3.29-4.65-5.8-6.06a77.9,77.9,0,0,0-29.34-9.42c-4.94-.55-10-.63-14.73-2.09s-9-4.25-13.21-7Q982,749.77,956.19,731.08c-5.52-4-6.81-10.78-7.54-17.56s-1.07-14-5.05-19.56c-6.48-9-20-10.06-27.26-18.47-6.31-7.34-6.07-18.23-4-27.69.83-3.83,1.91-7.67,1.73-11.59-.33-7-4.6-13.1-8.71-18.77-5.63-7.76-11.87-16-21-18.91-6-1.91-10.76-6.9-15-11.53s-8.06-9.68-12.69-13.93c-6-5.48-13.25-9.54-18.62-15.63-6.34-7.2-9.47-16.58-13-25.51-.94-2.38-2.11-5-4.46-6-10.45-4.59-20.41-11.33-27.17-20.53-3.37-4.58-5.63-9.85-7.87-15.07-2.61-6.1-5.27-12.39-5.4-19-.17-8.82,4.17-17.39,3.26-26.16-.5-4.79-2.53-9.26-4.53-13.64l-15.15-33.08
M1058.75,817.41a159.76,159.76,0,0,0,11.15-18.24c1.16-2.23,2.31-4.72,1.75-7.17-.64-2.81-3.29-4.65-5.8-6.06a77.9,77.9,0,0,0-29.34-9.42c-4.94-.55-10-.63-14.73-2.09s-9-4.25-13.21-7Q982,749.77,956.19,731.08c-5.52-4-6.81-10.78-7.54-17.56s-1.07-14-5.05-19.56c-6.48-9-20-10.06-27.26-18.47-6.31-7.34-6.07-18.23-4-27.69,2.67-12.28-.83-25.88,6.72-36.71,3.74-5.37,9.15-9.33,13.36-14.35,11.71-14,12.1-36.16.89-50.53-7.54-9.65-19.06-15.39-27.38-24.38-5.24-5.66-9.07-12.45-12.85-19.17" fill="none" stroke="red" stroke-miterlimit="10" stroke-width="5"/>
</g>
I'm 90% sure that the code I should primarily be focusing on is here. I just need a way to iterate it for each path component. I'm looking at "t.trailPath" and the path contained within "#trail-path." I initially tried multiple grouped path elements and iterating them but it didn't work (and rightfully so since I realized that was the wrong approach).
(0, p.default)(this.props.mapSrc).then(function(e) {
t.mapSVG = Array.from((new DOMParser).parseFromString(e, "image/svg+xml").childNodes).filter(function(t) {
var e = t.tagName;
return "undefined" == typeof e ? !1 : "svg" == e.toLowerCase()
})[0], t.cameraPath = t.mapSVG.querySelector("#camera-path path"), t.trailPath = t.mapSVG.querySelector("#trail-path path"), t.points = Array.from(t.mapSVG.querySelectorAll("#points circle")).map(function(e) {
var i = parseFloat(e.getAttribute("cx")),
r = parseFloat(e.getAttribute("cy"));
return {
x: i,
y: r,
length: d.getLengthAtPoint(t.trailPath, {
x: i,
y: r
}),
label: (e.getAttribute("id") || "").replace(/_/g, " "),
color: e.getAttribute("fill") || "black",
radius: parseFloat(e.getAttribute("r"))
}
}).sort(function(t, e) {
return t.length - e.length
}), t.cameraSubdivisions = d.subdividePath(t.cameraPath, t.cameraSubdivisionSize, !0), t.cameraLength = d.getLength(t.cameraPath), t.cameraBreakpoints = t.setupBreakpoints(t.cameraPath), t.trailSubdivisions = d.subdividePath(t.trailPath, t.trailSubdivisionSize, !0), t.trailBreakpoints = t.setupBreakpoints(t.trailPath), t.trailLength = d.getLength(t.trailPath), (0, l.loadImage)(t.props.mapSrc).then(function(e) {
t.mapWidth = e.width, t.mapHeight = e.height, 0 == t.mapHeight && (t.mapWidth = 2040, t.mapHeight = 1178), t.map = b(t.mapScales).map(function(i, r) {
var n = 1 + (t.mapMaxScale - 1) / (t.mapScales - 1) * r,
s = (0, h.default)(t.mapWidth * n, t.mapHeight * n),
a = s.getContext("2d", {
alpha: !1
});
return a.fillStyle = "#a8cecf", a.fillRect(0, 0, t.mapWidth * n, t.mapHeight * n), a.drawImage(e, 0, 0, t.mapWidth * n, t.mapHeight * n), {
map: s,
scale: n
}
}), t.mapBuffer = (0, h.default)(1, 1), t.mapBufferCtx = t.mapBuffer.getContext("2d", {
alpha: !1
}), t.updateMapBufferSize(), t.mapBufferCtx.fillStyle = "#a8cecf", t.mapBufferCtx.fillRect(0, 0, t.mapBufferSize.x, t.mapBufferSize.y), t.mapBufferOffset = {
x: 0,
y: 0
}, t.mapBufferScale = t.mapScale, t.ready = !0, document.addEventListener("scroll", t.onScroll.bind(t)), t.onScroll()
})
})
The site for reference. It's not updated to include attempts as obviously it breaks it. It focuses on Giarratana alongside Chiaramonte as it should, but no dice on getting the path traced or highlighted.
https://adrianatwell.github.io/bond-of-strangers/code/html/
The code is here for reference. It's 6.5K lines though so it wouldn't be much help.
https://github.com/adrianatwell/bond-of-strangers/blob/master/code/html/assets/js/app.js
I'm way in over my head with this script it seems, I've been tooling around with it and Google for the past 72 hours. Haha.

How to achieve progressive animate for svg line

I am trying to achieve progressive animation for svg line path. I am using path like as M L M L ..... .. do to this problem the animation will not work perfectly.
Here is my code,
var distancePerPoint = 1;
var drawFPS = 100;
var orig = document.querySelector('path'), length, timer;
var a = document.querySelector('svg');
a.addEventListener('mouseover',startDrawingPath,false);
a.addEventListener('mouseout', stopDrawingPath, false);
function startDrawingPath(){
length = 0;
orig.style.stroke = 'green';
timer = setInterval(increaseLength,600/drawFPS);
}
function increaseLength(a){
var pathLength = orig.getTotalLength();
length += distancePerPoint;
orig.setAttribute("stroke-dasharray", length + ' ,2000');
if (length >= pathLength) clearInterval(timer);
}
function stopDrawingPath(){
clearInterval(timer);
orig.style.stroke = '';
}
<svg id="asd" width="706" height="600">
<path stroke="red" stroke-width="2" d="M 0 239.34 L 105.75 299.25 M 105.75 299.25 L 211.5 279.28 M 211.5 279.28 L 317.25 259.31 M 317.25 259.31 L 423 259.46 M 423 259.46 L 528.75 99.55 M 528.75 99.55 L 634.5 199.40000000000003 " />
</svg>
If I add line path as M L L L L mean it will work perfectly what I expected.. but I need this same behavior in M L M L M L...
how to achieve... without using css
Do you mean that you want the subpaths to animate one after the other, instead of all at the same time?
The answer is you can't. The dash pattern begins/resets at the start of each subpath (each move 'M'). There is no way around this other than:
Fixing the path by removing the unnecessary 'M' commands, or
splitting the lines into separate paths, then triggering them one after another.
You're trying to animate the line using the 'stroke-dasharray' property. but that applies to each line primitive separately, and not the whole path. As you can see in the result. Every M component in the path will reset the internal stroke length values in the svg path renderer.
A more straight forward solution would be to animate the path data itself. Or just add path elements in the animation frame.

Highcharts Is there a way to resize plotbands after zoom?

I'm doing something like this to resize my plotband when the chart renders:
var _Chart = new Highcharts.Chart( options, function ( chart ) {
for ( var i = 0; i < chart.xAxis[0].plotLinesAndBands.length; i++ ) {
var band = chart.xAxis[0].plotLinesAndBands[i].svgElem, path = band.d.split(' ');
var bottomString = chart.xAxis[0].plotLinesAndBands[i].options.iMBottom + '';
var topString = chart.xAxis[0].plotLinesAndBands[i].options.iMTop + '';
path[2] = bottomString;
path[path.length - 1] = bottomString;
path[5] = topString;
path[7] = topString;
band.attr('d', path);
}
});
That allows me to set the top and bottom of a chart's Y-Axis. We're displaying several Y-Axis in the same chart with some padding between them and each axis may have it's own plotbands. I don't want those to spill over into the other Axis since they look like smaller individual charts. I'm also changing the hover formatter to display a tooltip for these plotbands if a point within the band is hovered over.
The issue I'm having is that if you click, drag to zoom the plotbands revert back to the state where they bands go through the entire chart. I wrote some code to remove them and add them back in, but it seems like I'd need a callback on the addPlotBand function to change the SVG array before it's actually added and rendered. I've tried re-adding it then trying to redraw it, that didn't work.
Is there a way for me to adjust the SVG element when adding a new plotband so that I can alter the SVG element?
Edit:
Here's some more info. I tried using the selection event to delete all bands then call redraw, which calls a custom redraw event to put the SVG values back. Here's how that looks (the select event is first kinda crude but it works):
SelectChart: function (chart) {
var plotBandData = new Array();
for (var i = 0; i < chart.xAxis[0].plotLinesAndBands.length; i++) {
var band = chart.xAxis[0].plotLinesAndBands[i].svgElem, path = band.d.split(' ');
var plotBand = chart.xAxis[0].plotLinesAndBands[i];
//get all the plot band info so we can recreate them after resize
var pbd = {
from: plotBand.options.from,
to: plotBand.options.to,
id: plotBand.options.id,
bottom: plotBand.options.iMBottom,
top: plotBand.options.iMTop,
color: plotBand.options.color
};
plotBandData.push(pbd);
}
//delete all existing plot bands:
for (var i = 0; i < plotBandData.length; i++) {
chart.xAxis[0].removePlotBand(plotBandData[i].id);
}
for (var i = 0; i < plotBandData.length; i++) {
//Add plotband back in
chart.xAxis[0].addPlotBand({
from: plotBandData[i].from,
to: plotBandData[i].to,
color: plotBandData[i].color,
id: plotBandData[i].id,
iMBottom: plotBandData[i].bottom,
iMTop: plotBandData[i].top
});
}
},
Then my redraw event looks something like this:
RedrawChart: function (chart){
//SVG Code:
for (var i = 0; i < chart.xAxis[0].plotLinesAndBands.length; i++) {
var band = chart.xAxis[0].plotLinesAndBands[i].svgElem, path = band.d.split(' ');
var bottomString = chart.xAxis[0].plotLinesAndBands[i].options.iMBottom + '';
var topString = chart.xAxis[0].plotLinesAndBands[i].options.iMTop + '';
path[2] = bottomString;
path[path.length - 1] = bottomString;
/*JH: this is interesting, the second value for top is typically in the 8th spot in the array
However, before it's rendered the two right most "L"s are removed shifting everything to the left.
an example would be:
After render:
M 525 100 L 525 100 L 525 50 L 707 50 L 707 100
Before render (which is the state it's in here):
M 525 100 L 525 100 L 525 50 707 50 707 100
So you can see that the 8th value after render which is second top is shifted over one space.
The last value which is the second bottom is shifted over 2 spaces.
*/
path[5] = topString;
path[7] = topString;
band.attr('d', path);
}
},
My SVG values are correct at the end of redraw, however, the heights still get rendered to the full height of the chart.
Edit:
Now if I zoom in only the plotbands visible in the zoom stretch to the full height of the chart. Upon resetting zoom all all other plotbands are the correct size. Then if I select an area of the chart with no bands then click zoom out all the chart bands are correct. Seems to have something to do with only visible plotbands on select.
Here's what worked:
I created a new method that fires on the X-Axis afterSetExtremes() method (I suppose if you were doing this on the y-Axis you'd fire it there instead). I basically just took the code from the above two methods and stuck it all in there. Here's the code that fires off from the xAxis.afterSetExtremes() event:
AfterChartSetExteremes: function (xAxis) {
var plotBandData = new Array();
for (var i = 0; i < xAxis.plotLinesAndBands.length; i++) {
//get all the plot band info so we can recreate them after resize
var plotBand = xAxis.plotLinesAndBands[i];
var pbd = {
from: plotBand.options.from,
to: plotBand.options.to,
id: plotBand.options.id,
bottom: plotBand.options.iMBottom,
top: plotBand.options.iMTop,
color: plotBand.options.color
};
plotBandData.push(pbd);
}
//delete all existing plot bands:
for (var x = 0; x < plotBandData.length; x++) {
xAxis.removePlotBand(plotBandData[x].id);
}
for (var y = 0; y < plotBandData.length; y++) {
//Add plotband back in
xAxis.addPlotBand({
from: plotBandData[y].from,
to: plotBandData[y].to,
color: plotBandData[y].color,
id: plotBandData[y].id,
iMBottom: plotBandData[y].bottom,
iMTop: plotBandData[y].top
});
}
$.each(xAxis.plotLinesAndBands, function (i, pband) {
if (this.svgElem !== undefined) {
var band = this.svgElem;
path = band.d.split(' ');
var bottomString = this.options.iMBottom + '';
var topString = this.options.iMTop + '';
path[2] = bottomString;
path[path.length - 1] = bottomString;
/*JH: this is interesting, the second value for top is typically in the 8th spot in the array
However, before it's rendered the two right most "L"s are removed shifting everything to the left.
an example would be:
After render:
M 525 100 L 525 100 L 525 50 L 707 50 L 707 100
Before render (which is the state it's in here):
M 525 100 L 525 100 L 525 50 707 50 707 100
So you can see that the 8th value after render which is second top is shifted over one space.
The last value which is the second bottom is shifted over 2 spaces.
*/
path[5] = topString;
path[7] = topString;
this.svgElem.attr('d', path);
}
});
//Need to reset formatter here?
}
The xAxis from the function is "this" from the afterSetExtremes event, so I just passed it through like this:
function() {return PureSense.Clifford.IM.Charting.AfterChartSetExteremes(this);}
that works. All the plotbands get resized after zooming in or resetting zoom. I actually walked all the way through the highcharts code with the methods in my initial post. I saw that the SVG values did get set correctly and held all the way through. Something happens outside of redraw though and I couldn't catch it.
I do know it happens though because if you look at my comments the "d" array is two items short of the SVG element on the page (if you view it with F12 dev tools). The afterSetExtreme event fires after redraw and after the zoom happens. I think writing those values during redraw causes them to get overwritten when the zoom finalizes.
Hope that's helpful to someone else.

Categories

Resources