I have developed my circular progress bar from angular-circular-progress github.
My current input was:
I need to modify the end of the progress bar with a small CIRCLE and a VALUE CENTRE of the circular progress bar with real animation value based on svg movement. How I can do that? I really need help from you all guys.
My expected output should be:
My current snippet:
angular.module('myModule', ['angular-circular-progress'])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://pencil.my/assets/js/circularProgress.js"></script>
<div ng-app="myModule">
<circular-progress
value="80"
max="100"
orientation="1"
radius="100"
stroke="10"
base-color="#fff"
progress-color="#f9991d"
iterations="100"
animation="easeInOutCubic"
></circular-progress>
</div>
Have you look at ProgressBar.js ?
var bar = new ProgressBar.Circle(container, {
enter code herecolor: '#aaa',
// This has to be the same size as the maximum width to
// prevent clipping
strokeWidth: 4,
trailWidth: 1,
easing: 'easeInOut',
duration: 1400,
text: {
autoStyleContainer: false
},
from: { color: '#aaa', width: 1 },
to: { color: '#333', width: 4 },
// Set default step function for all animate calls
step: function(state, circle) {
circle.path.setAttribute('stroke', state.color);
circle.path.setAttribute('stroke-width', state.width);
var value = Math.round(circle.value() * 100);
if (value === 0) {
circle.setText('');
} else {
circle.setText(value);
}
Here is a Fiddle
Regards,
Alex
Create a group that has a transparent object the size of your circle and has the small circle at one edge, then rotate that group around its center. The internals of the SVG would look something like
<g id="pip" transform="rotate({{360/value}}, 50, 50)">
<!--contents of g-->
</g>
This assumes the diameter of the circle is 100.
Here is a function that converts a number from 0 to 100 into the x,y coordinates needed to give the circle object (drawn with canvas tools) a circular path:
function drawCircle(percentage, ctx) {
var angle = percentage / 100.0;
var xPos = 140 * Math.cos((angle * (2 * Math.PI)) - (Math.PI * .5));
var yPos = -140 * Math.sin((angle * (2 * Math.PI)) - (Math.PI * .5) );
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.beginPath();
ctx.arc (xPos + 150, 150 - yPos, 10, 0, 2 * Math.PI);
ctx.stroke();
}
Look at this plunker to see it in action:
https://plnkr.co/edit/ePMK7DVLB3OH15oUJzr1?p=preview
This takes the number (from 0 to 100), scales it, converts it to radians, then converts the radians to cartesian coordinates.
Related
I'm using the scale feature in the 2D Context to scale in-game tiles to fit the screen, however the scaling integer has to be a float to make this happen. Due to this tiles are rendered so that in certain positions you can see lines in the air or inbetween tiles. On some screens screen tearing is minimal but on some is very apparent.
Scaling code: context.scale(this.camera.scale, this.camera.scale);
How scale is measured: window.innerHeight/672 * 3;
Note: Dividing by 672, since when divided by 48 (game units) results in 14, which is the general zone height.
What happens:
Please help!
Yes that can happen using scale, but instead you can do the scaling yourself, it's just a multiplication and rounding to keep numbers nice and integer...
Here is the a nice visual showing the difference between the two methods:
Sample code below:
var ctx1 = document.getElementById('canvas1').getContext('2d');
var ctx2 = document.getElementById('canvas2').getContext('2d');
var rect = { x: 10, y: 10, w: 50, h: 50 }
const scale = 0.63517
function drawRects(ctx, pos) {
ctx.fillRect(pos.x, pos.y, pos.w, pos.h);
ctx.fillRect(pos.x, pos.y + pos.h, pos.w, pos.h);
ctx.fillRect(pos.x + pos.w, pos.y + pos.h / 4, pos.w, pos.h);
}
function draw1() {
ctx1.scale(scale, scale);
drawRects(ctx1, rect)
}
function draw2() {
scaled_rect = {
x: Math.round(rect.x * scale),
y: Math.round(rect.y * scale),
w: Math.round(rect.w * scale),
h: Math.round(rect.h * scale)
}
drawRects(ctx2, scaled_rect)
}
draw1()
draw2()
canvas {
border: solid 1px red
}
<canvas id="canvas1" width=80 height=80></canvas>
<canvas id="canvas2" width=80 height=80></canvas>
I have a problem with ChartJS: I need to use a Polar graph for my project and I have to show this graphic in a PDF.
I also need to display the tooltips without hover. The problem is that these tooltips are at the center of each data.
I want this specific one to be found outside of the graph. I modified the Chart.js a lot and now I have:
Unfortunately when the labels are long, the display is not good:
My method is not good. Has someone already managed to display tooltips outside the circle?
Currently the center of your label text is at the position where you want to show the label. If you change it to the start of your label or end of your label for labels on the right and left of your chart, you'll have much better layout.
You could also align your labels closer to the sector end point instead of the outermost edge of the scale.
Here's how you do it
1. Override your scale
So that the chart does not take up the full canvas. I've hardcoded these values for a sample dataset, you could just as easily use the input data to get suitable values
scaleOverride: true,
scaleStartValue: 0,
scaleStepWidth: 40,
scaleSteps: 10,
2. Draw your Labels
The best place would be the end of your animation.
onAnimationComplete: function () {
this.segments.forEach(function (segment) {
Figure out the outer edge of each sector - this is not that difficult. We just use the same function that the tooltip position uses
var outerEdge = Chart.Arc.prototype.tooltipPosition.apply({
x: this.chart.width / 2,
y: this.chart.height / 2,
startAngle: segment.startAngle,
endAngle: segment.endAngle,
outerRadius: segment.outerRadius * 2 + 10,
innerRadius: 0
})
outerRadius decides how far away from the center you want your labels to appear. The x 2 is because the tooltip normally appears in the middle of the sector. The + 10 is padding so that the label does not stick too close to end of the sector
If you want the labels to all appear on the outer edge of the scale use outerRadius = self.scale.drawingArea * 2 (with self set to the Chartjs chart object)
3. Set the text alignment
This is based on whether you are on the right or left side of the graph (or the top or bottom).
For this, first normalize the angle (so that it is within 0 to 2 * PI)
var normalizedAngle = (segment.startAngle + segment.endAngle) / 2;
while (normalizedAngle > 2 * Math.PI) {
normalizedAngle -= (2 * Math.PI)
}
Then simply set the text position depending on the range of the angle (0 radians is on the right side middle and the radians increase anticlockwise).
if (normalizedAngle < (Math.PI * 0.4) || (normalizedAngle > Math.PI * 1.5))
ctx.textAlign = "start";
else if (normalizedAngle > (Math.PI * 0.4) && (normalizedAngle < Math.PI * 0.6)) {
outerEdge.y += 5;
ctx.textAlign = "center";
}
else if (normalizedAngle > (Math.PI * 1.4) && (normalizedAngle < Math.PI * 1.6)) {
outerEdge.y -5;
ctx.textAlign = "center";
}
else
ctx.textAlign = "end";
The "center" makes labels that appear near the top and bottom of the graph have the middle of their text align to the sector edge. The +5 and -5 are padding so that they don't stick too close.
ctx.fillText(segment.label, outerEdge.x, outerEdge.y);
Fiddle - http://jsfiddle.net/nyjodx4v/
And here's how it looks
i am using the latest version of kineticJs, right now I am doing puzzle games, which requires my puzzle pieces to rotate after scramble, anyone have any idea how to rotate different angle and not 2-3 pieces rotate of the same angle? thanks :)
fillPatternImage:imageObj,
fillPatternOffsetX :i * pieceWidth,
fillPatternOffsetY :j * pieceHeight,
stroke: "#000000",
strokeWidth: 4,
lineCap: "round",
rotation : Math.PI * 28.5 * Math.floor(Math.random() * 2), <-- rotation part
draggable: true,
offset : [ pieceWidth / 2 + pieceWidth * 0.3,pieceHeight / 2 + pieceHeight * 0.3 ],
x:0+ (Math.random()*6)*((stage.getWidth()+pieceWidth)/16),
y:0+ (Math.random()*4)*((stage.getHeight()+pieceHeight)/16),
My fiddle : http://jsfiddle.net/e70n2693/34/
the code Math.floor(Math.random() * 2) gives either 0 or 1, which is then multiplied by PI*28.5, giving either a rotation of 0 or PI*28.5.
increase the multiplier of Math.random() to desired number of possible rotations.
you may have to change the value multiplying PI also to give a better spread of possible angles (reduce it)
something like below should give a wider range of results
var numberOfDifferentAngles = 50;
var differenceBetweenAngles = Math.PI * 2;
rotation : differenceBetweenAngles
* Math.floor(Math.random() * numberOfDifferentAngles ),
I am working on a progress bar plugin for jQuery that utilizes Raphael for smooth graphics.
I tried to transform the attribute function provided by this Raphael example (polar clock).
The problem is, that at first I didn't notice that the Raphael example also has the deformation error there. Relatively larger circles just mitigate it. Looking at smaller ones, it is noticeable.
And yes, I have basicly copy-pasted the function with some minor tweaks, but the end result sport the same error.
I have set up a JSBin where I've added reference circles to my scene, so it's easier to spot the issue: http://jsbin.com/ekovir/1
How do I tune the Arc function to draw proper circle?
I think it's a bug in Chrome's SVG rendering implementation. At least in FireFox and Safari it looks much better.
Also, when selecting the arc-to point, I think it's better to use (center.x + radius * cos(a-0.01), center.y + radius * sin(a-0.01)), instead of (center.x + radius * cos(a) - 0.01, center.y + radius * sin(a)), otherwise the center may shift a bit.
As a workaround, I suggest creating one set of segments for the progress bar and then changing their color as the work is done, instead of drawing new ones over the old. This should look fine in any browser, and I don't think the defects are easy to spot without the contrasting background circle.
I have found what caused the circle to be deformed.
I used stroke-width to set the "fatness" / "cap" of the circle, and the larger it gets, the more it deforms.
At least, those are my observations, it could as well technically be caued by something else.
Anyways, in order to get proper donut, I ended up with this method:
/**
* Donut circle drawing
*
* #param integer start Percentage to start with
* #param float diameter
* #param float fat How fat should the circle bar be
* #return object
*/
var fatDonutArc = function (start, diameter, fat)
{
var center = diameter / 2;
var outerRadius = center;
var innerRadius = center - fat; // subtract fat
var alpha = 360 / 100 * start;
var a = (90 - alpha) * Math.PI / -180; // -180 starts to draw from 12 o'clock
// calculate outer ring point coordinates
var outerX = center + outerRadius * Math.cos(a);
var outerY = center + outerRadius * Math.sin(a);
// calculate inner ring point coordinates
var innerX = center + innerRadius * Math.cos(a);
var innerY = center + innerRadius * Math.sin(a);
// path cache
var path;
if (start !== 100)
{
path = [
// move to start point of inner ring
[
"M",
center,
center - innerRadius
],
// draw a line to outer ring
[
"L",
center,
center - outerRadius
],
// arc to outer ring end
[
"A",
outerRadius,
outerRadius,
0,
+(alpha > 180),
1,
outerX,
outerY
],
// move to inner ring end
[
"L",
innerX,
innerY
],
// arc to inner ring start
[
"A",
innerRadius,
innerRadius,
0,
+(alpha > 180),
0,
center,
center - innerRadius
]
];
}
else
{
path = [
// move to outer ring start
[
"M",
center,
center - outerRadius
],
// arc around the clock
[
"A",
outerRadius,
outerRadius,
0,
+(alpha > 180),
1,
outerX - .1, // subtract, otherwise the path becomes "reset"
outerY
],
// connect
[
"z"
],
// move to inner circle start
[
"M",
innerX,
innerY
],
// arc around the clock
[
"A",
innerRadius,
innerRadius,
0,
+(alpha > 180),
0,
innerX + .1, // subtract, otherwise the path becomes "reset"
innerY
],
// and connect
[
"z"
]
];
}
return {
path : path
};
};
That's a mashup of: raphael.js - converting pie graph to donut graph + http://raphaeljs.com/polar-clock.html
Here I have set up an example, to see it in action: http://jsbin.com/erusos/1
There still is one unanswered question: In Chrome, is it the CSS renderer, that doesn't fully round the circle, or is it the SVG?
Enjoy!
I'm trying to do something I thought would be rather simple. I've an object that I move around stepwise, i.e. I receive messages every say 100 milliseconds that tell me "your object has moved x pixels to the right and y pixels down". The code below simulates that by moving that object on a circle, but note that it is not known in advance where the object will be heading in the next step.
Anyway, that is pretty simple. But now I want to also tell the object, which is actually a set of subobjects, that it is being rotated.
Unfortunately, I am having trouble getting Raphaël to do what I want. I believe the reason is that while I can animate both translation and rotation independently, I have to set the center of the rotation when it starts. Obviously the center of the rotation changes as the object is moving.
Here's the code I'm using and you can view a live demo here. As you can see, the square rotates as expected, but the arrow rotates incorrectly.
// c&p this into http://raphaeljs.com/playground.html
var WORLD_SIZE = 400,
rect = paper.rect(WORLD_SIZE / 2 - 20, 0, 40, 40, 5).attr({ fill: 'red' }),
pointer = paper.path("M 200 20 L 200 50"),
debug = paper.text(25, 10, ""),
obj = paper.set();
obj.push(rect, pointer);
var t = 0,
step = 0.05;
setInterval(function () {
var deg = Math.round(Raphael.deg(t));
t += step;
debug.attr({ text: deg + '°' });
var dx = ((WORLD_SIZE - 40) / 2) * (Math.sin(t - step) - Math.sin(t)),
dy = ((WORLD_SIZE - 40) / 2) * (Math.cos(t - step) - Math.cos(t));
obj.animate({
translation: dx + ' ' + dy,
rotation: -deg
}, 100);
}, 100);
Any help is appreciated!
If you want do a translation and a rotation too, the raphael obj should be like that
obj.animate({
transform: "t" + [dx , dy] + "r" + (-deg)
}, 100);
Check out http://raphaeljs.com/animation.html
Look at the second animation from the top on the right.
Hope this helps!
Here's the code:
(function () {
var path1 = "M170,90c0-20 40,20 40,0c0-20 -40,20 -40,0z",
path2 = "M270,90c0-20 40,20 40,0c0-20 -40,20 -40,0z";
var t = r.path(path1).attr(dashed);
r.path(path2).attr({fill: "none", stroke: "#666", "stroke-dasharray": "- ", rotation: 90});
var el = r.path(path1).attr({fill: "none", stroke: "#fff", "stroke-width": 2}),
elattrs = [{translation: "100 0", rotation: 90}, {translation: "-100 0", rotation: 0}],
now = 0;
r.arrow(240, 90).node.onclick = function () {
el.animate(elattrs[now++], 1000);
if (now == 2) {
now = 0;
}
}; })();