SNAP.svg animate path clockwise - animation

I am trying to animate a donut using SNAP.svg. I am using the SNAP.animate function to calculate the path values. The problem is path is drawn from endAngle to startAngle, but I want the reverse of it.
Here is the codepen link http://codepen.io/junedchhipa/pen/qaeePP
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#chart {
text-align: center;
width: 100%;
margin-top: 60px;
margin-bottom: 60px;
margin-left: auto;
margin-right: auto;
padding: 0 0 0 25%;
height: 600px;
}
</style>
</head>
<body>
<svg id="chart"></svg>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<script>
var s = Snap("#chart");
var centerX = 279.6666666666667,
centerY = 279.6666666666667,
colors = ["#2b908f", "#f9a3a4", "#90ee7e", "#fa4443", "#69d2e7"],
x1 = [398.2520587792069, 418.9678919498291, 162.3925655822982, 227.28417802067494, 279.6666666666667],
y1 = [ 205.56628955139018, 291.8539446942142, 355.825358396268, 150.01545766974425, 139.83333333333334],
endAngle = [58, 95, 237, 338, 360],
startAngle = [0, 58, 95, 237, 338],
percent = [ 16.11111111111111, 10.277777777777777, 39.44444444444444, 28.055555555555557, 6.111111111111111],
begin = [0,1280,2560,3840,5120],
dur = 1280;
for(var i=0; i<5; i++) {
var el = s.path("");
el.node.id = "w" + i;
animateDonut(el, x1[i], y1[i], centerX, centerY, endAngle[i], startAngle[i], 139.833, percent[i], begin[i], dur, colors[i])
}
function animateDonut(el, x1, y1, centerX, centerY, endAngle, startAngle, size, percent, begin, dur, color ) {
window.setTimeout(function() {
var endpoint = (percent/100)*360;
Snap.animate(0, endpoint, function (val) {
var d = endAngle - val,
dr = d-90,
radians = Math.PI*dr/180,
x2 = centerX + size*Math.cos(radians),
y2 = centerY + size*Math.sin(radians),
largeArc = val>180 ? 1 : 0,
path = "M"+x1+","+y1+" A"+size+","+size+" 0 "+largeArc+",0 "+x2+","+y2;
el.attr({
d: path,
stroke: color,
fill: 'none',
strokeWidth: 40
});
console.log(el.node.getAttribute('id'),d)
},dur, mina.easeinout);
}, begin)
}
</script>
</html>

Nevermind, played with the StartAngle values and got it working.
Updated codepen http://codepen.io/junedchhipa/pen/qaeePP
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#chart {
text-align: center;
width: 100%;
margin-top: 60px;
margin-bottom: 60px;
margin-left: auto;
margin-right: auto;
padding: 0 0 0 25%;
height: 600px;
}
</style>
</head>
<body>
<svg id="chart"></svg>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
<script>
var s = Snap("#chart");
var centerX = 279.6666666666667,
centerY = 279.6666666666667,
colors = ["#2b908f", "#f9a3a4", "#90ee7e", "#fa4443", "#69d2e7"],
x1 = [398.2520587792069, 418.9678919498291, 162.3925655822982, 227.28417802067494, 279.6666666666667],
y1 = [ 205.56628955139018, 291.8539446942142, 355.825358396268, 150.01545766974425, 139.83333333333334],
endAngle = [58, 95, 237, 338, 360],
startAngle = [0, 58, 95, 237, 338],
percent = [ 16.11111111111111, 10.277777777777777, 39.44444444444444, 28.055555555555557, 6.111111111111111],
begin = [0,500,1000,1500,2000],
dur = 500;
for(var i=0; i<5; i++) {
var el = s.path("");
el.node.id = "w" + i;
animateDonut(el, x1[i], y1[i], centerX, centerY, endAngle[i], startAngle[i], 139.833, percent[i], begin[i], dur, colors[i])
}
function animateDonut(el, x1, y1, centerX, centerY, endAngle, startAngle, size, percent, begin, dur, color ) {
window.setTimeout(function() {
var endpoint = (percent/100)*360;
Snap.animate(0, endpoint, function (val) {
var startDeg = startAngle,
startRadians = Math.PI*(startDeg-90)/180,
endDeg = startDeg + val,
endRadians = Math.PI*(endDeg-90)/180,
x1 = centerX + size*Math.cos(startRadians),
y1 = centerY + size*Math.sin(startRadians),
x2 = centerX + size*Math.cos(endRadians),
y2 = centerY + size*Math.sin(endRadians),
largeArc = val>180 ? 1 : 0,
path = "M"+x1+","+y1+" A"+size+","+size+" 0 "+largeArc+",1 "+x2+","+y2;
el.attr({
d: path,
stroke: color,
fill: 'none',
strokeWidth: 40
});
console.log(el.node.getAttribute('id'),"startDeg",startDeg)
console.log(el.node.getAttribute('id'),"endDeg",endDeg)
},dur, mina.easeinout);
}, begin)
}
</script>
</html>

Related

How to fit and center-align Pixi.js stage in the maximized canvas element?

I have prepared a complete jsfiddle for my question -
For a board game I am trying to use jQuery UI buttons on both sides and assign the rest of the screen to the Pixi drawing area.
I have found a suggestion by a Pixi.js developer to scale the stage, so that its children are scaled automatically and below I am trying to implement it:
$(function() {
var WIDTH = 400;
var HEIGHT = 400;
var RATIO = WIDTH / HEIGHT;
var scaleX = 1,
scaleY = 1,
offsetX = 0,
offsetY = 0,
oldX, oldY;
var app = new PIXI.Application({
width: WIDTH,
height: HEIGHT,
view: document.getElementById('pixiCanvas'),
backgroundColor: 0xFFFFFF
});
app.stage.interactive = true;
app.stage.on('pointerdown', onDragStart)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd)
.on('pointermove', onDragMove);
var background = new PIXI.Graphics();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
if ((i + j) % 2 == 0) {
background.beginFill(0xCCCCFF);
background.drawRect(i * WIDTH / 8, j * HEIGHT / 8, WIDTH / 8, HEIGHT / 8);
background.endFill();
}
}
}
app.stage.addChild(background);
var bunny = PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png');
bunny.anchor.set(0.5);
bunny.scale.set(2);
bunny.x = WIDTH / 2;
bunny.y = HEIGHT / 2;
app.stage.addChild(bunny);
function onDragStart(ev) {
var stagePoint = ev.data.getLocalPosition(app.stage);
if (bunny.getBounds().contains(stagePoint.x, stagePoint.y)) {
bunny.alpha = 0.5;
oldX = stagePoint.x;
oldY = stagePoint.y;
this.data = ev.data;
}
}
function onDragMove() {
if (this.data) {
var stagePoint = this.data.getLocalPosition(app.stage);
bunny.x += stagePoint.x - oldX;
bunny.y += stagePoint.y - oldY;
oldX = stagePoint.x;
oldY = stagePoint.y;
}
}
function onDragEnd() {
if (this.data) {
bunny.alpha = 1;
var stagePoint = this.data.getLocalPosition(app.stage);
this.data = null;
}
}
$(':button').button();
$('#scaleCheck').checkboxradio();
window.onresize = function() {
if (!$('#scaleCheck').prop('checked')) {
return;
}
var canvasRatio = $('#pixiCanvas').width() / $('#pixiCanvas').height();
if (canvasRatio > RATIO) { // if canvas is too wide
scaleX = 1 / canvasRatio;
scaleY = 1;
offsetX = 0;
offsetY = 0;
} else {
scaleX = 1;
scaleY = canvasRatio;
offsetX = 0;
offsetY = 0;
}
app.stage.scale.set(scaleX, scaleY);
app.stage.position.set(offsetX, offsetY); // how to center-align?
}
window.onresize();
});
body {
margin: 0;
padding: 0;
}
#mainDiv {
width: 100%;
height: 100vh;
background: #FFF;
display: flex;
}
#leftMenuDiv {
text-align: center;
background: #FCC;
}
#rightMenuDiv {
text-align: center;
background: #CFC;
flex-shrink: 1;
}
#canvasDiv {
flex-grow: 1;
}
#pixiCanvas {
width: 100%;
height: 100%;
background: #CCF;
box-sizing: border-box;
border: 4px red dotted;
}
<div id="mainDiv">
<div id="leftMenuDiv">
<button id="btn1">Button 1</button><br>
<button id="btn2">Button 2</button><br>
<button id="btn3">Button 3</button><br>
</div>
<div id="canvasDiv">
<canvas id="pixiCanvas"></canvas>
</div>
<div id="rightMenuDiv">
<input id="scaleCheck" type="checkbox">
<label for="scaleCheck">Fit and center Pixi stage</label><br>
<button id="btn4">Button 4</button><br>
<button id="btn5">Button 5</button><br>
<button id="btn6">Button 6</button><br>
</div>
</div>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/pixi.js#5.3.3/dist/pixi.min.js"></script>
My problem with the above code is the following -
When you first run my code, it works. But after you set the checkbox and resize browser window, dragging will break.
I have been able to solve my problem by the following code:
$(function() {
var WIDTH = 400;
var HEIGHT = 400;
var RATIO = WIDTH / HEIGHT;
var scaleX = 1, scaleY = 1, offsetX = 0, offsetY = 0;
var app = new PIXI.Application({
width: WIDTH,
height: HEIGHT,
view: document.getElementById('pixiCanvas'),
backgroundColor: 0xFFFFFF
});
var background = new PIXI.Graphics();
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
if ((i + j) % 2 == 0) {
background.beginFill(0xCCCCFF);
background.drawRect(i * WIDTH / 8, j * HEIGHT / 8, WIDTH / 8, HEIGHT / 8);
background.endFill();
}
}
}
app.stage.addChild(background);
var bunny = PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png');
bunny.interactive = true;
bunny.buttonMode = true;
bunny.anchor.set(0.5);
bunny.scale.set(2);
bunny.x = WIDTH / 2;
bunny.y = HEIGHT / 2;
bunny.on('pointerdown', onDragStart)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd)
.on('pointermove', onDragMove);
app.stage.addChild(bunny);
function onDragStart(ev) {
this.data = ev.data;
this.alpha = 0.5;
}
function onDragMove() {
if (this.data) {
var newPos = this.data.getLocalPosition(this.parent);
this.x = newPos.x;
this.y = newPos.y;
}
}
function onDragEnd() {
if (this.data) {
this.alpha = 1;
this.data = null;
}
}
$(':button').button();
$('#scaleCheck').checkboxradio();
window.onresize = function() {
if (!$('#scaleCheck').prop('checked')) {
return;
}
var canvasRatio = $('#pixiCanvas').width() / $('#pixiCanvas').height();
if (canvasRatio > RATIO) { // if canvas is too wide
scaleX = RATIO / canvasRatio;
scaleY = 1;
offsetX = (1 - scaleX) * WIDTH / 2;
offsetY = 0;
} else {
scaleX = 1;
scaleY = canvasRatio / RATIO;
offsetX = 0;
offsetY = (1 - scaleY) * HEIGHT / 2;
}
app.stage.scale.set(scaleX, scaleY);
app.stage.position.set(offsetX, offsetY);
}
window.onresize();
});
body {
margin: 0;
padding: 0;
}
#mainDiv {
width: 100%;
height: 100vh;
background: #FFF;
display: flex;
}
#leftMenuDiv {
text-align: center;
background: #FCC;
}
#rightMenuDiv {
text-align: center;
background: #CFC;
flex-shrink: 1;
}
#canvasDiv {
flex-grow: 1;
}
#pixiCanvas {
width: 100%;
height: 100%;
background: #CCF;
box-sizing: border-box;
border: 4px red dotted;
}
<div id="mainDiv">
<div id="leftMenuDiv">
<button id="btn1">Button 1</button><br>
<button id="btn2">Button 2</button><br>
<button id="btn3">Button 3</button><br>
</div>
<div id="canvasDiv">
<canvas id="pixiCanvas"></canvas>
</div>
<div id="rightMenuDiv">
<input id="scaleCheck" type="checkbox" checked>
<label for="scaleCheck">Fit and center Pixi stage</label><br>
<button id="btn4">Button 4</button><br>
<button id="btn5">Button 5</button><br>
<button id="btn6">Button 6</button><br>
</div>
</div>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/pixi.js#5.3.3/dist/pixi.min.js"></script>
The main change for me has been to make the draggable sprite interactive and add drag listeners to it - instead of the app.stage.
Maybe app.stage could be interactive as well as in my original code? I think there is some matrix calculation required there in that case, that is why the math is difficult to figure out.

Fabric.js - Rotate change the position of object

I would rotate an object on FabricJS canvas, but when I rotate, its position changed. And I can't use center origin, just left/top, beacuse I save coordinates to database reference by left/top position.
Can you help me? Any idea?
Here is the example.
Thanks
var canvas = window._canvas = new fabric.Canvas('c');
canvas.add(new fabric.Triangle({
width: 100,
height: 100,
left: 0,
top: 0,
angle: 0,
fill: '#00AC6B'
}));
function rotateObject(angleOffset) {
var obj = canvas.getActiveObject();
if (!obj) return;
var angle = obj.getAngle() + angleOffset;
angle = angle > 360 ? 90 : angle < 0 ? 270 : angle;
obj.setAngle(angle).setCoords();
canvas.renderAll();
document.getElementById('log').innerHTML += 'Left: ' + obj.left + ', top: ' + obj.top + '<br>';
}
fabric.util.addListener(document.getElementById('rotate-left'), 'click', function () {
rotateObject(-90);
});
fabric.util.addListener(document.getElementById('rotate-right'), 'click', function () {
rotateObject(90);
});
canvas {
border: 1px solid #999;
}
.log {
height: 220px;
overflow: auto;
border: 1px solid #999;
padding: 5px;
margin-top: 10px;
}
<script src="https://rawgit.com/kangax/fabric.js/1.x/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>
<div>
<button id="rotate-left">Rotate left</button>
<button id="rotate-right">Rotate right</button>
</div>
<div id="log" class="log">
</div>

Parallax effect - calculate child offset to parent on scroll

I'm trying to create a parallax effect whereby an absolutely positioned child element should move at a rate slower than it's parent on scroll.
The child will always be 130% height of the parent but the parent can be any height:
HTML:
<div class="parallax-window lg">
<div class="parallax-image image-1"></div>
<div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window">
<div class="parallax-image image-2"></div>
<div class="parallax-content">Hello World</div>
</div>
CSS:
.parallax-window {
min-height: 300px;
position: relative;
overflow: hidden;
}
.parallax-window.lg {
min-height: 600px;
}
.parallax-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 130%;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
transform: translate3d(0, 0, 0);
z-index: -1;
}
.image-1 {
background-image: url(https://i.ytimg.com/vi/TbC-vUPMR7k/maxresdefault.jpg);
}
.image-2 {
background-image: url(https://i.ytimg.com/vi/xi5-YrAEChc/maxresdefault.jpg);
}
I have a formula to move the image but my maths is clearly way off:
var win = $(window),
win_h = win.height(),
parallaxers = $('.parallax-window');
function scroll_events() {
var win_top = win.scrollTop(),
win_btm = win_top + win_h;
parallaxers.each(function() {
var cont = $(this),
cont_top = cont.offset().top,
cont_h = cont.height(),
cont_btm = cont_top + cont_h,
para = cont.find('.parallax-image'),
para_h = Math.round(cont_h * 1.3);
if (cont_btm > win_top && cont_top <= win_btm) {
var diff = (win_h - cont_h) / (win_h - para_h),
value = -Math.round((win_top * diff));
// para.css('transform', 'translate3d(0,' + value*-1 + 'px, 0)');
para.css('top', value + 'px');
}
});
}
The images move but not at the correct rate.
The image should be in line with the top of the parent when the element first comes into the viewport. Then after scrolling, the bottom of the image should be in line with the bottom of the parent when it reaches the top of the viewport.
Any help would be massively appreciated!
FIDDLE (https://jsfiddle.net/8dwLwgy7/1/)
I figured this out.
For anyone stumbling on this in the future - the trick was to replace the window scrolled value with the remainder of the window scrolled amount minus the element's offset top, minus the height of the element.
Then calculate the speed by dividing the difference between the container height and the element height with largest of either the window and the container:
// Wrong:
// value = -Math.round((win_top * diff));
// Right:
var diff = elem_h - cont_h,
max = Math.max(cont_h, win_h),
speed = diff / max,
cont_scrolled = win_top - cont_top - cont_h,
value = Math.round(cont_scrolled * speed);
para.css('top', value + 'px');
Full working code:
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
},
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
(function($) {
var win = $(window),
win_h = win.height();
parallaxers = $('.parallax-window'),
parallax_objs = [],
scroll_busy = false;
function init_parallax() {
win_h = win.height();
parallax_objs = [];
parallaxers.each(function() {
var cont = $(this),
elem = cont.find('.parallax-image'),
cont_top = cont.offset().top,
cont_h = cont.height(),
elem_h = Math.round(cont_h * 1.3),
diff = elem_h - cont_h,
max = Math.max(cont_h, win_h),
speed = diff / max,
parallaxer = {
cont_top: cont_top,
cont_h: cont_h,
elem: elem,
speed: speed
};
parallax_objs.push(parallaxer);
});
}
function on_scroll() {
if (!scroll_busy) {
scroll_busy = true;
window.requestAnimationFrame(init_scroll);
}
}
function init_scroll() {
scroll_events()
scroll_busy = false;
}
function scroll_events() {
var win_top = win.scrollTop(),
win_btm = win_top + win_h;
$.each(parallax_objs, function(i, para) {
cont_btm = para.cont_top + para.cont_h;
if( cont_btm > win_top && para.cont_top <= win_btm ) {
var cont_scrolled = win_top - para.cont_top - para.cont_h,
value = Math.round(cont_scrolled * para.speed);
para.elem.css('top', value + 'px');
}
});
}
$(document).ready(function() {
init_parallax();
win.resize(init_parallax);
scroll_events();
win.scroll(on_scroll);
});
})(jQuery);
.parallax-window {
min-height: 300px;
position: relative;
overflow: hidden;
}
.parallax-window.lg {
min-height: 600px;
}
.parallax-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 130%;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
transform: translate3d(0, 0, 0);
z-index: -1;
}
.image-1 {
background-image: url(https://i.ytimg.com/vi/TbC-vUPMR7k/maxresdefault.jpg);
}
.image-2 {
background-image: url(https://i.ytimg.com/vi/xi5-YrAEChc/maxresdefault.jpg);
}
.parallax-content {
position: absolute;
top: 50%;
left: 0;
width: 100%;
text-align: center;
font-family: arial, sans-serif;
font-size: 60px;
color: #fff;
transform: translateY(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="parallax-window lg">
<div class="parallax-image image-1"></div>
<div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window">
<div class="parallax-image image-2"></div>
<div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window lg">
<div class="parallax-image image-1"></div>
<div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window">
<div class="parallax-image image-2"></div>
<div class="parallax-content">Hello World</div>
</div>
<div class="parallax-window lg">
<div class="parallax-image image-1"></div>
<div class="parallax-content">Hello World</div>
</div>
Updated Fiddle: https://jsfiddle.net/8dwLwgy7/2/

How to rotate the text labels for the x Axis of a nvd3.js line chart

I am new to nvd3 and d3 js.I am creating a line chart using nvd3. Now i want to rotate the text labels for the x Axis of the line chart.How to implement this?
I tried using
var xTicks = d3.selectAll('g.tick');
xTicks
.selectAll('text')
.attr('transform', function(d,i,j) { return ' rotate(-90 0,0)' }) ;
but was unsuccessful
My current code is
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="../build/nv.d3.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8"></script>
<script src="../build/nv.d3.js"></script>
<style>
text {
font: 12px sans-serif;
}
svg {
display: block;
}
html, body, #chart1, svg {
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
}
.dashed {
stroke-dasharray: 5,5;
}
</style>
<script type="text/javascript">
function download()
{
img = new Image(),
serializer = new XMLSerializer(),
svgStr = serializer.serializeToString(document.getElementById('svg'));
img.src = 'data:image/svg+xml;base64,'+window.btoa(svgStr);
// You could also use the actual string without base64 encoding it:
//img.src = "data:image/svg+xml;utf8," + svgStr;
var canvas = document.createElement("canvas");
var w=3000;
var h=3000;
canvas.width = w;
canvas.height = h;
canvas.getContext("2d").drawImage(img,0,0,w,h);
var imgURL = canvas.toDataURL("image/png");
var dlLink = document.createElement('a');
dlLink.download = "image";
dlLink.href = imgURL;
dlLink.dataset.downloadurl = ["image/png", dlLink.download, dlLink.href].join(':');
document.body.appendChild(dlLink);
dlLink.click();
document.body.removeChild(dlLink);
}
</script>
</head>
<body class='with-3d-shadow with-transitions'>
<div style="position:absolute; top: 0; left: 0;">
<button onclick="randomizeFillOpacity();">Randomize fill opacity</button>
<button onclick="expandLegend();">Expand/Contract Legend</button>
<script>
var expandLegend = function() {
var exp = chart.legend.expanded();
chart.legend.expanded(!exp);
chart.update();
}
</script>
</div>
<div id="chart1" width="100%" height='100%'></div>
<button onclick="download()">Download</button>
<script>
// Wrapping in nv.addGraph allows for '0 timeout render', stores rendered charts in nv.graphs, and may do more in the future... it's NOT required
var chart;
var data;
var randomizeFillOpacity = function() {
var rand = Math.random(0,1);
for (var i = 0; i < 100; i++) { // modify sine amplitude
data[4].values[i].y = Math.sin(i/(5 + rand)) * .4 * rand - .25;
}
data[4].fillOpacity = rand;
chart.update();
};
nv.addGraph(function() {
chart = nv.models.lineChart()
.options({
transitionDuration: 300,
useInteractiveGuideline: true
})
;
// chart sub-models (ie. xAxis, yAxis, etc) when accessed directly, return themselves, not the parent chart, so need to chain separately
chart.xAxis
.axisLabel("Time (s)")
.tickFormat(d3.format(',.1f'))
.staggerLabels(true)
;
chart.yAxis
.axisLabel('Voltage (v)')
.tickFormat(function(d) {
if (d == null) {
return 'N/A';
}
return d3.format(',.2f')(d);
})
;
data = sinAndCos();
d3.select('#chart1').append('svg')
.datum(data)
.attr("id","svg")
.attr("height","1000")
.attr("width","1000")
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function sinAndCos() {
var /*sin = [],
sin2 = [],*/
cos = [],
/* rand = [],*/
rand2 = []
;
for (var i = 0; i < 100; i++) {
cos.push({x: i, y: .5 * Math.cos(i/10)});
rand2.push({x: i, y: Math.cos(i/10) + Math.random() / 10 })
}
return [
{
values: cos,
key: "Cosine Wave",
color: "#2ca02c"
},
{
values: rand2,
key: "Random Cosine",
color: "#667711",
strokeWidth: 3.5,
fillOpacity: .1,
classed: 'dashed',
area: true,
}
];
}
</script>
</body>
</html>
This will work:
chart.xAxis
.rotateLabels(-45)

canvas gradient in animation

I’m having a problem with the rendering of the radial gradient; in fact only last colour of the gradient list of colours is rendered. The first three circles are animated. Is there any conflict between gradient and up-dating loop to render the animation?
Thanks
This is my code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Disc and Animated-Circle</title>
<style>
#canvasOne {
position: absolute;
border: dotted 2px black;
left: 50%;
margin-left: -450px;
top: 50%;
margin-top: -250px;
}
</style>
<script type="text/javascript">
window.addEventListener("load", eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasApp() {
var theCanvas = document.getElementById("canvasOne");
var context = theCanvas.getContext("2d");
drawScreen();
function drawScreen() {
//translation to centre canvas
context.setTransform(1, 0, 0, 1, 0, 0);
var x = canvasOne.width/2;
var y = canvasOne.height/2;
var circleWidth = 100;
var circleHeight = 100;
context.translate(x+.5*circleWidth, y+.5*circleHeight);
context.save();
//speed
r += speed;
//canvas
context.fillStyle = "blue";
context.fillRect(-(canvasOne.width/2+circleWidth/2), -(canvasOne.height/2+circleHeight/2), canvasOne.width, canvasOne.height);
//circle 1
context.strokeStyle = "#66f";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 1
context.stroke();
context.restore();
//circle 2
context.strokeStyle = "#69f";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r+4,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 2
context.stroke();
context.restore();
//circle 3
context.strokeStyle = "#6cf";
context.lineWidth = 4;
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, r+8,(Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call circle 3
context.stroke();
context.restore();
//disc gradient
var grad = context.createRadialGradient(100, 100, 0, 100, 100, 100);
grad.addColorStop(0, 'white');
grad.addColorStop(.5, 'grey');
grad.addColorStop(1, 'black');
context.fillStyle = grad;
//disc
context.beginPath();
context.arc(-circleWidth/2, -circleHeight/2, 100, (Math.PI/180)*0,(Math.PI/180)*360, false);
context.closePath();
//call disc
context.fill();
} //end drawScreen
var speed = 20;
var r = 100;
setInterval(drawScreen, 200);
} //end canvasApp
</script>
</head>
<body>
<canvas id="canvasOne" width="900" height="500">
Canvas is not supported.
</canvas>
</body>
</html>
You have the centre of the gradient at (100,100) which is not the centre of the circle.
Change the line
var grad = context.createRadialGradient(100, 100, 0, 100, 100, 100);
to
var grad = context.createRadialGradient(-circleWidth/2, -circleHeight/2, 0, -circleWidth/2, -circleHeight/2, 100);

Resources