Related
Trying to get series values in the selected area after mouseup.
Need to calculate width and height of the selected are in the chart with respect to axis.
[`https://jsbin.com/wapovohiwe/edit?html,output`][1]
I modified your example to draw the rectangle and to output the coordinates of the
Chart1 = new Tee.Chart("canvas");
Chart1.legend.visible = false;
Chart1.panel.format.gradient.visible = false;
Chart1.panel.format.fill = "white";
Chart1.walls.back.format.fill = "white";
Chart1.addSeries(new Tee.Line([1, 3, 0, 2, 7, 5, 6]));
Chart1.zoom.enabled = false;
var myFormat = new Tee.Format(Chart1);
myFormat.transparency = 0.9;
var rect = {},
drag = false;
Chart1.mousedown = function(e) {
rect.startX = e.x - canvas.offsetLeft - canvas.parentElement.offsetLeft - canvas.parentElement.parentElement.offsetLeft;
rect.startY = e.y - canvas.offsetTop - canvas.parentElement.offsetTop - canvas.parentElement.parentElement.offsetTop;
drag = true;
}
Chart1.mouseup = function(p) {
var i, tmpP = {};
points = [];
var s = Chart1.series.items[0];
for (i = 0; i < s.count(); i++) {
s.calc(i, tmpP);
if ((tmpP.x >= rect.startX) && (tmpP.x <= rect.startX + rect.w) && (tmpP.y >= rect.startY) && (tmpP.y <= rect.startY + rect.h))
console.log("index: " + i + ", value: " + s.data.values[i]);
}
drag = false;
}
Chart1.mousemove = function(e) {
if (drag) {
rect.w = e.x - rect.startX;
rect.h = e.y - rect.startY;
drawChart();
}
}
function drawChart() {
Chart1.draw();
myFormat.rectangle(rect.startX, rect.startY, rect.w, rect.h);
}
Chart1.draw();
<script src="https://www.steema.com/files/public/teechart/html5/latest/src/teechart.js"></script>
<canvas id="canvas" height="400" width="700"></canvas>
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#canvasOne
{
border: 1px solid black;
}
</style>
<script src="http://code.jquery.com/jquery-1.10.2.js" type="text/javascript"></script>
</head>
<body>
<div align="center">
<canvas id="canvasOne">
</canvas>
</div>
<script type="text/javascript">
var myCanvas = document.getElementById("canvasOne");
var myContext = myCanvas.getContext("2d");
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
init();
var numShapes;
var shapes;
var dragIndex;
var dragging;
var mouseX;
var mouseY;
var dragHoldX;
var dragHoldY;
var timer;
var targetX;
var targetY;
var easeAmount;
var bgColor;
var nodes;
var colorArr;
function init()
{
myCanvas.width = $(window).width() - 200;
myCanvas.height = $(window).height() - 200;
shapes = [];
nodes = ["0;Person;24828760;Alok Kumar;Gorakhpur;#F44336;28",
"0;Suspect;04/Dec/2016;4;Suman_Biswas;#3F51B5;20","1;Rule;4;Apparent Means;3 Parameter;#EEFF41;20",
"0;Policy;36QA649749;In-Force;Quarterly;#FF9800;20","3;Product;Pension;Saral Pension;SRPEN;#795548;20","3;Payment;Cheque;Realized;Lucknow;#0091EA;20",
"0;Policy;162348873;Lapsed;Quarterly;#FF9800;20","6;Product;Pension;Life-Long Pension;LLPP;#795548;20","6;Payment;Cheque;Realized;Gorakhpur;#0091EA;20",
"0;Policy;1EQF178639;Lapsed;Monthly;#FF9800;20","9;Product;Life;Shield;SHIELDA;#795548;20","9;Payment;Demand Draft;Realized;Lucknow;#0091EA;20"];
numShapes = nodes.length;
makeShapes();
drawScreen();
myCanvas.addEventListener("mousedown", mouseDownListener, false);
}
//drawing
function makeShapes()
{
var tempX;
var tempY;
for(var i = 0; i < numShapes; i++)
{
var centerX = myCanvas.width/2;
var centerY = myCanvas.height/2;
var nodeColor = nodes[i].split(";")[5];
var nodeRadius = nodes[i].split(";")[6];
var nodeConnect = nodes[i].split(";")[0];
if(i == 0)//center of circle
{
tempX = centerX
tempY = centerY;
}
else
{
//tempX = Math.random() * (myCanvas.width - tempRadius);
//tempY = Math.random() * (myCanvas.height - tempRadius);
//var x = x0 + r * Math.cos(2 * Math.PI * i / items);
//var y = y0 + r * Math.sin(2 * Math.PI * i / items);
//250 is the distance from center node to outside nodes it can be actual radius in degrees
tempX = shapes[nodeConnect].x + 300 * Math.cos(2 * Math.PI * i / numShapes);
tempY = shapes[nodeConnect].y + 300 * Math.sin(2 * Math.PI * i / numShapes);
}
tempShape = {x: tempX, y: tempY, rad: nodeRadius, color: nodeColor, text: nodes[i]};
shapes.push(tempShape);
}
}
//drawing both shape (line and circle) and screen
function drawScreen()
{
myContext.fillStyle = "#ffffff";
myContext.fillRect(0, 0, myCanvas.width, myCanvas.height);
drawShapes();
}
function drawShapes()
{
//line
for(var i = 1; i < numShapes; i++)
{
myContext.beginPath();
myContext.strokeStyle = "#B2B19D";
var nodeConnect = nodes[i].split(";")[0];
myContext.moveTo(shapes[nodeConnect].x, shapes[nodeConnect].y);
myContext.lineTo(shapes[i].x, shapes[i].y);
myContext.stroke();
}
//circle
for(var i = 0; i < numShapes; i++)
{
myContext.fillStyle = shapes[i].color;
myContext.beginPath();
myContext.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2*Math.PI, false);
myContext.closePath();
myContext.fill();
}
//text
for(var i = 0; i < numShapes; i++)
{
myContext.beginPath();
myContext.font = '10pt Arial';
myContext.fillStyle = 'black';
var textarr = shapes[i].text.split(";");
myContext.fillText(textarr[1], shapes[i].x + 30, shapes[i].y - 24);
/*myContext.fillText(textarr[2], shapes[i].x + 30, shapes[i].y + 1);
myContext.fillText(textarr[3], shapes[i].x + 30, shapes[i].y + 22);
myContext.fillText(textarr[4], shapes[i].x + 30, shapes[i].y + 44);*/
myContext.closePath();
myContext.fill();
}
}
//animation
function mouseDownListener(evt)
{
var highestIndex = -1;
var bRect = myCanvas.getBoundingClientRect();
mouseX = (evt.clientX - bRect.left) * (myCanvas.width/bRect.width);
mouseY = (evt.clientY - bRect.top) * (myCanvas.height/bRect.height);
for(var i = 0; i < numShapes; i++)
{
if(hitTest(shapes[i], mouseX, mouseY))
{
dragging = true;
if(i > highestIndex)
{
dragHoldX = mouseX - shapes[i].x;
dragHoldY = mouseY - shapes[i].y;
highestIndex = i;
dragIndex = i;
}
}
}
if(dragging)
{
window.addEventListener("mousemove", mouseMoveListener, false);
}
myCanvas.removeEventListener("mousedown", mouseDownListener, false);
window.addEventListener("mouseup", mouseUpListener, false);
if(evt.preventDefault)
{
evt.preventDefault;
}
return false;
}
function mouseMoveListener(evt)
{
var shapeRad = shapes[dragIndex].rad;
var minX = shapeRad;
var maxX = myCanvas.width - shapeRad;
var minY = shapeRad;
var maxY = myCanvas.height - shapeRad;
//get mouse position correctly
var bRect = myCanvas.getBoundingClientRect();
mouseX = (evt.clientX - bRect.left)*(myCanvas.width / bRect.width);
mouseY = (evt.clientY - bRect.top)*(myCanvas.height / bRect.height);
//clamp x and y position to prevent object from dragging outside canvas
posX = mouseX - dragHoldX;
posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX);
posY = mouseY - dragHoldY;
posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY);
shapes[dragIndex].x = posX;
shapes[dragIndex].y = posY;
drawScreen();
}
function mouseUpListener(evt)
{
myCanvas.addEventListener("mousedown", mouseDownListener, false);
window.removeEventListener("mouseup", mouseUpListener, false);
if(dragging)
{
dragging = false;
window.removeEventListener("mousemove", mouseMoveListener, false);
}
}
function hitTest(shape, mx, my)
{
var dx = mx - shape.x;
var dy = my - shape.y;
return(dx * dx + dy * dy < shape.rad * shape.rad);
}
</script>
</body>
</html>
The following canvas animation creates nodes and edges. However due
to space constraint, some of the nodes are not visible due to canvas
height and width. Even adding overflow css to canvas dosen't help as
i am not able to scroll.
<canvas> context doesn't have a built-in scroll method.
You then have multiple ways to circumvent this limitation.
The first one, is as in #markE's answer, to scale your context's matrix so that your drawings fit into the required space. You could also refactor your code so that all coordinates are relative to the canvas size.
This way, you won't need scrollbars and all your drawings will just be scaled appropriately, which is the desirable behavior in most common cases.
But if you really need to have some scrolling feature, here are some ways :
The easiest and most recommended one : let the browser handle it.
You will have to set the size of your canvas to the maximum of your drawings, and wrap it in an other element which will scroll. By setting the overflow:auto css property on the container, our scrollbars appear and we have our scrolling feature.
In following example, the canvas is 5000px wide and the container 200px.
var ctx = canvas.getContext('2d');
ctx.textAlign = 'center';
for (var w = 0; w < canvas.width; w += 100) {
for (var h = 0; h < canvas.height; h += 100) {
ctx.fillText(w + ',' + h, w, h);
}
}
#container {
width: 200px;
height: 200px;
overflow: auto;
border: 1px solid;
}
canvas{
display: block;
}
<div id="container">
<canvas id="canvas" height="5000" width="5000"></canvas>
</div>
Main advantages :
easily implemented.
users are used to these scrollbars.
Main caveats :
You're limited by canvas maximum sizes.
If your canvas is animated, you'll also draw for each frame parts of the canvas that aren't visible.
You have small control on scrollbars look and you'll still have to implement drag-to-scroll feature yourself for desktop browsers.
A second solution, is to implement this feature yourself, using canvas transform methods : particularly translate, transform and setTransform.
Here is an example :
var ctx = canvas.getContext('2d');
var app = {};
// the total area of our drawings, can be very large now
app.WIDTH = 5000;
app.HEIGHT = 5000;
app.draw = function() {
// reset everything (clears the canvas + transform + fillStyle + any other property of the context)
canvas.width = canvas.width;
// move our context by the inverse of our scrollbars' left and top property
ctx.setTransform(1, 0, 0, 1, -app.scrollbars.left, -app.scrollbars.top);
ctx.textAlign = 'center';
// draw only the visible area
var visibleLeft = app.scrollbars.left;
var visibleWidth = visibleLeft + canvas.width;
var visibleTop = app.scrollbars.top
var visibleHeight = visibleTop + canvas.height;
// you probably will have to make other calculations than these ones to get your drawings
// to draw only where required
for (var w = visibleLeft; w < visibleWidth + 50; w += 100) {
for (var h = visibleTop; h < visibleHeight + 50; h += 100) {
var x = Math.round((w) / 100) * 100;
var y = Math.round((h) / 100) * 100;
ctx.fillText(x + ',' + y, x, y);
}
}
// draw our scrollbars on top if needed
app.scrollbars.draw();
}
app.scrollbars = function() {
var scrollbars = {};
// initial position
scrollbars.left = 0;
scrollbars.top = 0;
// a single constructor for both horizontal and vertical
var ScrollBar = function(vertical) {
var that = {
vertical: vertical
};
that.left = vertical ? canvas.width - 10 : 0;
that.top = vertical ? 0 : canvas.height - 10;
that.height = vertical ? canvas.height - 10 : 5;
that.width = vertical ? 5 : canvas.width - 10;
that.fill = '#dedede';
that.cursor = {
radius: 5,
fill: '#bababa'
};
that.cursor.top = vertical ? that.cursor.radius : that.top + that.cursor.radius / 2;
that.cursor.left = vertical ? that.left + that.cursor.radius / 2 : that.cursor.radius;
that.draw = function() {
if (!that.visible) {
return;
}
// remember to reset the matrix
ctx.setTransform(1, 0, 0, 1, 0, 0);
// you can give it any shape you like, all canvas drawings operations are possible
ctx.fillStyle = that.fill;
ctx.fillRect(that.left, that.top, that.width, that.height);
ctx.beginPath();
ctx.arc(that.cursor.left, that.cursor.top, that.cursor.radius, 0, Math.PI * 2);
ctx.fillStyle = that.cursor.fill;
ctx.fill();
};
// check if we're hovered
that.isHover = function(x, y) {
if (x >= that.left - that.cursor.radius && x <= that.left + that.width + that.cursor.radius &&
y >= that.top - that.cursor.radius && y <= that.top + that.height + that.cursor.radius) {
// we are so record the position of the mouse and set ourself as the one hovered
scrollbars.mousePos = vertical ? y : x;
scrollbars.hovered = that;
that.visible = true;
return true;
}
// we were visible last call and no wheel event is happening
else if (that.visible && !scrollbars.willHide) {
that.visible = false;
// the app should be redrawn
return true;
}
}
return that;
};
scrollbars.horizontal = ScrollBar(0);
scrollbars.vertical = ScrollBar(1);
scrollbars.hovered = null;
scrollbars.dragged = null;
scrollbars.mousePos = null;
// check both of our scrollbars
scrollbars.isHover = function(x, y) {
return this.horizontal.isHover(x, y) || this.vertical.isHover(x, y);
};
// draw both of our scrollbars
scrollbars.draw = function() {
this.horizontal.draw();
this.vertical.draw();
};
// check if one of our scrollbars is visible
scrollbars.visible = function() {
return this.horizontal.visible || this.vertical.visible;
};
// hide it...
scrollbars.hide = function() {
// only if we're not using the mousewheel or dragging the cursor
if (this.willHide || this.dragged) {
return;
}
this.horizontal.visible = false;
this.vertical.visible = false;
};
// get the area's coord relative to our scrollbar
var toAreaCoord = function(pos, scrollBar) {
var sbBase = scrollBar.vertical ? scrollBar.top : scrollBar.left;
var sbMax = scrollBar.vertical ? scrollBar.height : scrollBar.width;
var areaMax = scrollBar.vertical ? app.HEIGHT - canvas.height : app.WIDTH - canvas.width;
var ratio = (pos - sbBase) / (sbMax - sbBase);
return areaMax * ratio;
};
// get the scrollbar's coord relative to our total area
var toScrollCoords = function(pos, scrollBar) {
var sbBase = scrollBar.vertical ? scrollBar.top : scrollBar.left;
var sbMax = scrollBar.vertical ? scrollBar.height : scrollBar.width;
var areaMax = scrollBar.vertical ? app.HEIGHT - canvas.height : app.WIDTH - canvas.width;
var ratio = pos / areaMax;
return ((sbMax - sbBase) * ratio) + sbBase;
}
scrollbars.scroll = function() {
// check which one of the scrollbars is active
var vertical = this.hovered.vertical;
// until where our cursor can go
var maxCursorPos = this.hovered[vertical ? 'height' : 'width'];
var pos = vertical ? 'top' : 'left';
// check that we're not out of the bounds
this.hovered.cursor[pos] = this.mousePos < 0 ? 0 :
this.mousePos > maxCursorPos ? maxCursorPos : this.mousePos;
// seems ok so tell the app we scrolled
this[pos] = toAreaCoord(this.hovered.cursor[pos], this.hovered);
// redraw everything
app.draw();
}
// because we will hide it after a small time
scrollbars.willHide;
// called by the wheel event
scrollbars.scrollBy = function(deltaX, deltaY) {
// it's not coming from our scrollbars
this.hovered = null;
// we're moving horizontally
if (deltaX) {
var newLeft = this.left + deltaX;
// make sure we're in the bounds
this.left = newLeft > app.WIDTH - canvas.width ? app.WIDTH - canvas.width : newLeft < 0 ? 0 : newLeft;
// update the horizontal cursor
this.horizontal.cursor.left = toScrollCoords(this.left, this.horizontal);
// show our scrollbar
this.horizontal.visible = true;
}
if (deltaY) {
var newTop = this.top + deltaY;
this.top = newTop > app.HEIGHT - canvas.height ? app.HEIGHT - canvas.height : newTop < 0 ? 0 : newTop;
this.vertical.cursor.top = toScrollCoords(this.top, this.vertical);
this.vertical.visible = true;
}
// if we were called less than the required timeout
clearTimeout(this.willHide);
this.willHide = setTimeout(function() {
scrollbars.willHide = null;
scrollbars.hide();
app.draw();
}, 500);
// redraw everything
app.draw();
};
return scrollbars;
}();
var mousedown = function(e) {
// tell the browser we handle this
e.preventDefault();
// we're over one the scrollbars
if (app.scrollbars.hovered) {
// new promotion ! it becomes the dragged one
app.scrollbars.dragged = app.scrollbars.hovered;
app.scrollbars.scroll();
}
};
var mousemove = function(e) {
// check the coordinates of our canvas in the document
var rect = canvas.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// we're dragging something
if (app.scrollbars.dragged) {
// update the mouse position
app.scrollbars.mousePos = app.scrollbars.dragged.vertical ? y : x;
app.scrollbars.scroll();
} else if (app.scrollbars.isHover(x, y)) {
// something has changed, redraw to show or hide the scrollbar
app.draw();
}
e.preventDefault();
};
var mouseup = function() {
// we dropped it
app.scrollbars.dragged = null;
};
var mouseout = function() {
// we're out
if (app.scrollbars.visible()) {
app.scrollbars.hide();
app.scrollbars.dragged = false;
app.draw();
}
};
var mouseWheel = function(e) {
e.preventDefault();
app.scrollbars.scrollBy(e.deltaX, e.deltaY);
};
canvas.addEventListener('mousemove', mousemove);
canvas.addEventListener('mousedown', mousedown);
canvas.addEventListener('mouseup', mouseup);
canvas.addEventListener('mouseout', mouseout);
canvas.addEventListener('wheel', mouseWheel);
range.onchange = function() {
app.WIDTH = app.HEIGHT = this.value;
app.scrollbars.left = 0;
app.scrollbars.top = 0;
app.draw();
};
// an initial drawing
app.draw();
canvas {border: 1px solid;}
span{font-size: .8em;}
<canvas id="canvas" width="200" height="150"></canvas>
<span>
change the total area size
<input type="range" min="250" max="5000000" steps="250" value="5000" id="range" />
</span>
Main advantages :
no limitation for the size of your drawing areas.
you can customize your scrollbars as you wish.
you can control when the scrollbars are enable or not.
you can get the visible area quite easily.
Main caveats:
a bit more code than the CSS solution...
no really, that's a lot of code...
A third way I wrote some time ago for an other question took advantage of the ability to draw an other canvas with ctx.drawImage(). It has its own caveats and advantages, so I let you pick the one you need, but this last one also had a drag and slide feature which can be useful.
So your node drawings don't fit on the canvas size?
You can easily "shrink" your content to fit the visible canvas with just 1 command!
The context.scale(horizontalRescale,verticalRescale) command will shrink every following drawing by your specified horizontalRescale & verticalRescale percentages.
An Important note: You must make horizontalRescale,verticalRescale the same value or your content will be distorted.
The nice thing about using context.scale is that you don't have to change any of the code that draws your nodes ... canvas automatically scales all those nodes for you.
For example, this code will shrink your nodes to 80% of their original size:
var downscaleFactor= 0.80;
context.scale( downscaleFactor, downscaleFactor );
Rather than go through your 200+ lines of code, I leave it to you to calculate downscaleFactor.
Drawing was working fine, until I decided to use multiple canvas's. I have a stage canvas, an entity canvas, and an object canvas. I'll probably end up combining the object and entity canvas's, though. Anyway, as you can see below, my hero class draws fine. I then tried to make an entity class with the same draw function, but it won't let me draw when I call the function. I have almost the same issue with my background canvas. I don't have a class for the background yet, but I will. But I try simply drawing the image with the stage's context, and it breaks the code.
(I tried setting up a JSFiddle, but I wouldn't be able to get the images on there.)
UPDATE
Half of my issue was fixed by markE. The only issue I currently have, is my entitiesCtx is the the only context that can draw images/rectangles. The other ctx's just can't draw anything. Help, please! I updated the code.
var stage = document.getElementById('stage');
var ctxStage = stage.getContext('2d');
var entitiesStage = document.getElementById('entities');
var ctxEntities = entitiesStage.getContext('2d');
var bg = document.getElementById('bg');
var ctxBg = bg.getContext('2d');
var playerImg = new Image();
playerImg.src = 'res/player_sprite_sheet.png';
var bgImg = new Image();
bgImg.onload = function() {
ctxBg.drawImage(bgImg,0,0,80,50,-200,-90,1000,700);
};
bgImg.src = 'res/background.png';
var consoleImg = new Image();
consoleImg.onload = function() {
ctxEntities.drawImage(consoleImg,0,0,80,50,20,20,1000,700);
};
console.src = 'res/console.png';
var hero = new Hero();
var prop;
var isPlaying = false;
window.onload = init;
var requestAnimFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
function init() {
console.debug('initializing...');
document.addEventListener('keydown',keyDown,false);
document.addEventListener('keyup',keyUp,false);
ctxStage.imageSmoothingEnabled = false;
ctxStage.webkitImageSmoothingEnabled = false;
ctxStage.mozImageSmoothingEnabled = false;
ctxEntities.imageSmoothingEnabled = false;
ctxEntities.webkitImageSmoothingEnabled = false;
ctxEntities.mozImageSmoothingEnabled = false;
prop = new Entity(consoleImg,20,20,80,50,0,0);
startLoop();
}
function startLoop(){
console.debug('starting loop...');
isPlaying = true;
loop();
}
function stopLoop(){
console.debug('stopping loop...');
isPlaying = false;
}
function loop(){
if(isPlaying){
requestAnimFrame(loop);
draw();
update();
}
}
function update(){
hero.update();
}
function clearCtx(){
ctxEntities.clearRect(0,0,stage.width,stage.height);
}
function draw(){
clearCtx();
ctxEntities.fillStyle = 'black';
ctxEntities.fillRect(0,0,stage.width,stage.height);
ctxEntities.drawImage(bgImg,0,0,80,50,-200,-90,1000,700);
hero.draw();
prop.draw();
}
// hero class
function Hero() {
this.xpos = 140;
this.ypos = 320;
this.srcX = 0;
this.srcY = 0;
this.width = 10;
this.height = 20;
this.scaleX = 50;
this.scaleY = 80;
this.isUpKey;
this.isDownKey;
this.isLeftKey;
this.isRightKey;
this.img = playerImg;
this.speed = 2;
this.defspeed = 3.5;
this.dir = 'right';
}
Hero.prototype.draw = function() {
ctxEntities.drawImage(this.img,this.srcX,this.srcY,this.width,this.height,this.xpos,this.ypos,this.scaleX,this.scaleY);
};
Hero.prototype.update = function() {
this.checkKeys();
if(this.dir == 'right'){
if(this.scaleX >= 0){
this.srcX = 0;
}
if(this.scaleX >= 40){
this.scaleX = 40;
this.speed = this.defspeed;
}else{
this.xpos -= 2.3;
this.speed = 0;
this.scaleX += 5;
}
}else if(this.dir =='left'){
if(this.scaleX <= 0){
this.srcX = 10;
}
if(this.scaleX <= -40){
this.scaleX = -40;
this.speed = this.defspeed;
}else{
this.xpos += 2.3;
this.speed = 0;
this.scaleX -= 5;
}
}
};
Hero.prototype.checkKeys = function() {
if(this.isLeftKey){
this.xpos += -this.speed;
this.dir = 'left';
}
if(this.isRightKey){
this.xpos += this.speed;
this.dir = 'right';
}
};
// end of hero class
// entity class
function Entity(img,xpos,ypos,width,height,scaleX,scaleY){
this.img = img;
this.xpos = xpos;
this.ypos = ypos;
this.width = width;
this.height = height;
this.scaleX = scaleX;
this.scaleY = scaleY;
}
Entity.prototype.draw = function(){
ctxEntities.drawImage(this.img,0,0,this.width,this.height,this.xpos,this.ypos,this.scaleX,this.scaleY);
};
// end of entity class
// input handling
function keyDown(e){
var keyID = (e.keyCode) ? e.keyCode : e.which;
if(keyID == 38 || keyID == 87){ //w
e.preventDefault();
hero.isUpKey = true;
}
if(keyID == 37 || keyID == 65){ //a
e.preventDefault();
hero.isLeftKey = true;
}
if(keyID == 40 || keyID == 83){ //s
e.preventDefault();
hero.isDownKey = true;
}
if(keyID == 39 || keyID == 68){ //d
e.preventDefault();
hero.isRightKey = true;
}
}
function keyUp(e){
var keyID = (e.keyCode) ? e.keyCode : e.which;
if(keyID == 38 || keyID == 87){
hero.isUpKey = false;
}
if(keyID == 37 || keyID == 65){
hero.isLeftKey = false;
}
if(keyID == 40 || keyID == 83){
hero.isDownKey = false;
}
if(keyID == 39 || keyID == 68){
hero.isRightKey = false;
}
}
// end of input handling
UPDATE
Half of my issue was fixed by markE. The only issue I currently have, is my entitiesCtx is the the only context that can draw images/rectangles. The other ctx's just can't draw anything. I updated the code.
Using JS “classes” to draw on multiple canvas’s
[I expanded my answer to include example of using your JS classes]
This example illustrates your 2 js-classes that draw images on canvases
The Entity class controls and draws an image on a canvas.
The Hero class controls and draws spritesheets on a canvas.
There is also an image loader so that all your images are fully loaded before they are used.
In your question you included only your js-class code and no specifics on your project.
So I made up my own project using your Hero and Entity classes (pardon my taking liberty).
This image shows your Entity and Hero classes in action drawing on all 3 of your canvases...
This is the background canvas containing:
A sky-blue rect filling the canvas (the sky)
The background contains 2 Entity class objects.
A sun which is an image wrapped in an Entity class object
A wall which is an image wrapped in an Entity class object
This is the stage canvas containing:
A cannon which is an Entity class object that animates up and down
This is the entities canvas containing:
A cat image is a spritesheet image wrapped in a Hero class object
The cat object animates sprites in response to the cannon object
The cat is composed of a spritesheet that’s controlled by the Hero class
The Entity class controls and draws an image on a canvas:
The image can be moved and scaled.
The Entity class has 3 methods.
Entity.draw() will draw the image on the canva.
Entity.set() will set the XY position of the image on the canvas.
Entity.scale() will scale the image.
Here is the code for the Entity class:
// Entity class
function Entity(context,img,x,y){
this.context=context;
this.img = img;
this.xpos = x;
this.ypos = y;
this.width = img.width;
this.height = img.height;
this.scaleX = img.width;
this.scaleY = img.height;
}
// Entity.set()
Entity.prototype.set = function(x,y){
this.xpos=x;
this.ypos=y;
}
// Entity.scale()
Entity.prototype.scale = function(scaleX,scaleY){
this.scaleX=scaleX;
this.scaleY=scaleY;
}
// Entity.draw()
Entity.prototype.draw = function(){
this.context.drawImage(this.img,
0,0,this.width,this.height,
this.xpos,this.ypos,this.scaleX,this.scaleY);
}
The Hero class controls and draws spritesheets on a canvas
The individual sprites are pulled from the spritesheet image.
Each sprite is defined by an object having its x,y,width,height within the spritesheet.
The sprites can be moved and scaled.
The Hero class has 3 methods.
Hero.draw() will draw one of the sprites on the canvas.
Hero.set() will set which sprite is drawn and its XY position on the canvas
Hero.scale() will scale the sprite.
Here is the code for the Hero class:
// Hero class
function Hero(context,img,spriteDefs) {
this.context=context;
this.spriteDefs=spriteDefs;
this.img = img;
this.xpos = 0;
this.ypos = 0;
this.srcX = 0;
this.srcY = 0;
this.width = img.width;
this.height = img.height;
this.scaleX = img.width;
this.scaleY = img.height;
this.isUpKey;
this.isDownKey;
this.isLeftKey;
this.isRightKey;
this.speed = 2;
this.defspeed = 3.5;
this.dir = 'right';
}
// Hero.set()
Hero.prototype.set = function(spriteNumber,x,y){
// pull the specified sprite
var sprite=this.spriteDefs[spriteNumber];
this.srcX=sprite.x;
this.srcY=sprite.y;
this.width=sprite.width;
this.height=sprite.height;
// default scale to 100%
this.scaleX=sprite.width;
this.scaleY=sprite.height;
this.xpos=x;
this.ypos=y;
}
// Hero.scale()
Hero.prototype.scale = function(scaleX,scaleY){
this.scaleX=scaleX;
this.scaleY=scaleY;
}
// Hero.draw()
Hero.prototype.draw = function() {
this.context.drawImage(this.img,
this.srcX,this.srcY,this.width,this.height,
this.xpos,this.ypos,this.scaleX,this.scaleY);
}
This is an image loader that makes sure all images are loaded before they are used
var imageURLs=[];
var imagesOK=0;
var imgs=[];
imageURLs.push("cats.png");
imageURLs.push("cannonLifted.png");
imageURLs.push("brickwall.jpg");
imageURLs.push("sun.png");
loadAllImages();
function loadAllImages(){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){ imagesOK++; imagesAllLoaded(); };
img.src = imageURLs[i];
}
}
var imagesAllLoaded = function() {
if (imagesOK==imageURLs.length ) {
// all images are fully loaded an ready to use
cat=imgs[0];
cannon=imgs[1];
wall=imgs[2];
sun=imgs[3];
start();
}
};
Here is complete code and a Fiddle: http://jsfiddle.net/m1erickson/yCW9U/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:20px; }
h3{ font-size:2em; }
#wrapper{
position:relative;
width:350px;
height:400px;
}
#bg,#stage,#entities{
position:absolute; top:0px; left:0px;
border:1px solid green;
width:100%;
height:100%;
}
</style>
<script>
$(function(){
//////////////////////////////
// get context references
//////////////////////////////
// stage
var stage = document.getElementById('stage');
var ctxStage = stage.getContext('2d');
// entities
var entitiesStage = document.getElementById('entities');
var ctxEntities = entitiesStage.getContext('2d');
// background
var bg = document.getElementById('bg');
var ctxBg = bg.getContext('2d');
//////////////////////////////
// public variables
//////////////////////////////
// images
var wall,cat,cannon,sun;
// display objectx
var sunEntity,wallEntity,cannonEntity,catHero;
// animation vars
var cannonX=65;
var cannonMove=-10;
var cannonMin=75;
var cannonMax=185;
var cannonY=185;
var cannonSafe=145;
// cat hero sprites
var catSpriteNames={
laying:0,
layingX:250,
layingY:127,
standing:1,
standingX:165,
standingY:25
};
var catSprites=[
{x:80, y:30, width:67, height:48},
{x:15, y:8, width:47, height:78}
];
//////////////////////////////
// preload all images
//////////////////////////////
var imageURLs=[];
var imagesOK=0;
var imgs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/cats.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/cannonLifted.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/BrickWall.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sun.png");
loadAllImages();
function loadAllImages(){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){ imagesOK++; imagesAllLoaded(); };
img.src = imageURLs[i];
}
}
var imagesAllLoaded = function() {
if (imagesOK==imageURLs.length ) {
// all images are fully loaded an ready to use
cat=imgs[0];
cannon=imgs[1];
wall=imgs[2];
sun=imgs[3];
start();
}
};
//////////////////////////////
// build the display objects
// and start animation
//////////////////////////////
function start(){
// static background (canvas: bg)
// rectangle=blue sky
ctxBg.rect(0,0,bg.width,bg.height);
ctxBg.fillStyle="skyblue";
ctxBg.fill();
// sun image # 75% scale
sunEntity=new Entity(ctxBg,sun,185,15);
sunEntity.set(25,15);
sunEntity.scale(sun.width*.75,sun.height*.75);
sunEntity.draw();
// wall image
wallEntity=new Entity(ctxBg,wall,250,bg.height-wall.height);
wallEntity.set(250,bg.height-wall.height,wall.width,wall.height);
wallEntity.draw();
// stage (canvas: stage)
// contents: wall
cannonEntity=new Entity(ctxStage,cannon,cannonX,cannonY,cannon.width,cannon.height,cannon.width,cannon.height);
cannonEntity.draw();
// entities (canvas: entities)
// contents:
catHero=new Hero(ctxEntities,cat,catSprites);
catHero.set(catSpriteNames.laying,catSpriteNames.layingX,catSpriteNames.layingY);
catHero.draw();
animate();
}
function animate(){
cannonY+=cannonMove;
if(cannonY<cannonMin){ cannonY=cannonMin; cannonMove=-cannonMove; }
if(cannonY>cannonMax){ cannonY=cannonMax; cannonMove=-cannonMove; }
cannonEntity.context.clearRect(0,0,stage.width,stage.height);
cannonEntity.set(cannonX,cannonY);
cannonEntity.draw();
if(cannonY>cannonSafe){
catHero.set(catSpriteNames.laying,catSpriteNames.layingX,catSpriteNames.layingY);
}else{
catHero.set(catSpriteNames.standing,catSpriteNames.standingX,cannonY-50);
}
catHero.context.clearRect(0,0,entities.width,entities.height);
catHero.draw()
window.setTimeout(function(){animate();},500);
}
// Hero class
function Hero(context,img,spriteDefs) {
this.context=context;
this.spriteDefs=spriteDefs;
this.img = img;
this.xpos = 0;
this.ypos = 0;
this.srcX = 0;
this.srcY = 0;
this.width = img.width;
this.height = img.height;
this.scaleX = img.width;
this.scaleY = img.height;
this.isUpKey;
this.isDownKey;
this.isLeftKey;
this.isRightKey;
this.speed = 2;
this.defspeed = 3.5;
this.dir = 'right';
}
// Hero.set()
Hero.prototype.set = function(spriteNumber,x,y){
// pull the specified sprite
var sprite=this.spriteDefs[spriteNumber];
this.srcX=sprite.x;
this.srcY=sprite.y;
this.width=sprite.width;
this.height=sprite.height;
// default scale to 100%
this.scaleX=sprite.width;
this.scaleY=sprite.height;
this.xpos=x;
this.ypos=y;
}
// Hero.scale()
Hero.prototype.scale = function(scaleX,scaleY){
this.scaleX=scaleX;
this.scaleY=scaleY;
}
// Hero.draw()
Hero.prototype.draw = function() {
this.context.drawImage(this.img,
this.srcX,this.srcY,this.width,this.height,
this.xpos,this.ypos,this.scaleX,this.scaleY);
}
// Entity class
function Entity(context,img,x,y){
this.context=context;
this.img = img;
this.xpos = x;
this.ypos = y;
this.width = img.width;
this.height = img.height;
this.scaleX = img.width;
this.scaleY = img.height;
}
// Entity.set()
Entity.prototype.set = function(x,y){
this.xpos=x;
this.ypos=y;
}
// Entity.scale()
Entity.prototype.scale = function(scaleX,scaleY){
this.scaleX=scaleX;
this.scaleY=scaleY;
}
// Entity.draw()
Entity.prototype.draw = function(){
this.context.drawImage(this.img,
0,0,this.width,this.height,
this.xpos,this.ypos,this.scaleX,this.scaleY);
}
}); // end $(function(){});
</script>
</head>
<body>
<h3>Watch out Kitty!</h3><br>
<div id="wrapper">
<canvas id="bg" width=350 height=400></canvas>
<canvas id="stage" width=350 height=400></canvas>
<canvas id="entities" width=350 height=400></canvas>
</div>
</body>
</html>
I'm trying to place a background image on the back of this canvas script I found. I know it's something to do with the context.fillstyle but not sure how to go about it. I'd like that line to read something like this:
context.fillStyle = "url('http://www.samskirrow.com/background.png')";
Here is my current code:
var waveform = (function() {
var req = new XMLHttpRequest();
req.open("GET", "js/jquery-1.6.4.min.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/soundmanager2.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/soundcloudplayer.js", false);
req.send();
eval(req.responseText);
req.open("GET", "js/raf.js", false);
req.send();
eval(req.responseText);
// soundcloud player setup
soundManager.usePolicyFile = true;
soundManager.url = 'http://www.samskirrow.com/client-kyra/js/';
soundManager.flashVersion = 9;
soundManager.useFlashBlock = false;
soundManager.debugFlash = false;
soundManager.debugMode = false;
soundManager.useHighPerformance = true;
soundManager.wmode = 'transparent';
soundManager.useFastPolling = true;
soundManager.usePeakData = true;
soundManager.useWaveformData = true;
soundManager.useEqData = true;
var clientID = "345ae40b30261fe4d9e6719f6e838dac";
var playlistUrl = "https://soundcloud.com/kyraofficial/sets/kyra-ft-cashtastic-good-love";
var waveLeft = [];
var waveRight = [];
// canvas animation setup
var canvas;
var context;
function init(c) {
canvas = document.getElementById(c);
context = canvas.getContext("2d");
soundManager.onready(function() {
initSound(clientID, playlistUrl);
});
aniloop();
}
function aniloop() {
requestAnimFrame(aniloop);
drawWave();
}
function drawWave() {
var step = 10;
var scale = 60;
// clear
context.fillStyle = "#ff19a7";
context.fillRect(0, 0, canvas.width, canvas.height);
// left wave
context.beginPath();
for ( var i = 0; i < 256; i++) {
var l = (i/(256-step)) * 1000;
var t = (scale + waveLeft[i] * -scale);
if (i == 0) {
context.moveTo(l,t);
} else {
context.lineTo(l,t); //change '128' to vary height of wave, change '256' to move wave up or down.
}
}
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(4 * i, 255 + waveRight[i] * 128.);
}
context.lineWidth = 0.5;
context.strokeStyle = "#000";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
Revised code - currently just showing black as the background, not an image:
// canvas animation setup
var backgroundImage = new Image();
backgroundImage.src = 'http://www.samskirrow.com/images/main-bg.jpg';
var canvas;
var context;
function init(c) {
canvas = document.getElementById(c);
context = canvas.getContext("2d");
soundManager.onready(function() {
initSound(clientID, playlistUrl);
});
aniloop();
}
function aniloop() {
requestAnimFrame(aniloop);
drawWave();
}
function drawWave() {
var step = 10;
var scale = 60;
// clear
context.drawImage(backgroundImage, 0, 0);
context.fillRect(0, 0, canvas.width, canvas.height);
// left wave
context.beginPath();
for ( var i = 0; i < 256; i++) {
var l = (i/(256-step)) * 1000;
var t = (scale + waveLeft[i] * -scale);
if (i == 0) {
context.moveTo(l,t);
} else {
context.lineTo(l,t); //change '128' to vary height of wave, change '256' to move wave up or down.
}
}
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(4 * i, 255 + waveRight[i] * 128.);
}
context.lineWidth = 0.5;
context.strokeStyle = "#ff19a7";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
Theres a few ways you can do this. You can either add a background to the canvas you are currently working on, which if the canvas isn't going to be redrawn every loop is fine. Otherwise you can make a second canvas underneath your main canvas and draw the background to it. The final way is to just use a standard <img> element placed under the canvas. To draw a background onto the canvas element you can do something like the following:
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 903;
canvas.height = 657;
var background = new Image();
background.src = "http://www.samskirrow.com/background.png";
// Make sure the image is loaded first otherwise nothing will draw.
background.onload = function(){
ctx.drawImage(background,0,0);
}
// Draw whatever else over top of it on the canvas.
Why don't you style it out:
<canvas id="canvas" width="800" height="600" style="background: url('./images/image.jpg')">
Your browser does not support the canvas element.
</canvas>
Make sure that in case your image is not in the dom, and you get it from local directory or server, you should wait for the image to load and just after that to draw it on the canvas.
something like that:
function drawBgImg() {
let bgImg = new Image();
bgImg.src = '/images/1.jpg';
bgImg.onload = () => {
gCtx.drawImage(bgImg, 0, 0, gElCanvas.width, gElCanvas.height);
}
}
Canvas does not using .png file as background image. changing to other file extensions like gif or jpg works fine.
I got the following RequestAnimationframe function from http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
I am trying to use it. But not sure how to call it and use it. Can someone give me a simple example. I am new to this html5 animation thing so you can understand..
I will really appreciate any help! The function is below..
(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.cancelRequestAnimationFrame = 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);
};
}())
Just paste that code into your JS or in its own file and put this inside of your rendering function at the very bottom.
requestAnimationFrame(yourrenderingfunction);
Live Demo
// requestAnimationFrame shim
(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.cancelRequestAnimationFrame = 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);
};
}())
// Sprite unimportant, just for example purpose
function Sprite(){
this.x = 0;
this.y = 50;
}
Sprite.prototype.draw = function(){
ctx.fillStyle = "rgb(255,0,0)";
ctx.fillRect(this.x, this.y, 10, 10);
}
// setup
var canvas = document.getElementsByTagName("canvas")[0],
ctx = canvas.getContext("2d");
canvas.width = 200;
canvas.height = 200;
//init the sprite
var sprite = new Sprite();
// draw the sprite and update it using request animation frame.
function update(){
ctx.clearRect(0,0,200,200);
sprite.x+=0.5;
if(sprite.x>200){
sprite.x = 0;
}
sprite.draw();
// makes it update everytime
requestAnimationFrame(update);
}
// initially calls the update function to get it started
update();