g.raphael : how to animate bar chart height? - javascript

Is there any option to increase bar chart as animation from 0 to ?
bars.animate({'stroke':"#FF0"},1000); this can change attributes. Actually I need to change value of bar chart height and also change label when increase which didn't find yet.
var svgWidth = 400;
var svgHeight = 450;
var r = Raphael('overview');
var barBorder = {stroke: '#000', 'stroke-width':1};
r.setViewBox(0, 0, svgWidth, svgHeight, false);
r.setSize('100%', '100%');
var colors = [ "#999", "#B2B2B2", "#CCC"];
data4 = [[83], [72], [43]];
data2 = [[13], [22], [20]];
var bars = r.barchart(50, 20, 250, 150, data4, {colors: colors, 'gutter': '-1%'}).bars.attr(barBorder);//.hover(fin, fout);
var unicorn = r.path("M350 150 H10 V10").attr({stroke: "#000","stroke-width": 1});
bars.animate({'stroke':"#FF0"},1000);
Demo.

Finally changed barchart() to rect()
here is my solution http://jsfiddle.net/sweetmaanu/sqnXM/
// Create options object that specifies the rectangle
var PatientBar1 = { width: 100,height: 200,x: 0,y: 0}
var PatientBar2 = { width: 100,height: 180,x: 100,y: 20}
var PatientBar3 = { width: 100,height: 120,x: 200,y: 80}
var speed = 2000;
// Create new raphael object
var patient01 = new Raphael('patient02-mobile', 300, 300);
/*
* Create rectangle object with y-position at bottom by setting it to the specified height,
* also give the rectangle a height of '0' to make it invisible before animation starts
*/
var rect1 = patient01.rect(PatientBar1.x, PatientBar1.height, PatientBar1.width, 0).attr({fill: '#999', stroke:'#000'});
var rect2 = patient01.rect(PatientBar2.x, 200, PatientBar2.width, 0).attr({fill: '#B2B2B2', stroke:'#000'});
var rect3 = patient01.rect(PatientBar3.x, 200, PatientBar3.width, 0).attr({fill: '#CCC', stroke:'#000'});
/*
* Animate the rectangle from bottom up by setting the height to the earlier specified
* height and by setting the y-position to the top of the rectangle
*/
var anim1 = rect1.animate({
y:PatientBar1.y,
height:PatientBar1.height
}, speed);
var anim2 = Raphael.animation({
y:PatientBar2.y,
height:PatientBar2.height
}, speed);
var anim3 = Raphael.animation({
y:PatientBar3.y,
height:PatientBar3.height
}, speed);
rect2.animate(anim2.delay(2000));
rect3.animate(anim3.delay(4000));
Please post answer if anybody find solution :)

Related

Calculate % position of the group in fabric js

I am stuck in a problem, don't know if this is related to the current thread.
I have created a rectangle inside the canvas like this:
The grey part is the canvas there is a small rectangle inside. This is the code I have written:
// THIS METHOD WHEN THE COMPONENT IS INITIALIZED
// THAT IS VERY FIRST TIME
// htmlCanvas = Canvas from HTML file
initCanvas(htmlCanvas) {
this.mockupDrawableAreaCanvasSize = size;
this.mainCanvasDivRef = htmlCanvas;
fabric.textureSize = 4096;
fabric.charWidthsCache = {};
fabric.Object.prototype.borderScaleFactor = 2;
fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.lockScalingFlip = true;
fabric.Object.prototype.hasRotatingPoint = true;
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.cornerColor = "rgb(255,255,255)";
fabric.Object.prototype.cornerSize = 8;
fabric.Object.prototype.cornerStrokeColor = "#48B774";
fabric.Object.prototype.borderColor = "#48B774";
fabric.Object.prototype.fill = "#FFFFFF";
fabric.Object.prototype.cornerStyle = "rect";
fabric.Object.prototype.borderOpacityWhenMoving = .5;
fabric.Object.prototype.snapAngle = 90;
fabric.Object.prototype.snapThreshold = 5;
fabric.Object.prototype.charWidthsCache = {};
this.canvas = new fabric.Canvas(htmlCanvas.nativeElement, this.defaultOption);
this.canvas.backgroundColor = '#e8e8e8';
this.canvas.uniScaleTransform = true;
this.canvas.requestRenderAll()
// -------
const {
width,
height
} = this.getDimensions();
this.drawingBoard = new fabric.Rect({
excludeFromExport: false,
hasControls: false,
height,
selectable: false,
borderColor: "transparent",
strokeWidth: 0,
stroke: 'transparent',
fill: '#ffffff',
width,
preserveObjectStacking: false,
absolutePositioned: true,
clip_id: 'io_main_canvas',
originX: 'center',
originY: 'center',
lockUniScaling: true,
});
}
// Here mockupDrawableAreaCanvasSize = {width: 1080, height: 1080}
getDimensions() {
let containerWidth: any = parseInt(this.mockupDrawableAreaCanvasSize.width, 10);
let containerHeight: any = parseInt(this.mockupDrawableAreaCanvasSize.height, 10);
const footer: any = document.querySelector('.footer-toolbar');
const container = document.querySelector('.upper-canvas');
const lowerCanvasEl = container && window.getComputedStyle(container, null);
let canvasHeight = parseInt(lowerCanvasEl.height, 10) - 1.5 * parseInt(footer.offsetHeight, 10);
const canvasWidth = parseInt(lowerCanvasEl.width, 10);
// Complete fit
if (containerWidth <= canvasWidth && containerHeight <= canvasHeight) {
return {
width: containerWidth,
height: containerHeight
}
}
if (canvasWidth < containerWidth) {
containerWidth = canvasWidth - 80;
canvasHeight = (containerWidth / (containerWidth / containerHeight)) - 6 * parseInt(footer.offsetHeight, 10)
}
let width = (containerWidth / containerHeight) * canvasHeight;
return {
width,
height: canvasHeight
}
}
This code works well in every use case. I want to position the objects at the same place where they were initially in the bigger or smaller screens.
My approach was:
Group everything, Add the group to canvas, calculate the percentage, scale and finally ungroup
But the objects are very small as shown in the below picture
How should I scale the object so that the whole content is a perfect fit in the group?
Group everything -> done
calculate % position of the group -> done
scale the group by ratio -> how?
-->>> The ratio between which values- group and canvas or group and drawing board?
apply for the same % position -->done
Ungroup --> done
I found many issues with the approach I was trying to implement. Now instead od repositionin, grouping, etc.I am zooming the canvas

How to create a JavaScript stacked, semi-circle gauge chart with customized line widths?

I would like to be able to plot two or three values on one stacked gauge chart, similar to the following, with a light green, on top of another blue and a main thick value:
I have seen examples of these lines being separated, which would also do.
The first two need not be superimposed, but would be nice.
In looking at https://github.com/pguso/jquery-plugin-circliful, I can create multiple values on a chart but only in full-circle, not half-circle.
In the following JSFiddle, https://jsfiddle.net/0c8qaqaj/41/
<section class="container">
<h3>Circliful</h3>
<div class="row">
<div class="col-lg-4">
<div id="test-circle"></div>
</div> </div>
</section>
<script>
$( document ).ready(function() { // 6,32 5,38 2,34
$("#test-circle").circliful({
animation: 1,
animationStep: 5,
foregroundBorderWidth: 7,
backgroundBorderWidth: 7,
percent: 99,
textSize: 28,
textStyle: 'font-size: 12px;',
textColor: '#666',
multiPercentage: 1,
//halfCircle: 1,
halfCircle: false,
percentages: [
{'percent': 10, 'color': '#3180B8', 'title': 'Gryffindor' },
{'percent': 30, 'color': '#4ADBEA', 'title': 'Ravenclaw' },
{'percent': 50, 'color': '#49EBA8', 'title': 'Hufflepuff' },
{'percent': 70, 'color': '#FFCA35', 'title': 'Slytherin' }
],
multiPercentageLegend: 1,
replacePercentageByText: '',
backgroundColor: '#eee',
icon: 'f0d0',
iconPosition: 'middle',
iconColor: '#273B4E'
});
});
</script>
Setting 'halfCircle: true', only draws one value. Obviously not what I'm looking for.
The library does have a sample with two values, although I'm not sure how to replicate this example and whether or not it would work in halfcircle or if I can create an array to stack these values.
In another test, using AMCharts, I was able to create a semi-circle, stacked gauge chart.
A few issues:
I am unable to change the chart line widths manually. They seem to be proportional to the larger of the chart's height or width setting.
Setting width: 350:
I cannot change the white-space/padding above/below the charts. This one is fixable using css position: relative; left: -150; or whatever works. I don't really want to have to do this for anything around sides (top, bottom, etc.)
The charts do not display in a '' tag. To get in-line charts, I am using table cells.
Here is the JSFiddle for it.
I managed to locate a closer example of what I'm looking for in Chart.JS
The issue remains that I still am unable achieve exactly what I'm looking for as once again, the line sizing seems to be directly proportional to the container. You can see this by resizing the window.
The question/problem: I am m looking for a library that gives me the ability to customize the line widths in semi-circular gauge/doughnut charts and not be auto-constrained to the chart's dimensions.
Any recommendations on another library that would give me what I'm looking for please?
There is more than one way to do it with amCharts 4, here is one:
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4charts.GaugeChart);
chart.innerRadius = am4core.percent(80);
var colorSet = new am4core.ColorSet();
var axis = chart.xAxes.push(new am4charts.ValueAxis());
axis.min = 0;
axis.max = 100;
axis.renderer.innerRadius = 10
axis.strictMinMax = true;
axis.renderer.labels.template.disabled = true;
axis.renderer.ticks.template.disabled = true;
axis.renderer.grid.template.disabled = true;
var range0 = axis.axisRanges.create();
range0.value = 0;
range0.endValue = 60;
range0.axisFill.fillOpacity = 1;
range0.axisFill.fill = colorSet.getIndex(0);
range0.grid.disabled = true;
var range1 = axis.axisRanges.create();
range1.value = 60;
range1.endValue = 100;
range1.axisFill.fillOpacity = 1;
range1.axisFill.fill = am4core.color("#DADADA");
range1.grid.disabled = true;
var axis2 = chart.xAxes.push(new am4charts.ValueAxis());
axis2.min = 0;
axis2.max = 100;
axis2.strictMinMax = true;
axis2.renderer.labels.template.disabled = true;
axis2.renderer.ticks.template.disabled = true;
axis2.renderer.grid.template.disabled = true;
var range2 = axis2.axisRanges.create();
range2.value = 0;
range2.endValue = 90;
range2.axisFill.fillOpacity = 1;
range2.axisFill.fill = colorSet.getIndex(3);
range2.axisFill.radius = am4core.percent(105);
range2.axisFill.innerRadius = am4core.percent(100); // set it to >100 if you'd like to have some gap between fills
range2.grid.disabled = true;
var range3 = axis2.axisRanges.create();
range3.value = 90;
range3.endValue = 100;
range3.axisFill.fillOpacity = 0.5;
range3.axisFill.fill = am4core.color("#DADADA");
range3.axisFill.radius = am4core.percent(105);
range3.axisFill.innerRadius = am4core.percent(100); // set it to >100 if you'd like to have some gap between fills
range3.grid.disabled = true;
var label = chart.radarContainer.createChild(am4core.Label);
label.isMeasured = false;
label.fontSize = 45;
label.x = am4core.percent(50);
label.y = am4core.percent(100);
label.horizontalCenter = "middle";
label.verticalCenter = "bottom";
label.text = "50%";
And this is a result: https://codepen.io/team/amcharts/pen/qgxyZK

How to change x-Axes label position in Chart.js

Is it possible to change the label position, like padding or margin in CSS?
I would like to have the labels above the x-Axes.
You can change the xAxes label positions with the following steps:
Add .getContext("2d") to the call that gets the ctx canvas object:
var ctx = document.getElementById("gescanntePackzettelChart").getContext("2d");
Hide the current xAxes ticks:
xAxes: [{
ticks: {
display: false
}
}
Add an animation to the options config, and use the canvas fillText() method to create new labels:
animation: {
duration: 1,
onComplete: function() {
var controller = this.chart.controller;
var chart = controller.chart;
var xAxis = controller.scales['x-axis-0'];
var numTicks = xAxis.ticks.length;
var xOffsetStart = xAxis.width / numTicks;
var halfBarWidth = (xAxis.width / (numTicks * 2));
xAxis.ticks.forEach(function(value, index) {
var xOffset = (xOffsetStart * index) + halfBarWidth;
var yOffset = chart.height - 20;
ctx.fillText(value, xOffset, yOffset);
});
}
}
For xOffset, to figure out the correct position, take the xAxis width and divide it by the number of tick labels. This will tell you how wide each bar is. Then, multiply that number by the current index to position the label in front of the correct bar. Finally, add add the width of half a bar to center the labels in the bar.
For the yOffset, start with the chart's height and subtract however much you want to move the labels up.
Working JSFiddle: https://jsfiddle.net/m5tnkr4n/124
Building on #Tot-Zam's response, it's possible to use the ChartJs scale object's methods to define the context pixel coordinates easier. You also don't need to define a ctx object - it is already accessible using the this.chart object.
animation: {
duration: 0,
onComplete: function() {
let chart = this.chart;
let controller = chart.controller;
let axis = controller.scales['x-axis-0'];
let yOffset = chart.height - 5;
axis.ticks.forEach(function(value, index) {
let xOffset = axis.getPixelForValue(value);
chart.ctx.fillText(value, xOffset, yOffset);
})
}
}
Working repl: https://repl.it/#lunarplasma/ChartJs-custom-axis-labels

Aligning a fabric.js object to the top left corner of the inner text of an IText element

http://jsfiddle.net/541ev5nh/15/
I'm attempting to align the red Text object to the upper-left corner of the black IText object. When the Itext object is not rotated (at angle 0), you can see that the text is correctly aligned. However, rotating the IText throws the alignment off.
Resizing or changing the text of the IText also throws off the alignment, but don't worry about that for now. The rotation is the only thing that needs to work right now.
The problem is obviously coming from the fact that I'm using magic numbers to align the two items. I need a formulaic way derive these numbers that will keep the alignment consistent when the IText is rotated. Any ideas?
HTML:
<canvas id="canvas" width="800" height="600" style=""></canvas>
Javascript:
var w = 800;
var h = 600;
var cx = w/2;
var cy = h/2;
var auto = false; // auto/manual rotation
// Main "Text"
var txt = "Text";
var canvas = new fabric.Canvas('canvas');
var text = new fabric.IText(txt, {
left: 20,
top: 30,
fontFamily: 'sans-serif',
fontSize: 80
});
canvas.add(text);
var pt = new fabric.Point(cx,cy);
text.setPositionByOrigin(pt, 'center', 'center');
canvas.setActiveObject(text);
// decorator
var txt = "Top left";
var deco = new fabric.Text(txt, {
left: 20,
top: 30,
fontFamily: 'sans-serif',
fontSize: 14,
stroke: '#DD0000',
fill: '#DD0000'
});
canvas.add(deco);
canvas.on('object:modified', onModified);
function onModified(data){
var rotatedPoint = data.target.getPointByOrigin("left", "top");
deco.rotate(data.target.angle);
deco.setPositionByOrigin(new fabric.Point(rotatedPoint.x + 1, rotatedPoint.y + 11), 'left', 'top');
canvas.renderAll();
}
var angle = -2;
if (auto){
setInterval(onInterval, 30);
}
else{
onInterval();
text.setCoords();
}
function onInterval(){
angle += 2;
text.rotate(angle);
var data = {
target: text
};
onModified (data);
}
You can achieve this by making objects group. Fabric has a nice support for object group.
See here:
// Main "Text"
var txt = "Text";
var canvas = new fabric.Canvas('canvas');
canvas.clear();
var text = new fabric.IText(txt, {
fontFamily: 'sans-serif',
fontSize: 80
});
// decorator
var txt = "Top left";
var deco = new fabric.Text(txt, {
top:10,
fontFamily: 'sans-serif',
fontSize: 14,
stroke: '#DD0000',
fill: '#DD0000'
});
var group = new fabric.Group([ text, deco ], {
angle: 0
});
var lefts=canvas.getWidth()/2-group.getWidth()/2;
var tops=canvas.getHeight()/2-group.getHeight()/2;
group.set({
'left':lefts,
'top':tops
});
canvas.add(group);
canvas.renderAll();
See in Fiddler

Snap svg dynamic : wrong positioning

With Snap SVG I am trying to create an rect dynamically.
When I click, it should create a rect at the position of the mouse click.
it's create the rect, BUT the postion is always wrong.
Here is my script : http://jsfiddle.net/noteStylet/L2kpd6yt/
So My question is Who to create a rect at the mouse click postion and not below.
HTML :
<h1>Click to create </h1>
<div>
<svg id="plan" width="900" height="500"></svg>
</div>
Javascript :
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
imagePlan.click(function (evt) {
//When click, create a rect
var rect1 = snap.rect(evt.clientX, evt.clientY, 40, 40);
});
Thanks !
We should use this method :
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = s.rect(transformed.x, transformed.y, 40, 40);
instead of
var rect1 = snap.rect(evt.clientX, evt.clientY, 40, 40);
We have to use :
var mySvg = $("#svg1")[0];
var pt = mySvg.createSVGPoint(); // create the point;
imagePlan.click(function(evt)
{
pt.x = evt.x;
pt.y = evt.y;
// convert the mouse X and Y so that it's relative to the svg element
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = s.rect(transformed.x, transformed.y, 40, 40);
});
Here is the Example : http://jsfiddle.net/noteStylet/L2kpd6yt/6/
Your problem is the grid system of the svg you need to re-abjust it so that your mouse is not the (0,0) but rather the (-20,-80).
change the rect creation code to :
var rect1 = snap.rect(evt.clientX-20, evt.clientY-80, 40, 40);
and it should work
update:
Ok so what you need is 1.get mouse position and 2.the position of the image ( left & top values). Then subtract them from current mouse position so you can adjust the svg grid to feet your needs
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
var currentMousePos = { x: -1, y: -1 };
$(document).mousemove(function(event) {
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
var image = $( "#plan" );
var position = image.position();
imagePlan.click(function()
{
//When click, create a rect
var rect1 = snap.rect(currentMousePos.x-position.left ,currentMousePos.y-position.top, 40, 40);
});
});

Categories