<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Mouse over <canvas> does not draw.
var TILE_WIDTH = 30;
var TILE_HEIGHT = 30;
document.getElementById("input").onchange = function() {
var reader = new FileReader();
reader.onload = function(e) {
// get loaded data and render thumbnail.
document.getElementById("image").src = e.target.result;
};
// read the image file as a data URL.
reader.readAsDataURL(this.files[0]);
};
// The first function call to create photomosaic
function photomosaic(image) {
// Dimensions of each tile
var tileWidth = TILE_WIDTH;
var tileHeight = TILE_HEIGHT;
// creating the canvas for photomosaic
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
canvas.height = image.height;
canvas.width = image.width;
var imageData = context.getImageData(0, 0, image.width, image.height);
var pixels = imageData.data;
// The Number of mosaic tiles
var numTileRows = image.width / tileWidth;
var numTileCols = image.height / tileHeight;
// The canvas copy of image
var imageCanvas = document.createElement('canvas');
var imageCanvasContext = canvas.getContext('2d');
imageCanvas.height = image.height;
imageCanvas.width = image.width;
imageCanvasContext.drawImage(image, 0, 0);
// A function for finding the average color
function averageColor(row, column) {
var blockSize = 1, // we can set how many pixels to skip
data, width, height,
i = -4,
length,
rgb = {
r: 0,
g: 0,
b: 0
},
count = 0;
try {
data = imageCanvasContext.getImageData(column * TILE_WIDTH, row * TILE_HEIGHT, TILE_HEIGHT, TILE_WIDTH);
} catch (e) {
alert('Not happening this time!');
return rgb;
}
length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return rgb;
}
// Loop through each tile
for (var r = 0; r < numTileRows; r++) {
for (var c = 0; c < numTileCols; c++) {
// Set the pixel values for each tile
var rgb = averageColor(r, c)
var red = rgb.r;
var green = rgb.g;
var blue = rgb.b;
// Loop through each tile pixel
for (var tr = 0; tr < tileHeight; tr++) {
for (var tc = 0; tc < tileWidth; tc++) {
// Calculate the true position of the tile pixel
var trueRow = (r * tileHeight) + tr;
var trueCol = (c * tileWidth) + tc;
// Calculate the position of the current pixel in the array
var pos = (trueRow * (imageData.width * 4)) + (trueCol * 4);
// Assign the colour to each pixel
pixels[pos + 0] = red;
pixels[pos + 1] = green;
pixels[pos + 2] = blue;
pixels[pos + 3] = 255;
};
};
};
};
// Draw image data to the canvas
context.putImageData(imageData, 0, 0);
return canvas;
}
function create() {
var image = document.getElementById('image');
var canvas = photomosaic(image);
document.getElementById("output").appendChild(canvas);
};
#output,
.container {
text-align: center;
}
.inputDiv {
margin: 20px 0px;
}
#image {
width: 300px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<div class="container">
<img id="image" src="https://via.placeholder.com/100" />
<div class="inputDiv">
<input id="input" type="file" accept="image/*">
<button onclick="create()">create</button>
</div>
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
</canvas>
<div id='output'></div>
</div>
</body>
</html>
How do I create a circle when I touch the mouse? I'm sorry for the poor translation. This is the only place to ask. I'm also sorry that the code is very long. Not applicable to script ...
Related
New to HTML canvas. I got a good pointer for the wave generation using Shovan Dhara
codes.
However i want to achieve a floating rectangle at the top of this wave. Any pointer would be useful.
Thanks.
P.S: find code below:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Oscillators</title>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
background:#e6e5e5;
}
</style>
<script type='text/javascript'>
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
//<![CDATA[
window.onload=function(){
/**
* Wave oscillators by Ken Fyrstenberg Nilsen
* http://abdiassoftware.com/
*
* CC-Attribute 3.0 License
*/
var ctx = canvas.getContext('2d'),
w, h;
canvas.width = w = window.innerWidth * 1.1;
canvas.height = h = window.innerHeight * 1;
var osc1 = new osc(),
osc2 = new osc(),
osc3 = new osc(),
horizon = h * 0.5;
count = 40,
step = Math.ceil(w / count),
//points = new Array(count);
buffer = new ArrayBuffer(count * 4),
points = new Float32Array(buffer);
osc1.max = 15;//h * 0.7;
osc2.max = 5;
osc2.speed = 0.03;
osc2.max = 5;
osc2.speed = 0.015;
function fill() {
for(var i = 0; i < count; i++) {
points[i] = mixer(osc1, osc2, osc3);
}
}
fill();
ctx.lineWidth = 20;
ctx.strokeStyle = '#0000';
ctx.fillStyle = '#1d96d3';
function loop() {
var i;
/// move points to the left
for(i = 0; i < count - 1; i++) {
points[i] = points[i + 1];
}
/// get a new point
points[count - 1] = mixer(osc1, osc2, osc3);
ctx.clearRect(0, 0, w, h);
//ctx.fillRect(0, 0, w, h);
/// render wave
ctx.beginPath();
ctx.moveTo(-5, points[0]);
for(i = 1; i < count; i++) {
ctx.lineTo(i * step, points[i]);
}
ctx.lineTo(w, h);
ctx.lineTo(-5, h);
ctx.lineTo(-5, points[1]);
ctx.stroke();
ctx.fill();
ctx.strokeRect(100,h/2,150,100);
}
/// oscillator object
function osc() {
this.variation = 0.4;
this.max = 150;
this.speed = 0.02;
var me = this,
a = 0,
max = getMax();
this.getAmp = function() {
a += this.speed;
if (a >= 2.0) {
a = 0;
max = getMax();
}
return max * Math.sin(a * Math.PI);
}
function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}
return this;
}
function mixer() {
var d = arguments.length,
i = d,
sum = 0;
if (d < 1) return 0;
while(i--) sum += arguments[i].getAmp();
return sum / d + horizon;
}
(function animloop(){
requestAnimFrame(animloop);
loop();
})();
}//]]>
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
I took width of the screen and divided it by points number then I calculated which point to use for the box Y coordinate for given X coordinate based on its dimensions. points are just Y coordinates, so the height of a wave in the point.
Those are my calculations:
var rectX = 500;
var rectWidth = 200;
var rectHeight = 100;
var centerX = rectX + rectWidth / 2;
var pointToUse = Math.floor(centerX / (w / points.length));
And I draw the box like this:
ctx.strokeRect(rectX, points[pointToUse] - rectHeight, rectWidth, rectHeight);
You can make it more submerged by adding some to points[pointToUse] - rectHeight
You may also add safety checks for points.length != 0 and (w / points.length) != 0
Here is working snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Oscillators</title>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
background:#e6e5e5;
}
</style>
<script type='text/javascript'>
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
//<![CDATA[
window.onload=function(){
/**
* Wave oscillators by Ken Fyrstenberg Nilsen
* http://abdiassoftware.com/
*
* CC-Attribute 3.0 License
*/
var ctx = canvas.getContext('2d'),
w, h;
canvas.width = w = window.innerWidth * 1.1;
canvas.height = h = window.innerHeight * 1;
var osc1 = new osc(),
osc2 = new osc(),
osc3 = new osc(),
horizon = h * 0.5;
count = 40,
step = Math.ceil(w / count),
//points = new Array(count);
buffer = new ArrayBuffer(count * 4),
points = new Float32Array(buffer);
osc1.max = 15;//h * 0.7;
osc2.max = 5;
osc2.speed = 0.03;
osc2.max = 5;
osc2.speed = 0.015;
function fill() {
for(var i = 0; i < count; i++) {
points[i] = mixer(osc1, osc2, osc3);
}
}
fill();
ctx.lineWidth = 20;
ctx.strokeStyle = '#0000';
ctx.fillStyle = '#1d96d3';
var rectX = 200;
var rectWidth = 100;
var rectHeight = 50;
var centerX = rectX + rectWidth / 2;
var pointToUse = Math.floor(centerX / (w / points.length));
function loop() {
var i;
/// move points to the left
for(i = 0; i < count - 1; i++) {
points[i] = points[i + 1];
}
/// get a new point
points[count - 1] = mixer(osc1, osc2, osc3);
ctx.clearRect(0, 0, w, h);
//ctx.fillRect(0, 0, w, h);
/// render wave
ctx.beginPath();
ctx.moveTo(-5, points[0]);
for(i = 1; i < count; i++) {
ctx.lineTo(i * step, points[i]);
}
ctx.lineTo(w, h);
ctx.lineTo(-5, h);
ctx.lineTo(-5, points[1]);
ctx.stroke();
ctx.fill();
ctx.strokeRect(rectX, points[pointToUse] - rectHeight, rectWidth, rectHeight);
}
/// oscillator object
function osc() {
this.variation = 0.4;
this.max = 150;
this.speed = 0.02;
var me = this,
a = 0,
max = getMax();
this.getAmp = function() {
a += this.speed;
if (a >= 2.0) {
a = 0;
max = getMax();
}
return max * Math.sin(a * Math.PI);
}
function getMax() {
return Math.random() * me.max * me.variation +
me.max * (1 - me.variation);
}
return this;
}
function mixer() {
var d = arguments.length,
i = d,
sum = 0;
if (d < 1) return 0;
while(i--) sum += arguments[i].getAmp();
return sum / d + horizon;
}
(function animloop(){
requestAnimFrame(animloop);
loop();
})();
}//]]>
</script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
<!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.
I draw varicolored canvas and on click redraw it and draw black rectangles. But rectangles does not remove! What I'm doing wrong?
Demo:
http://jsfiddle.net/82nnJ/
function draw_palette() {
$c = document.getElementById('palette');
$ctx = $c.getContext('2d');
var size = 256;
$ctx.clearRect(0, 0, size, size); //
var r = 255;
var a = 255;
for (var g = 0; g < size; g++) {
for (var b = 0; b < size; b++) {
$ctx.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + (a/255) + ")";
$ctx.fillRect(g, b, 1, 1);
}
}
}
jQuery(document).ready(function() {
draw_palette();
$('#palette').click(function(e) {
draw_palette();
var x = e.pageX - $(this).position().left;
var y = e.pageY - $(this).position().top;
var radius = 5;
$ctx.rect(x-radius, y-radius, 2*radius+1, 2*radius+1);
$ctx.strokeStyle = 'black';
$ctx.stroke();
});
});
There should be beginPath and closePath methods.
$ctx.beginPath();
$ctx.rect(x-radius, y-radius, 2*radius+1, 2*radius+1);
$ctx.strokeStyle = 'black';
$ctx.stroke();
$ctx.closePath();
I just solved a similar issue. I have a chart that was programmed in javascript on the web-side and a server transmitting data to the chart. Used websockets to update the chart on a realtime basis.
Basically in the onmessage event the Canvas object was destroyed and constructed using the DOM. With the previous object destroyed this ensures that it repaints correctly.
Here's what I did...
var c = document.getElementsByName("myCanvas")[0];
if (c != null)
{
c.remove();
}
var c = document.createElement("canvas");
c.setAttribute("name", "myCanvas");
c.setAttribute("width", 900);
c.setAttribute("height", 600);
c.setAttribute("style", "border:1px solid #d3d3d3");
var ctx = c.getContext("2d");
document.body.append(c);
I have a html5 canvas that draws a sound wave. I have set the background as an background image, however, I want this background image to repeat. Can anyone tell me how I would do this and what I need to add into my code:
var backgroundImage = new Image();
backgroundImage.src = 'http://www.samskirrow.com/client-kyra/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);
// left wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(6 * i, 257 + waveLeft[i] * 80.);
}
context.lineWidth = 1;
context.strokeStyle = "#000";
context.stroke();
// right wave
context.beginPath();
context.moveTo(0, 256);
for ( var i = 0; i < 256; i++) {
context.lineTo(6 * i, 256 + waveRight[i] * 80.);
}
context.lineWidth = 1;
context.strokeStyle = "#000";
context.stroke();
}
function updateWave(sound) {
waveLeft = sound.waveformData.left;
}
return {
init : init
};
})();
You can see this code in action here:
http://www.samskirrow.com/client-kyra
Use the canvas' createPattern function
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = 'https://www.google.nl/images/srpr/logo3w.png';
img.addEventListener('load', () => {
const ptrn = context.createPattern(img, 'repeat'); // Create a pattern with this image, and set it to "repeat".
context.fillStyle = ptrn;
context.fillRect(0, 0, canvas.width, canvas.height); // context.fillRect(x, y, width, height);
})
<canvas id="canvas" width="600px" height="600px"></canvas>
(This is the fastest of the 2 samples).
Or, try a manual implementation:
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = 'https://www.google.nl/images/srpr/logo3w.png';
img.addEventListener('load', () => {
for (let w = 0; w < canvas.width; w += img.width) {
for (let h = 0; h < canvas.height; h += img.height) {
context.drawImage(img, w, h);
}
}
})
<canvas id="canvas" width="600px" height="600px"></canvas>
I've been searching everywhere and couldn't find how to draw a grid on an HTML5 Canvas. I'm new to HTML5 and canvas.
I know how to draw shapes but this drawing grid is taking forever to understand.
Can someone help me on this?
The answer is taken from here Grid drawn using a <canvas> element looking stretched
Just edited it a little, hope it helps
// Box width
var bw = 400;
// Box height
var bh = 400;
// Padding
var p = 10;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
function drawBoard(){
for (var x = 0; x <= bw; x += 40) {
context.moveTo(0.5 + x + p, p);
context.lineTo(0.5 + x + p, bh + p);
}
for (var x = 0; x <= bh; x += 40) {
context.moveTo(p, 0.5 + x + p);
context.lineTo(bw + p, 0.5 + x + p);
}
context.strokeStyle = "black";
context.stroke();
}
drawBoard();
body {
background: lightblue;
}
#canvas {
background: #fff;
margin: 20px;
}
<div>
<canvas id="canvas" width="420px" height="420px"></canvas>
</div>
// Box width
var bw = 270;
// Box height
var bh = 180;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
function drawBoard(){
context.lineWidth = 10;
context.strokeStyle = "rgb(2,7,159)";
for (var x = 0; x < bw; x += 90) {
for (var y = 0; y < bh; y += 90) {
context.strokeRect(x+10, y+10, 90, 90);
}
}
}
drawBoard();
This code allows for a scalable / resize grid
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
function drawBoard()
{
// canvas dims
const bw = window.innerWidth
const bh = window.innerHeight
const lw = 1 // box border
const boxRow = 10 // how many boxes
const box = bw / boxRow // box size
ctx.lineWidth = lw
ctx.strokeStyle = 'rgb(2,7,159)'
for (let x=0;x<bw;x+=box)
{
for (let y=0;y<bh;y+=box)
{
ctx.strokeRect(x,y,box,box)
}
}
}
let rTimeout = null
window.addEventListener('resize', (e) =>
{
clearTimeout(rTimeout)
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
rTimeout = setTimeout(function(){drawBoard()}, 33)
})
drawBoard()
<canvas id="canvas"></canvas>