I'm doing a responsive pie chart which holds title in centered position inside it.I've used,
title: {
text: "",
margin: 0,
y:0,
x:0,
align: 'center',
verticalAlign: 'middle',
},
but it's not perfectly centered inside the chart.Any suggestions would be appreciated.Thank you in advance.
Here's the Link : http://jsfiddle.net/LHSey/128/
Better is remove title and use renderer which allows to add custom text, which can be repositioned each time (when you redraw chart). Only what you need is catch this event.
function addTitle() {
if (this.title) {
this.title.destroy();
}
var r = this.renderer,
x = this.series[0].center[0] + this.plotLeft,
y = this.series[0].center[1] + this.plotTop;
this.title = r.text('Series 1', 0, 0)
.css({
color: '#4572A7',
fontSize: '16px'
}).hide()
.add();
var bbox = this.title.getBBox();
this.title.attr({
x: x - (bbox.width / 2),
y: y
}).show();
}
chart:{
events: {
load: addTitle,
redraw: addTitle,
},
}
Example: http://jsfiddle.net/LHSey/129/
We can customize any properties of title using chart.setTitle() as shown below.I've added a title and set useHTML property to true.
chart: {
events: {
load: function () {
this.setTitle({text: 'Title',useHTML:true});
}
}
}
Related
EDIT:
I am having the following JSFiddle where I can enter a custom label annotation. There is something similar in this JSFiddle as well, which was developed as a plugin.
The issue which I am facing is, when clicking over the chart, the input control appears at the place where I clicked and after I enter the text and click "add", once label is placed over the chart, it's placed far away from the position where control was placed (it goes left and up). All this works smoothly in the plugin provided above (second code snippet) and I was trying to figure out and replicate it, but I was not able to do it right.
What I can notice in my code is, seems that positions are working well, but the issue is that if the label needs to be placed at the position (X,Y) I need this (X,Y) position to be the bottom-left point of the newly added annotation label, and by default highcharts is using this as the point at the center of the label.
Here is a video where the difference is very clear.
I believe that this part of the code is responsible for this positioning:
bindings: {
inputText: {
className: 'highcharts-inputText-annotation',
start: function(e) {
const xvalueAn = e.chartX - this.chart.plotLeft;
const yvalueAn = e.chartY - this.chart.plotTop;
var coords = this.chart.pointer.getCoordinates(e),
x = coords.xAxis[0].value,
y = coords.yAxis[0].value,
navigation = this.chart.options.navigation,
controlPoints = [{
positioner: function(target) {
if (!target.graphic.placed) {
return {
x: 0,
y: -9e7
};
}
return {
x: x -
this.graphic.width / 2,
y: y -
this.graphic.height / 2
};
},
events: {
drag: function(e, target) {
var xy = this.mouseMoveToTranslation(e);
target.translate(xy.x, xy.y);
target.annotation.labels[0].options =
target.options;
target.redraw(false);
}
}
}];
var _self = this;
var labelTextForm = document.getElementById('labelTextForm');
var onclick = function() {
_self.chart.addAnnotation(Highcharts.merge({
langKey: 'label',
labelOptions: {
shape: 'rect'
},
labels: [{
text: labelTextForm.querySelector('#labelTextInput').value,
point: {
xAxis: 0,
yAxis: 0,
x: x,
y: y
},
overflow: 'none',
crop: false,
text: labelTextForm.querySelector('#labelTextInput').value,
controlPoints: controlPoints
}]
}, navigation
.annotationsOptions, navigation
.bindings
.labelAnnotation
.annotationsOptions));
};
Highcharts.css(
labelTextForm, {
top: (e.pageY - 20) + 'px',
left: e.pageX + 'px',
display: 'block'
}
);
var unbinder = Highcharts.addEvent(
labelTextForm.querySelector('#labelTextButton'),
'click',
function() {
onclick();
Highcharts.css(labelTextForm, {
display: 'none'
});
unbinder();
}
)
return true;
}
},
ORIGINAL CODE:
My initial code was placed here JSFiddle and the first comment helped me to fix the position of the input filed itself, but the issue for attached label not matching at the same position where input filed was placed, still remains. With the initial fix applied, I got to the code which I attached in my updated question above.
I want to add some tooltips for the preconfigured date range buttons (like 1 day, 1 month etc.) in stock chart in highstock. I am not able to find a way to do it.
refer this link
Any help would be appreciated.
Thanks
Highcharts doesn't have built-in tooltip for the rangeSelector, but still you can create your own tooltip for that. It is very simple to add events to the buttons:
Highcharts.stockChart('container', {
chart: {
events: {
load: function() {
var chart = this,
buttons = chart.rangeSelector.buttons;
for (var i = 0, len = buttons.length; i < len; i++) {
(function(i) {
var item = buttons[i],
group = $('.highcharts-range-selector-tooltip'),
rectElem = $('.range-selector-tooltip'),
textElem = $('.range-selector-tooltip-text'),
box;
item.on('mouseover', function(e) {
// Define legend-tooltip text
var str = item.text.textStr;
textElem.text(str)
// Adjust rect size to text
box = textElem[0].getBBox()
rectElem.attr({
x: box.x - 8,
y: box.y - 5,
width: box.width + 15,
height: box.height + 10
})
// Show tooltip
group.attr({
transform: `translate(${e.clientX + 7}, ${e.clientY + 7})`
})
}).on('mouseout', function(e) {
// Hide tooltip
group.attr({
transform: 'translate(-9999,-9999)'
})
});
})(i);
}
}
}
},
...
}, function(chart) {
var group = chart.renderer.g('range-selector-tooltip')
.attr({
transform: 'translate(-9999, -9999)',
zIndex: 99
}).add(),
text = chart.renderer.text()
.attr({
class: 'range-selector-tooltip-text',
zIndex: 7
}).add(group),
box = text.getBBox();
chart.renderer.rect().attr({
'class': 'range-selector-tooltip',
'stroke-width': 1,
'stroke': 'grey',
'fill': 'white',
'zIndex': 6
})
.add(group)
});
Live example: http://jsfiddle.net/BlackLabel/Lg9cfrub/
API Reference: https://api.highcharts.com/highstock/chart.events.load
I try to add several times the same element in my paper.
Then I created it thanks to embed and then I cloned it with deep:true.
My problem is that deep:true change some properties (I don't know which) but I'm now enable to apply a translation to it.
here is my code, that work without deep:true but doesn't with. (but clone a rect and not my combined element) :
var width=400, height=1000;
var graph = new joint.dia.Graph; //define a graph
var paper = new joint.dia.Paper({ //define a paper
el: $('#myholder'),
width: width,
height: height,
gridSize: 1,
model: graph, //include paper in my graph
restrictTranslate: function(element) { //restriction of drag n drop to the vertical line (x never changes)
return {
x: element.model.attributes.position.x, //this represent the original x position of my element
y: 0,
width: 0,
height: height
};
}
});
var rect1 = new joint.shapes.basic.Rect({ //create first rect (with input and output)
position: { x: 100, y: 20 },
size: { width: 90, height: 90 },
attrs: {
rect: { fill: '#2ECC71' }
}
});
var add_block= new joint.shapes.basic.Circle({ //create add button
position: { x: 170, y: 20 },
size: { width: 20, height: 20 },
attrs: {
circle: { fill: '#2ECC71'},
text:{text:'+', "font-size":20}
}
});
rect1.embed(add_block);
graph.addCell([rect1,add_block]);
var clones=rect1.clone({deep:true});
graph.addCells(clones);
var line = V('line', { x1: 250, y1: 10, x2: 250, y2: 500, stroke: '#ddd' });
V(paper.viewport).append(line);
//Create a new block and link between two blocks
//chek if click on + button
//if click on this button, create a new block and link between them
paper.on('cell:pointerclick', function(cellView, evt, x, y) {
var elementBelow = graph.get('cells').find(function(cell) {
if (!cell.get('parent')) return false;//not interested in parent
if (cell instanceof joint.dia.Link) return false; // Not interested in links.
if (cell.getBBox().containsPoint(g.point(x, y))) {
return true;
}
return false;
});
if(elementBelow) //if we start from a block, let's go!
{
rect=rect1.clone({deep:true});
graph.addCell(rect);
rect.translate(200, 0);
}
});
Using various posts/questions in SO as reference I created a scatter highchart jsfiddle
xAxis: {
opposite:true,
type: 'datetime',
gridLineWidth: 1,
gridLineDashStyle: 'ShortDot',
gridLineColor:'black',
alternateGridColor: 'lightgrey',
tickInterval: 3 * 30 * 24 * 3600 * 1000, // 1 quarter
labels: {
//align: "left",
//padding:200,
formatter: function () {
var s = "";
if (Highcharts.dateFormat('%b', this.value) == 'Jan') {
s = s + "Q1"
};
if (Highcharts.dateFormat('%b', this.value) == 'Apr') {
s = s + "Q2"
};
if (Highcharts.dateFormat('%b', this.value) == 'Jul') {
s = s + "Q3"
};
if (Highcharts.dateFormat('%b', this.value) == 'Oct') {
s = s + "Q4"
};
s = s + " " + Highcharts.dateFormat('%Y', this.value);
return s;
}
},
plotLines: [{
color: 'red', // Color value
value: now, // Value of where the line will appear
width: 2, // Width of the line
label: {
text: 'Now',
align: 'center',
verticalAlign: 'bottom',
y: +20,
rotation: 0
}
}]
},
But I'm struck with having the X-axis label positioned near the tick.
How to move to middle of the grid?
Is there anyway I can achieve the below?
I tried align, padding but didn't help. When the timeline increases I should still have the labels positioned in the middle.
should I do something with tickInterval? It might be a simple property I'm missing.
I found this link jsfiddle which addresses my concern but with 2 x-axis and I'm populating the data from a list.
I implemented Christopher Cortez' solution found here:
However, also changed to to fire on the highcharts load event, rather than the callback, and I've changed it to be recalled when the HighCharts redraw event is fired, so that they stay aligned when the page is resized.
$('#container').highcharts({
chart: {
defaultSeriesType: 'scatter',
events: {
load: centerLabels,
redraw: centerLabels
}
},
/* ... all the other options ...*/
});
Where
function centerLabels(chart) {
var $container = $(chart.target.container);
var axes = chart.target.axes;
var $labels = $container.find('.highcharts-axis-labels .timeline_label');
var $thisLabel, $nextLabel, thisXPos, nextXPos, delta, newXPos;
$labels.each(function () {
$thisLabel = $(this).parent('span');
thisXPos = parseInt($thisLabel.css('left'));
$nextLabel = $thisLabel.next();
// next position is either a label or the end of the axis
nextXPos = $nextLabel.length ? parseInt($nextLabel.css('left')) : axes[0].left + axes[0].width;
delta = (nextXPos - thisXPos) / 2.0;
newXPos = thisXPos + delta;
// remove the last label if it won't fit
if ($nextLabel.length || $(this).width() + newXPos < nextXPos) {
$thisLabel.css('left', newXPos + 'px');
} else {
$thisLabel.remove();
}
});
}
JSFiddle
I have a custom subclass in FabricJS that is based on a FabricJS group:
var canvasObject = fabric.util.createClass(fabric.Group, {
type: 'canvasObject',
initialize: function(options) {
options || (options = { });
this.callSuper('initialize', options);
var rectBase = new fabric.Rect({
fill : 'red',
originX: 'left',
originY: 'top',
left: options.margin.l,
top: options.margin.t,
width : (options.width-options.margin.l-options.margin.r),
height :(options.height-options.margin.t-options.margin.b),
});
var labeledRect = new LabeledRect({
width: options.width,
height: options.height,
'idname': options.idname,
background: 'transparent',
labelFont: '14px Helvetica',
});
this.callSuper('initialize', [labeledRect, rectBase], options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'), {
idname: this.get('idname')
});
},
_render: function(ctx) {
this.callSuper('_render', ctx);
}
});
How do I include an SVG within this custom group. I'd like to be able to load an SVG from a URL similar to this:
fabric.loadSVGFromURL('example.svg', function(objects, options) {
var shape = fabric.util.groupSVGElements(objects, options);
canvas.add(shape.scale(1));
canvas.renderAll();
});
But have it add to the canvas within my custom group - so that each canvasObject added can have an SVG attached.
I've tried adding the SVG to a PathGroup object - but I'm not sure the asynchronous load is working with it.
I'd also like to be able to update the SVG images within each group. How can I update an SVG path content similar to updating an objects properties?