In Highcharts there is a nice feature to zoom and pane the area. But in order to use panning - it should be in combination with a shift key as mentioned in the example here. Is there a way to display a scroll bar on zoom in instead of panning?
You can use renderer and make your custom scrollbar with it:
http://api.highcharts.com/highcharts#Renderer.rect
You can make two rectangles, one for your scrollbar background and second for your scrolling button.
You can change their attributes using attr():
http://api.highcharts.com/highcharts#Element.attr
chart.renderer.rect(0, height - 60, width, 20)
.attr({
fill: '#666',
zIndex: 3,
visibility: 'hidden'
}).addClass('scroll')
.add();
You can use afterSetExtremes event and inside its callback function you can connect visibility of your scrollbar with visibility of your reset zoom button:
http://api.highcharts.com/highcharts#xAxis.events.afterSetExtremes
You need to calculate width of your scrollbar and x position. You can do it by simple math proportion of your axis min and max and width of your chart. For example you can set your width inside redraw event callback function:
redraw: function() {
var chart = this;
this.xAxis[0].displayBtn ? ($('.scrollBar').show() && $('.scroll').show()) : ($('.scrollBar').hide() && $('.scroll').hide())
width = chart.chartWidth;
newWidth = width * (max - min) / (oldMax - oldMin);
$('.scroll').attr({
width: width
});
$('.scrollBar').attr({
width: newWidth,
x: width * min / oldMax,
});
}
You need to add mousedown and mousemove events to your scrollbar. You can do it using jQuery. Inside mousemove event you need to recalculate x position of your scroll button basing on your mouse position:
$('.scrollBar').on('mousedown', function() {
var mousePos;
$(this).bind('mousemove', function(e) {
$(this).attr({
x: e.clientX + 70,
})
chart.xAxis[0].setExtremes(min - ((mousePos || e.clientX) - e.clientX) * oldMax / width, max - ((mousePos || e.clientX) - e.clientX) * oldMax / width, true, false);
mousePos = e.clientX;
});
})
Here you can see an example how it work:
http://jsfiddle.net/LnneuLoy/8/
Kind regards.
Related
I am working on konva js. I am working on an app that lets users create custom shapes. and after creation they can resize it by mouse, connect two shapes by a line. So far the feature drawing custom shape and their connecting by line is complete.
Now I want to show dots around the custom shape when user hovers on the custom shape just like this
P.S I have seen this from https://app.diagrams.net/. I want to build drawing app same like it.If someone can navigate me to the resources from where I can build drawing app like this, it would be really helpful.
You can use mouseenter and mouseleave events to show/hide anchors for the shape.
It is up to you to choose how to implement anchors. It can be custom anchors like in https://konvajs.org/docs/sandbox/Modify_Curves_with_Anchor_Points.htm or it can be Konva.Transformer https://konvajs.org/docs/select_and_transform/Basic_demo.html.
On mouseenter you can show anchors. Hiding anchors is a bit tricker for the demo I will hide anchors when mouse is too far away from the shape. We can't use mouseleave as is here, because it will trigger hide when we simply hover Konva.Transformer.
In the demo, try to hover the circle.
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
const layer = new Konva.Layer();
stage.add(layer);
const shape = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 50,
fill: 'green'
});
layer.add(shape);
const tr = new Konva.Transformer();
layer.add(tr);
// from https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
function getDistance(rect, p) {
var dx = Math.max(rect.x - p.x, 0, p.x - (rect.x + rect.width));
var dy = Math.max(rect.y - p.y, 0, p.y - (rect.y + rect.height));
return Math.sqrt(dx*dx + dy*dy);
}
shape.on('mouseenter', () => {
tr.nodes([shape]);
});
stage.on('mousemove', () => {
if (!tr.nodes().length) {
return;
}
if (tr.isTransforming()) {
return;
}
const rect = shape.getClientRect();
const dist = getDistance(rect, stage.getPointerPosition());
if (dist > 60) {
tr.nodes([]);
}
});
layer.draw();
<script src="https://unpkg.com/konva#^8/konva.min.js"></script>
<div id="container"></div>
I have a chart with some indicators below it. Each indicator area consists
of a svg renderer button. so when I use resize property to drag and resize
the panes, the series resized perfectly but the button remains in its same
position, Can we move the button with the resizer?
Here I created a sample link to regenerate
https://jsfiddle.net/q0ybpnvx/2/
Any help will be appreciated. I am having great trouble. Thank you
You can add and position the custom button in render event:
chart: {
events: {
render: function() {
var chart = this;
if (chart.customBtn) {
chart.customBtn.attr({
y: chart.yAxis[1].top,
});
} else {
chart.customBtn = chart.renderer.button(
'sometext',
5,
chart.yAxis[1].top,
function() {
console.log('some task')
}).add()
}
}
}
},
Live demo: https://jsfiddle.net/BlackLabel/b7vq4ecy/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr
I was able to do something by manually changing the x/y attributes of my svgRenderer label, the same should apply to buttons.
I'm in angular and have a listener for screen resizing:
Also Note that you can change the entire SVGRenderer label with the attr.text property.
this.chart = Highcharts.chart(.....);
// I used a helper method to create the label
this.chart.myLabel = this.labelCreationHelperMethod(this.chart, data);
this.windowEventService.resize$.subscribe(dimensions => {
if(dimensions.x < 500) { //this would be your charts resize breakpoint
// here I was using a specific chart series property to tell where to put my x coordinate,
// you can traverse through the chart object to find a similar number,
// or just use a hardcoded number
this.chart.myLabel.attr({ y: 15, x: this.chart.series[0].points[0].plotX + 20 });
} else {
this.chart.myLabel.attr({ y: 100, x: this.chart.series[0].points[0].plotX + 50 });
}
}
//Returns the label object that we keep a reference to in the chart object.
labelCreationHelperMethod() {
const y = screen.width > 500 ? 100 : 15;
const x = screen.width > 500 ? this.chart.series[0].points[0].plotX + 50 :
this.chart.series[0].points[0].plotX + 20
// your label
const label = `<div style="color: blue"...> My Label Stuff</div>`
return chart.renderer.label(label, x, y, 'callout', offset + chart.plotLeft, chart.plotTop + 80, true)
.attr({
fill: '#e8e8e8',
padding: 15,
r: 5,
zIndex: 6
})
.add();
}
I have a column chart that has yAxis labels inside the plot area. DEMO: http://jsfiddle.net/o4abatfo/
This is how I have set up the labels:
yAxis: {
labels: {
align: 'left',
x: 5,
y: -3
}
}
The problem is that the leftmost column is so near the plot area edge that labels are overlapping it. Is there a way to adjust the plot area padding so that the columns would start a bit further on the right?
You can set min value as -0.49.
http://jsfiddle.net/o4abatfo/2/
One possible solution:
Keep the labels on the outside, and apply the plotBackgroundColor as the chart backgroundColor.
This means that the legend will be encased in the background color too, but, again, it's on option.
Example:
http://jsfiddle.net/jlbriggs/o4abatfo/11/
I asked the same thing in the Highcharts forum and got this solution as a reply from #paweł-fus:
var chartExtraMargin = 30;
Highcharts.wrap(Highcharts.Axis.prototype, 'setAxisSize', function (p) {
p.call(this);
if (this.isXAxis) {
this.left += chartExtraMargin;
this.width -= chartExtraMargin;
this.len = Math.max(this.horiz ? this.width : this.height, 0);
this.pos = this.horiz ? this.left : this.top;
}
});
However, adding this made the tooltips appear in the wrong position. This was fixed by overriding the Tooltip.prototype.getAnchor() method and adding the extra margin in the x coordinate:
Highcharts.wrap(Highcharts.Tooltip.prototype, 'getAnchor', function(p, points, mouseEvent) {
var anchor = p.call(this, points, mouseEvent);
anchor[0] += chartExtraMargin;
return anchor;
});
I have a highstock chart witch candlestick data type.
When I mouseover the data point, I want to highlight the background of the point.
This is what tooltip -> crosshairs do:
tooltip: {
crosshairs: true
}
But the only width option to set is the fixed width. See http://jsfiddle.net/8YBd7/.
This fixed width works with initial zoom, but when I change the zoom, the width is not updated with new point width.
When I set 100% width, the crosshair would fill entire chart area:
tooltip: {
crosshairs: {
width: '100%'
}
}
Is there another option how to highlight current data point by changing its background or setting the width to the pointPixelInterval or something else?
Meanwhile, I produced a dirty workaround, so improvements are welcomed:
xAxis: {
events: {
afterSetExtremes: function() {
this.chart.tooltip.crosshairs = [];
this.chart.options.tooltip.crosshairs.width = (this.width / (this.series[0].points.length-1));
}
}
}
http://jsfiddle.net/QbdEu/1/
Whenever the zoom is changed, the width is recounted according to chart width and number of displayed data points. The width is not updated when calling redraw(), so the old crosshair needs to be removed.
Have you tried to use Renderer http://api.highcharts.com/highstock#Renderer.rect() which allows to plot any shapes and defined width? Only what you need is getting point width in pixels frpm(chart.series[0].data[0].graphic) and then setting correct widht of "shape".
I want to draw a background behind a plotLine label in a highstock chart.
Using an example from the Highstock API, I came up with this code (crt is the chart object):
var textbox = crt.yAxis[ 0 ].plotLinesAndBands[ 0 ].label;
var box = textbox.getBBox();
crt.renderer.rect(box.x - 3, box.y + 1, box.width + 6, box.height, 3).attr({
fill: '#0c0',
id: 'labelBack',
opacity: .7,
'stroke-width': 0,
zIndex: 4
}).add();
This draws a semi-transparent box behind the label as intended (the label has zIndex 5). However when the chart is resized, the box maintains the same position relative to the top-left of the chart, causing misalignment with the label text (the position of the label changes because of the chart resizing).
I tried using the chart redraw event for this, but even though I can see that the event is fired, and the function is executed again, no other boxes are drawn (I was trying to get more boxes to appear on each redraw, planning to solve removing obsolete boxes in the next iteration).
How can I solve this?
It feels more like a hack than a genuine solution, but I have come up with a workaround that solves my issue for now, I have the function below:
var labelBackground = null;
function labelDrawBack(crt) {
if ( isIntraDay ) {
var textbox = crt.yAxis[ 0 ].plotLinesAndBands[ 0 ].label;
if ( !!labelBackground ) {
labelBackground.attr({ y: textbox.y - 10 });
} else {
var box = textbox.getBBox();
labelBackground = crt.renderer.rect( box.x - 3, box.y + 1, box.width + 6, box.height, 3 ).attr( {
fill: '#fff',
id: 'labelBack',
opacity: .65,
'stroke-width': 0,
zIndex: 4
}).add();
}
}
}
I make sure this function is executed immediately after the chart is initialized and additionally I attach the function to the chart object that is returned from the StockChart call:
var chartObj = new Highcharts.StockChart( chartConfig, function ( crt ) {
labelDrawBack( crt );
} );
chartObj.labelDraw = labelDrawBack;
And in the chart options I have added this to the chart.redraw event:
events: {
redraw: function() {
this.labelDraw(this);
}
}
This works as intended, moving the transparent background with the label (which is moved vertically when the chart is resized).
The reason I have redirected the call in the chart redraw event is that the labelDrawBack function is defined in another function than the one where my chart options are defined, thus the labelDrawBack function is out of scope there.