Angle tag solutions for Graphael multiple line chart - show-hide

I've tried to create an multipleline chart with tag for each node.
Every things ok. But some time the tags are showed not good when the values are nearly.
Any one have solution for this problem. Thank!
http://www.flickr.com/photos/96516997#N02/8973858413/
This is my
Graphael Line Chart
<script src="js/raphael-min.js"></script>
<script src="js/g.raphael-min.js"></script>
<script src="js/g.line-min.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<style type="text/css">
.block {
text-align: center;
background: #c0c0c0;
}
.block:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.centered1{
display: inline-block;
vertical-align: middle;
width: 97%;
background: #f5f5f5;
}
.centered2{
text-align: left;
display: inline-block;
vertical-align: middle;
width: 97%;
background: #f5f5f5;
}
</style>
<script type="text/javascript">
var hidedChart = [ false, false, false, false];
var paper;
var chart;
var xData = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
var yData = [ [ 31, 62, 3, 4, 5, 60, 47, 8, 9, 10, 51, 72 ],
[ 31, 33, 44, 11, 55, 60, 71, 82, 19, 141, 23, 34 ],
[ 3, 2, 49, 64, 51, 26, 43, 14, 39, 10, 41, 32 ],
[ 10, 330, 50, 34, 53, 12, 67, 84, 32, 171, 239, 36 ]];
var colory = [ "#9e1316", "#007fff", "#104421", "#734f96", "#b43f26" ];
var xAxis = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" ];
var direcTag = [ 'right', 'up', 'left', 'down' ];
var angle = [0,45,90,135,180,225,270,315];
var options = {
symbol : "circle",
nostroke : false,
smooth : false,
colors : colory,
shade : true,
fill : "transparent",
axis : "0 0 1 1",
axisxstep : xAxis.length - 1,
axisystep : 5
};
window.onload = function() {
paper = Raphael("no", "800", "550");
//line chart object
chart = drawLineChart(34, 35, 600, 450, xData, yData, options);
addCheckBox(yData.length);
}
$(window).load(function(){
});
function drawLineChart(x, y, w, h, xdata, ydata, options) {
var lines = paper.linechart(x, y, w, h, xdata, ydata, options);
lines.hoverColumn(hoverColumn, unhoverColumn);
//set x Axis label
$.each(lines.axis[0].text.items, function(index, label) {
this.attr("text", xAxis[index]);
});
for ( var i = 0; i < ydata.length; i++) {
lines.shades[i].attr({
fill : "transparent"
});
}
lines.symbols.attr({
r : 4
});
return lines
}
function hoverColumn() {
this.tags = paper.set();
for ( var i = 0, ii = this.y.length; i < ii; i++) {
if (hidedChart[i] == false) {
var nTag;
nTag = paper.drop(this.x, this.y[i], this.values[i],
angle[i]);
this.tags.push(nTag.insertBefore(this).attr([ {
fill : colory[i]
}, {
fill : "#ffffff"
} ]));
}
}
}
function unhoverColumn() {
this.tags && this.tags.remove();
}
function showHideLine(num) {
if((!$("#LINE"+num).is(':checked')) != hidedChart[num]){
hidedChart[num] = !hidedChart[num];
if (hidedChart[num] == true) {
chart.lines[num].attr({
opacity : 0
});
chart.symbols[num].attr({
opacity : 0
});
} else {
chart.lines[num].attr({
opacity : 100
});
chart.symbols[num].attr({
opacity : 100
});
}
}
}
function addCheckBox(num) {
$("#lineCheck").empty();
for ( var i = 0; i < num; i++) {
//CHECK BOX
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = "LINE" + i;
checkbox.style.margin = "7px";
checkbox.checked = "checked";
$(checkbox).click(function() {
for ( var j = 0; j < num; j++) {
showHideLine(j);
}
});
//LABEL
var label = document.createElement("label");
label.htmlFor = "LINE" + i;
label.appendChild(document.createTextNode("Line " + (i + 1)));
//BREAK LINE
var br = document.createElement("br");
$("#lineCheck").append(checkbox);
$("#lineCheck").append(label);
$("#lineCheck").append(br);
}
}
</script>
</head>
<body>
<div id="padLeft" class="block" style="float: left; width: 84%; height: 100%;">
<div id="no" class="centered1"></div>
</div>
<div id="padRight" class="block" style="float: right; height: 100%; width: 15%;" align="left">
<div id="lineCheck" class="centered2"></div>
</div>
</body>
</html>

Related

How to create gauge diagram with amchart 5 with arabic text in it

I want to create a gauge diagram with amcharts 5 with persian text on it. All the code sample I found is working correctly with english text on it. But when I want to use persian or arabic text (rtl languages), it doesn't show texts correct. How can I solve this problem?
Here is my code:
<script>
var root = am5.Root.new("chartdiv");
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(am5radar.RadarChart.new(root, {
panX: false,
panY: false,
startAngle: 160,
endAngle: 380
}));
var axisRenderer = am5radar.AxisRendererCircular.new(root, {
innerRadius: -40
});
axisRenderer.grid.template.setAll({
stroke: root.interfaceColors.get("background"),
visible: true,
strokeOpacity: 0.8
});
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
maxDeviation: 0,
min: -40,
max: 100,
strictMinMax: true,
renderer: axisRenderer
}));
var axisDataItem = xAxis.makeDataItem({});
var clockHand = am5radar.ClockHand.new(root, {
pinRadius: am5.percent(20),
radius: am5.percent(100),
bottomWidth: 40
})
var bullet = axisDataItem.set("bullet", am5xy.AxisBullet.new(root, {
sprite: clockHand
}));
xAxis.createAxisRange(axisDataItem);
var label = chart.radarContainer.children.push(am5.Label.new(root, {
fill: am5.color(0xffffff),
centerX: am5.percent(50),
textAlign: "center",
centerY: am5.percent(50),
fontSize: "3em"
}));
axisDataItem.set("value", 50);
bullet.get("sprite").on("rotation", function () {
var value = axisDataItem.get("value");
var text = Math.round(axisDataItem.get("value")).toString();
var fill = am5.color(0x000000);
xAxis.axisRanges.each(function (axisRange) {
if (value >= axisRange.get("value") && value <= axisRange.get("endValue")) {
fill = axisRange.get("axisFill").get("fill");
}
})
label.set("text", Math.round(value).toString());
clockHand.pin.animate({ key: "fill", to: fill, duration: 500, easing: am5.ease.out(am5.ease.cubic) })
clockHand.hand.animate({ key: "fill", to: fill, duration: 500, easing: am5.ease.out(am5.ease.cubic) })
});
var i = 0;
var a = setInterval(function() {
if (i === 9) {
axisDataItem.animate({
key: "value",
to: Math.round(28),
duration: 100,
easing: am5.ease.out(am5.ease.cubic)
});
}
else if (i === 25) {
clearInterval(a);
}
else {
axisDataItem.animate({
key: "value",
to: Math.round(Math.random() * 140 - 40),
duration: 2000,
easing: am5.ease.out(am5.ease.cubic)
});
i++;
}
}
, 100);
var bandsData = [{
title: "لاغری مفرط",
direction: "rtl",
position: "right",
orientation: "rtl",
color: "#ee1f25",
lowScore: -40,
highScore: -20
}, {
title: 'لاغر',
color: "#f04922",
lowScore: -20,
highScore: 0
}, {
title: "نرمال",
color: "#fdae19",
lowScore: 0,
highScore: 20
}, {
title: "اضافه وزن",
color: "#f3eb0c",
lowScore: 20,
highScore: 40
}, {
title: "چاق",
color: "#b0d136",
lowScore: 40,
highScore: 60
}, {
title: "چاقی زیاد",
color: "#54b947",
lowScore: 60,
highScore: 80
}, {
title: "چاقی مفرط",
color: "#0f9747",
lowScore: 80,
highScore: 100
}];
am5.array.each(bandsData, function (data) {
var axisRange = xAxis.createAxisRange(xAxis.makeDataItem({}));
axisRange.setAll({
value: data.lowScore,
endValue: data.highScore
});
axisRange.get("axisFill").setAll({
visible: true,
fill: am5.color(data.color),
fillOpacity: 0.8
});
axisRange.get("label").setAll({
text: data.title,
inside: true,
radius: 15,
fontSize: "0.9em",
fill: root.interfaceColors.get("background")
});
});
chart.rtl = true;
chart.appear(1000, 100);
chart.rtl = true;
</script>
Final result is like this image:
amcharts5 result
I also searched about it in documentation of amcharts 5 but I couldn't find the answer.

Laravel - How to Display both count and percentage (%) in chartjs pie chart

In my Laravel-5.8, I have used chartjs to display total male and female counts (total number of male and female)
as shown below:
Controller:
public function report()
{
$userCompany = Auth::user()->company_id;
$userId = Auth::user()->id;
$gender_record = HrEmployee::selectRaw('count(gender_id) as count,gender_id, if (gender_id = 1, "Male", "Female") as gender')->where('company_id', $userCompany)->groupBy('gender_id')->get();
$gender_data = [];
foreach($gender_record as $row) {
$gender_data['gender_label'][] = $row->gender;
$gender_data['gender_data'][] = (int) $row->count;
}
$gender_data['gender_chart_data'] = json_encode($gender_data);
return view('report-default', $gender_data);
}
view
<div class="card-body">
<canvas id="empGender" style="min-height: 250px; height: 250px; max-height: 250px; max-width: 100%;"></canvas>
</div>
<script src="{{ asset('theme/adminlte3/plugins/chart.js/Chart.min.js') }}"></script>
<script>
$(function () {
/* ChartJS
* -------
* Charts using ChartJS
*/
//-------------
//- GENDER-EMPLOYEE CHART -
//-------------
// Get context with jQuery - using jQuery's .get() method.
var genderData = JSON.parse(`<?php echo $gender_chart_data; ?>`);
var genderChartCanvas = $('#empGender').get(0).getContext('2d')
var genderData = {
labels: genderData.gender_label,
datasets: [
{
data: genderData.gender_data,
backgroundColor : [
'#f56954',
'#00a65a',
'#f39c12',
'#00c0ef',
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
],
borderWidth: 1
}
]
}
var genderOptions = {
maintainAspectRatio : true,
responsive : true,
cutoutPercentage: 80,
}
//Create pie or douhnut chart
var genderChart = new Chart(genderChartCanvas, {
type: 'doughnut',
data: genderData,
options: genderOptions
})
})
</script>
What I have as shown above only displays Total counts per Gender as shown above.
How do I make it also to include the percentage per Gender?
Thank you.
You can do this by defining a tooltip label callback function as follows.
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
var value = data.datasets[0].data[tooltipItem.index];
var total = data.datasets[0].data.reduce((a, b) => a + b, 0);
var pct = 100 / total * value;
var pctRounded = Math.round(pct * 10) / 10;
return value + ' (' + pctRounded + '%)';
}
}
}
Please have a look at below runnable code snippet.
new Chart('empGender', {
type: 'doughnut',
data: {
labels: ['Male', 'Female'],
datasets: [{
backgroundColor: ['#f56954', '#00a65a'],
borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)'],
data: [17, 7],
borderWidth: 1
}]
},
options: {
maintainAspectRatio: true,
responsive: true,
cutoutPercentage: 80,
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
var value = data.datasets[0].data[tooltipItem.index];
var total = data.datasets[0].data.reduce((a, b) => a + b, 0);
var pct = 100 / total * value;
var pctRounded = Math.round(pct * 10) / 10;
return value + ' (' + pctRounded + '%)';
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="empGender" height="100"></canvas>

Aligning C3 line shapes with Bar charts

We have the following mixed line chart / bar chart in C3:
a bar chart with two groups (light/dark blue is one group, gray is the
other group)
two other data sets represented as line with stroke-width = 0 that represent the limit for group1 and group2.
How can we place the circle shape for line1 aligned with the bar for group1 and the circle shape for line2 aligned with the two bars of group2?
In the following example, we basically would want one of the two circles to be moved slightly to the right so to align with the center of a group and the other one slightly to the left.
var chartSettings = {
padding: {
left: 120,
right: 120
},
bindto: '#chart',
data: {
x: 'Dates',
type: 'bar',
types: {
line1: 'line',
line2: 'line'
},
groups: [
['data2', 'data3'],
],
colors: {
data1: '#f3e274',
data2: '#85bdde',
data3: '#ccebfb'
},
},
bar: {
width: {
ratio: 0.50
}
},
point: {
r: 8
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%d-%m-%Y'
}
},
y: {
label: { // ADD
text: '',
position: 'outer-middle'
},
},
}
};
var date1 = new Date(2015, 1, 1, 0,0, 0,0);
var date2 = new Date(2015, 3, 1, 0,0, 0,0);
var date3 = new Date(2015, 6, 1, 0,0, 0,0);
var xAxis = ['Dates', date1, date2,date3];
var line1 = ['line1', 50, 60,55];
var line2 = ['line2', 70, 75,60];
var data1 = ['data1', 40, 35,30];
var data2 = ['data2', 5, 10,10];
var data3 = ['data3', 20, 15,30];
chartSettings.data.columns = [xAxis,
line1,
line2,
data1,
data2,
data3];
c3.generate(chartSettings);
#cr-chart .c3-line-accordatoTotale {
stroke-width: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart"/>
var chartSettings = {
bindto: '#chart',
data: {
x: 'Dates',
type: 'bar',
types: {
line1: 'line',
line2: 'line'
},
groups: [
['data2', 'data3'],
],
names: {
line1: 'Limit for data1',
line2: 'Limit for data2 + data3',
data1: 'Data1',
data2: 'Data2',
data3: 'Data3'
},
},
bar: {
width: {
ratio: 0.50 // this makes bar width 50% of length between ticks
}
},
point: {
r: 8
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%d-%m-%Y'
}
},
y: {
label: { // ADD
text: '',
position: 'outer-middle'
}
},
}
};
var date1 = new Date(2016, 1, 1, 0, 0, 0, 0);
var date2 = new Date(2016, 3, 1, 0, 0, 0, 0);
var date3 = new Date(2016, 6, 1, 0, 0, 0, 0);
var xAxis = ['Dates',date1,date2,date3];
var line1 = ['line1', 50, 70,80];
var data1 = ['data1', 30, 40, 60];
var line2 = ['line2', 70, 60,40];
var data2 = ['data2',10,15,20];
var data3 = ['data3',15,30,5];
chartSettings.data.columns = [xAxis,
line1,
line2,
data1,
data2,
data3];
c3.generate(chartSettings);
#chart .c3-line-line1 {
stroke-width: 0px;
}
#chart .c3-line-line2 {
stroke-width: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart"/>
It would be nice if you attached some jsfiddle.
But at this point I can say that you probably need to look inside .c3-chart-lines container and find desired line eighter by order:
.c3-chart-line:first-child // or last-child?
or by data name:
.c3-chart-line.c3-target-YOUR-ORANGE-DATA-NAME
Hope this helps.

fabric.js works with subclass

I try to create new class working with fabric.js framework. This class should consist of 3 simple objects: 2 text and 1 rectangle. One of text object should be updated by time, for example each second. The problem is new value does not appear on canvas as expected, but it updates every time when you select object. Here is my code. Could anyone explain me, what should I do to make it updates by time?
var canvas = new fabric.Canvas('c');
fabric.Tag = fabric.util.createClass(fabric.Group, {
type: 'PItag',
initialize: function() {
options = {};
options.top = 0;
options.left = 0;
var defaults = {
width: 100,
height: 40,
originX: 'center',
originY: 'center'
};
var defaults1 = {
width: 100,
height: 20,
originX: 'center',
originY: 'top',
top: -20,
backgroundColor: 'red'
};
var defaults2 = {
width: 100,
height: 20,
originX: 'center',
originY: 'top',
top: 0
};
var items = [];
items[0] = new fabric.Rect($.extend({}, defaults, {
fill: '#77AAFF',
}));
items[1] = new fabric.Textbox('PI tag name', $.extend({}, defaults1, {
textAlign: 'center',
fontSize: 14
}));
items[2] = new fabric.IText('####', $.extend({}, defaults2, {
textAlign: 'center',
fontSize: 16
}));
this.callSuper('initialize', items, options);
},
getTagName: function () {
return this._objects[1].text;
},
setTagName: function (value) {
this._objects[1].text = value;
},
getValue: function () {
return this._objects[2].text;
},
setValue: function (value) {
this._objects[2].text = value;
this.canvas.renderAll();
},
_render: function(ctx) {
this.callSuper('_render', ctx);
}
});
var pi = new fabric.Tag();
pi.setTagName("Unix time");
canvas.add(pi);
setInterval(function() {
pi.setValue(Math.floor((new Date()).getTime() / 1000).toString());
canvas.renderAll();
}, 1000);
var canvas = new fabric.Canvas('c');
fabric.Tag = fabric.util.createClass(fabric.Group, {
type: 'PItag',
initialize: function() {
options = {};
options.left = 100;
options.top=100;
var defaults = {
width: 100,
height: 40,
originX: 'center',
originY: 'center'
};
var defaults1 = {
width: 100,
height: 20,
originX: 'center',
originY: 'top',
top: -20,
backgroundColor: 'red'
};
var defaults2 = {
width: 100,
height: 20,
originX: 'center',
originY: 'top',
top: 0
};
var items = [];
items[0] = new fabric.Rect($.extend({}, defaults, {
fill: '#77AAFF',
}));
items[1] = new fabric.Textbox('PI tag name', $.extend({}, defaults1, {
textAlign: 'center',
fontSize: 14
}));
items[2] = new fabric.IText('####', $.extend({}, defaults2, {
textAlign: 'center',
fontSize: 16
}));
this.callSuper('initialize', items, options);
},
getTagName: function () {
return this._objects[1].text;
},
setTagName: function (value) {
this._objects[1].text = value;
},
getValue: function () {
return this._objects[2].text;
},
setValue: function (value) {
this._objects[2].set({ text: value });
this.canvas.renderAll();
},
_render: function(ctx,noTransform) {
console.log('xs')
this.callSuper('_render', ctx);
//ctx._objects[1].text = this._objects[1].text;
}
});
var pi = new fabric.Tag();
// canvas.pi.async = true;
pi.setTagName("Unix time");
canvas.add(pi);
setInterval(function() {
pi.setValue(Math.floor((new Date()).getTime() / 1000).toString());
canvas.renderAll();
}, 1000);
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="c" height="418" width="400" style="border: 1px solid rgb(170, 170, 170);"></canvas>
just change this function
setValue: function (value) {
this._objects[2].set({ text: value });
this.canvas.renderAll();
},

C3.js Donut Chart,Grow Segment

i'm exploring c3.js, i have created an donut chart, which was very simple to do, next thing i wanted to do is on mouser-over i wanted to expand/zoom/popout that focused segment, this functionality we can see in d3pai., but i'm trying to achieve this effect purely using c3.js.
can some one please suggest me how to proceed and how to create such poping-up of segment effect.
var init = function() {
var chart = c3.generate({
data: {
x: 'x',
columns: [
['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
['Coin1', 30, 200, 100, 400, 150, 250],
['Coin2', 130, 100, 140, 200, 150, 50],
['Coni3', 50, 100, 130, 240, 200, 150],
['Coin4', 130, 100, 140, 200, 150, 50],
['Coin5', 130, 150, 200, 300, 200, 100]
],
type: 'donut',
onclick: function(e) {
//console.log(e);
// console.log(d3.select(this).attr("stroke-width","red"));
},
onmouseover: function(d, i) {
},
onmouseout: function(d, i) {
}
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d',
centered: true,
position: 'inner-right'
}
}
},
bindto: '#dash',
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
},
pie: {
expand: true,
},
tooltip: {
grouped: false,
contents: function(data, defaultTitleFormat, defaultValueFormat, color) {
// console.log("Containt");
// console.log(data, defaultTitleFormat, defaultValueFormat, color);
return "<p style='border:1px solid red;'>" + data[0].value + "</p>";
}
}
});
};
inti();
p {
line-height: 1;
font-weight: bold;
padding: 5px 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 4px;
line-height: 15px;
font-size: 12px;
min-width: 91px;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>
</head>
<body>
<div id="dash"></div>
</body>
</html>
In the c3 config object, you can define onmouseover and onmouseout callback functions. The DOM node corresponding to the events is passed in as the second argument, so you can use it in the logic.
You can use that to apply things such as transformations. So on mouseover, you could scale it up, and on mouseout, scale it down. This is just a nudge in the right direction. You can play with other transformations to get the effect you want.
onmouseover: function (d, i) {
// 'i' is the dom node.
d3.select(i).attr("transform", "scale(1.1)")
},
onmouseout: function (d, i) {
d3.select(i).attr("transform", "scale(1)")
}
http://jsfiddle.net/ggamir/eqkrr5j0/
If you want the transformation to persist until the next mouse event, then you can keep track of the last item hovered over, and only "de-transform" it on the next mouseover:
http://jsfiddle.net/ggamir/79qhy9hn/
// Somewhere outside before defining your c3 config object:
var currentSlice;
// Inside your c3 config object:
onmouseover: function (d, i) {
if(currentSlice !== void 0) {
currentSlice.attr("transform","scale(1)")
}
currentSlice = d3.select(i).attr("transform", "scale(1.1)");
}

Resources