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

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.

Related

How to optimize display & interactive with large svg image without Lag in FabricJS

I have a fabricJS editor with some large svg files, therefore, when I interactive with ( move / drag ) items on the editor I fill it very lag & heavy.
How to optimize using large svg files with fabricJS ?
big_image_1.svg: 4.4MB
big_image_2.svg: 6.1MB
big_image_3.svg: 4.1MB
big_image_4.svg: 13.6MB
Here is my code:
var canvas;
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
for (var i = 0; i < 4; i++) {
var bigImage = new fabric.Image();
bigImage.left = 10 * (i + 1);
bigImage.top = 10 * (i + 1);
bigImage["objectCaching"] = true;
canvas.add(bigImage);
bigImage.setSrc('https://futushigame.firebaseapp.com/big_image/big_image_' + (i + 1) + '.svg', function(imageObject) {
imageObject.set('dirty', true);
canvas.renderAll();
setObjectCoords();
});
}
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
Drag items are filling heavy & lag
You can rewrite needsItsOwnCache from fabric.Image class.
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
for (var i = 0; i < 4; i++) {
var bigImage = new fabric.Image();
bigImage.left = 10 * (i + 1);
bigImage.top = 10 * (i + 1);
// bigImage["objectCaching"] = true;
bigImage["ownCaching"] = true;
// bigImage["clipPath"] = [];
canvas.add(bigImage);
bigImage.setSrc('https://futushigame.firebaseapp.com/big_image/big_image_' + (i + 1) + '.svg', function(imageObject) {
//imageObject.set('dirty', true);
canvas.renderAll();
setObjectCoords();
});
}
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
fabric.Image.prototype.needsItsOwnCache = function() {
return true
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

Chart.js V2.7.2 How to make Horizontal scroll bar without loosing Y-Axis

I see some solutions but they are not working in V 2.7.2
Is there any way without using animation - make static Y-axis and scroll horizontal
I'm afraid I haven't yet found a way to achieve this without using animation. However, I have managed to find a solution that works in Chart.js 2.7.2.
https://jsfiddle.net/EmmaLouise/eb1aqpx8/3/
This approach handles different DPR settings and will scale the axis to match the scaling that Chart.js applies to its charts. It also calls .clearRect() on the original Y axis that Chart.js draws, clearing the pixels in the defined area which means that there is no duplication of axes or overlaps.
CSS:
.chartWrapper {
position: relative;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events: none;
}
.chartAreaWrapper {
width: 600px;
overflow-x: scroll;
}
HTML
<div class="chartWrapper">
<div class="chartAreaWrapper">
<div class="chartAreaWrapper2">
<canvas id="chart-Test" height="300" width="1200"></canvas>
</div>
</div>
<canvas id="axis-Test" height="300" width="0"></canvas>
</div>
JS:
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'bar',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: false
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
},
animation: {
onComplete: function () {
if (!rectangleSet) {
var scale = window.devicePixelRatio;
var sourceCanvas = chartTest.chart.canvas;
var copyWidth = chartTest.scales['y-axis-0'].width - 10;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var targetCtx = document.getElementById("axis-Test").getContext("2d");
targetCtx.scale(scale, scale);
targetCtx.canvas.width = copyWidth * scale;
targetCtx.canvas.height = copyHeight * scale;
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth * scale, copyHeight * scale, 0, 0, copyWidth * scale, copyHeight * scale);
var sourceCtx = sourceCanvas.getContext('2d');
// Normalize coordinate system to use css pixels.
sourceCtx.clearRect(0, 0, copyWidth * scale, copyHeight * scale);
rectangleSet = true;
}
},
onProgress: function () {
if (rectangleSet === true) {
var copyWidth = chartTest.scales['y-axis-0'].width;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var sourceCtx = chartTest.chart.canvas.getContext('2d');
sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
}
}
}
}
});
simple way to achieve this is
make the inner div width dynamically.
so enter image description herebased on the number of bars the width gets changed

SNAP.svg animate path clockwise

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>

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)

Resources