DIV changing shape unexpectedly - javascript

I'm trying to draw a circle in a canvas to match the dimensions of a div. I can't understand what's wrong here (aside from the bad style), as the result is an ellipsis, which looks like the canvas size has been stretched after the drawing (JSFiddle here):
$(document).ready(function() {
scrH = $(window).height();
scrW = $(window).width();
// place map
$('body').append("<div id='pagUserStart_map1' style='border:5px solid red;'></div>");
var map = $("#pagUserStart_map1");
map.css("width", scrW - 60 + "px");
map.css("height", map.css("width"));
map.css("top", scrH / 2 - map.height()/2);
map.css("left", (scrW - map.width()) / 2);
map.css("position", "absolute");
map.css("margin", "0 auto");
map.css("border-radius", "50%");
map.css("z-index", "100");
//place canvas
$('body').append("<canvas id='canvas1'></canvas>");
var canvas = $("#canvas1");
canvas.width(map.width());
canvas.height(canvas.width());
canvas.css("position", "absolute");
canvas.position({
my: "center",
at: "center",
of: map
});
canvas = document.getElementById("canvas1");
// draw circle in canvas
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height /2 ;
var radius = 50;
context.beginPath();
context.arc(centerX, centerY, 50, 0, 2 * Math.PI, false);
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 10;
context.shadowColor = '#656565';
context.lineWidth = 10;
context.strokeStyle = '#B8CADE';
context.stroke();
});
I understand that something goes wrong between when I use JQuery to reference 'canvas1' and when I use getElementById. But why? It seems like the code is not executed sequentially. I've lost a few hours googling around and playing with the code... I really need your help.

You need to set Canvas size correctly:
canvas.attr('width', map.width());
canvas.attr('height', map.height());
And you will recieve this:
http://i.stack.imgur.com/5UsGQ.png

Set the canvas element width instead of the canvas css width:
// draw circle in canvas
canvas = document.getElementById("canvas1");
canvas.width=map.width();
canvas.height=map.height();
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height /2 ;
var radius = 50;

Simple change your absolute position to fixed.
Like this
$(document).ready(function() {
scrH = $(window).height();
scrW = $(window).width();
// place map
$('body').append("<div id='pagUserStart_map1' style='border:5px solid red;'></div>");
var map = $("#pagUserStart_map1");
map.css("width", scrW - 60 + "px");
map.css("height", map.css("width"));
map.css("top", scrH / 2 - map.height()/2);
map.css("left", (scrW - map.width()) / 2);
map.css("position", "fixed");
map.css("margin", "0 auto");
map.css("border-radius", "50%");
map.css("z-index", "100");
//place canvas
$('body').append("<canvas id='canvas1'></canvas>");
var canvas = $("#canvas1");
canvas.width(map.width());
canvas.height(canvas.width());
canvas.css("position", "fixed");
canvas.position({
my: "center",
at: "center",
of: map
});

Related

How to mirror and reverse a movement of a canvas object?

So I have two objects. SquareA and SquareB. SquareA follows the movement of the cursor. Now I want to make SquareB mirror the movement of SquareA but in reverse.
Example:
SquareA goes left, SquareB goes right.
SquareA goes down, SquareB goes up.
I currently have this code to make squareB follow squareA
// update squareA to mouse
squareA.x = mouseX - (squareB.width * .5);
squareA.y = mouseY - (squareB.height * .5);
// update squareB to squareA
squareB.x = squareA.x;
squareB.y = squareA.y - (squareA.height * 2);
But I can't think of a way to reverse squareB's movement.
Here's the pen for the problem
https://codepen.io/ricjonsu098/pen/xxZrvZP?editors=0010
Full solution:
// create a canvas to work with
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
// style canvas
canvas.id = "canvas";
canvas.width = 400;
canvas.height = 400;
canvas.setAttribute("style", "border: 1px solid black;");
// get 2D context
var context = canvas.getContext('2d');
var squareA = {x:10, y:30, width: 25, height: 25 };
var squareB = {x:10, y:30, width: 25, height: 25 };
// place holders for mouse x,y position
var mouseX = 0;
var mouseY = 0;
var centerX = canvas.width/2;
var centerY = canvas.height/2;
// Render Loop
function update() {
// update squareA to mouse
squareA.x = mouseX - (squareB.width * .5);
squareA.y = mouseY - (squareB.height * .5);
// update squareB to squareA
squareB.x = centerX - (squareA.x - centerX);
squareB.y = centerY - (squareA.y - centerY);
// clear the canvas
canvas.width = canvas.width;
// draw first rectangle
context.fillStyle = "blue";
context.fillRect (squareA.x,squareA.y,squareA.width,squareA.height);
// draw second rectangle
context.fillStyle = "green";
context.fillRect (squareB.x,squareB.y,squareB.width,squareB.height);
}
// update mouse position
canvas.onmousemove = function(e) {
mouseX = e.offsetX;
mouseY = e.offsetY;
update();
}
Note that I got rid of the interval. You can just update whne the mouse moves.
I hope this helps, 400 is canvas size
// update squareA to mouse
squareA.x = mouseX;
squareA.y = mouseY;
// update squareB to squareA
squareB.x = 400 - squareA.x;
squareB.y = 400 - squareA.y;

Divide whole canvas in equal columns

I am trying to divide my whole canvas in 20 equal columns and animate them individually on the y-axis. The goal is to create a similar wave scroll animation like here. First I tried to create the wave scroll effect with php generated images with the text on it and tried to animate them in single divs with the images as background-images. It technically worked but the performance and page load time was extremely bad. Now I want to create it with canvas: I already have the content with all the images and text in it and tried to animate it. I tried to save the whole content in columns (rectangles) with getImageData() then I created created rectangles with the ImageData and re-draw them in a loop but again the performance was terrible, especially on mobile devices. The animation loop looked as followed:
var animate = function(index, y) {
// The calculations required for the step function
var start = new Date().getTime();
var end = start + duration;
var current = rectangles[index].y;
var distance = y - current;
var step = function() {
// get our current progress
var timestamp = new Date().getTime();
var progress = Math.min((duration - (end - timestamp)) / duration, 1);
context.clearRect(rectangles[index].x, rectangles[index].y, columnWidth, canvas.height);
// update the rectangles y property
rectangles[index].y = current + (distance * progress);
context.putImageData(rectangles[index].imgData, rectangles[index].x, rectangles[index].y);
// if animation hasn't finished, repeat the step.
if (progress < 1)
requestAnimationFrame(step);
};
// start the animation
return step();
};
Now the question: How can I divide the whole canvas in equal columns and animate them on the y-axis with a good performance? Any suggestions? Maybe with the help of Pixi.js / Greensock? Thanks in advance!
Do not use getImageData and setImageData to do animation. The canvas is an image and can be rendered just like any image.
To do what you want
Create a second copy of the canvas and use that canvas a source for the strips you want to render.
Example.
const slices = 20;
var widthStep;
var canvas = document.createElement("canvas");
var canvas1 = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.top = canvas.style.left = "0px";
var ctx = canvas.getContext("2d");
var ctx1 = canvas1.getContext("2d");
var w = canvas.width;
var h = canvas.height;
function resize(){
canvas.width = canvas1.width = innerWidth;
canvas.height = canvas1.height = innerHeight;
w = canvas.width;
h = canvas.height;
ctx1.font = "64px arial black";
ctx1.textAlign = "center"
ctx1.textBaseLine = "middle";
ctx1.fillStyle = "blue";
ctx1.fillRect(0,0,w,h);
ctx1.fillStyle = "red";
ctx1.fillRect(50,50,w-100,h-100);
ctx1.fillStyle = "black";
ctx1.strokeStyle = "white";
ctx1.lineWidth = 5;
ctx1.lineJoin = "round";
ctx1.strokeText("Waves and canvas",w / 2, h / 2);
ctx1.fillText("Waves and canvas",w / 2, h / 2);
widthStep = Math.ceil(w / slices);
}
resize();
window.addEventListener("resize",resize);
document.body.appendChild(canvas);
function update(time){
var y;
var x = 0;
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i = 0; i < slices; i ++){
y = Math.sin(time / 500 + i / 5) * (w / 8);
y += Math.sin(time / 700 + i / 7) * (w / 13);
y += Math.sin(time / 300 + i / 3) * (w / 17);
ctx.drawImage(canvas1,x,0,widthStep,h,x,y,widthStep,h);
x += widthStep;
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);

Canvas saving and restoring

I have a canvas that i need to change the height for after every bit of content is added - the only way for me to get a dynamic canvas height. I'm trying to use save and restore so i don't lose all the styles, settings etc.
I can't get save and restore to work. I must be doing something wrong or is this the wrong approach?
function DrawLeftText(text) {
var canvas = document.getElementById('canvasPaper');
if (canvas.getContext) {
var context = canvas.getContext('2d');
context.textAlign = 'left';
context.font = 'normal 20px Monkton';
context.fillText(text, leftPosition, cursor);
context.textAlign = 'start';
context.save();
}
}
function restoreSettings(){
var canvas = document.getElementById('canvasPaper');
if (canvas.getContext) {
var context = canvas.getContext('2d');
context.restore();
}
}
function onDrawReceipt() {
var canvas = document.getElementById('canvasPaper');
if (canvas.getContext) {
var context = canvas.getContext('2d');
context.textBaseline = 'top';
lineSpace = 20;
leftPosition = 0;
// centerPosition = canvas.width / 2;
centerPosition = (canvas.width + 26) / 2;
// rightPosition = canvas.width;
rightPosition = (canvas.width - 0);
// cursor = 0;
cursor = 80;
context.fillRect(25, cursor - 2, 526, 2); cursor += lineSpace;
context.fillRect(25, cursor - 2, 526, 2); cursor += lineSpace;
DrawCenterText(company['name']); cursor += lineSpace;
DrawCenterText(company['address']['address_line_1']); cursor += lineSpace;
DrawCenterText(company['address']['city'].toUpperCase()); cursor += lineSpace;
DrawCenterText(company['address']['postcode']); cursor += lineSpace;
context.clearRect(0, 0, canvas.width, canvas.height += 20);
**//increasing the height and then trying to restore**
restoreSettings();
}
}
////// Additional attempt. I've tried the following too without luck.
////// None of the content appears despite setting the height before adding the content??
var header = function headerSection(){
var height = cursor;
canvas.height += height;
context.textBaseline = 'top';
lineSpace = 20;
leftPosition = 0;
centerPosition = (canvas.width + 26) / 2;
rightPosition = (canvas.width - 0);
console.log(height);
console.log(context);
context.fillRect(25, cursor - 2, 526, 2); cursor += lineSpace;
context.fillRect(25, cursor - 2, 526, 2); cursor += lineSpace;
DrawCenterText(company['name']); cursor += lineSpace;
DrawCenterText(company['address']['address_line_1']); cursor += lineSpace;
DrawCenterText(company['address']['city'].toUpperCase()); cursor += lineSpace;
DrawCenterText(company['address']['postcode']); cursor += lineSpace;
console.log(canvas.height);
return;
}
header()
I would suggest the following approach at the cost of a little more memory (if you're dealing with very large canvases you will of course have to weight in memory concern) -
Use an internal larger canvas representing a max size (or block size1)
Keep a value representing the current height (not actual)
Create a visual canvas in the document at the height stored in the value
For every draw operation, draw to the internal canvas
When done, set the visual canvas height using the current height value, draw internal canvas to visual one
Example 1
This example uses this technique to draw text at random color. As you can see we do not need to redraw the text when we change the visual canvas' size, we just copy everything from the internal canvas which also contains the current styles (font, font size, fill style).
var vcanvas = document.querySelector("canvas"),
vctx = vcanvas.getContext("2d"),
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
line = 25,
maxHeight = 7 * line,
currentHeight = line,
chars = "abcdefghijklmnowxyzABCD#/&%/(#)=!LMNOPQRSTUVWXYZ".split(""),
x = 0, y = 0, ch;
vcanvas.height = currentHeight;
// internal canvas setup
ctx.font = "20px sans-serif";
ctx.textBaseline = "top";
// draw someting to internal canvas:
(function loop() {
ch = chars[(Math.random() * chars.length)|0];
ctx.fillStyle = "hsl(" + (360*Math.random()) + ",75%,50%)";
ctx.fillText(ch, x, y);
x += ctx.measureText(ch).width;
if (x > canvas.width) {
x = 0; y += line; currentHeight += line;
}
// copy to visual canvas:
if (currentHeight < maxHeight) vcanvas.height = currentHeight;
vctx.drawImage(canvas, 0, 0, canvas.width, currentHeight,
0, 0, canvas.width, currentHeight);
if (currentHeight < maxHeight) setTimeout(loop, 50);
})();
body{background:#eee} canvas{background:#fff}
canvas{border:1px solid #000}
<canvas></canvas>
1) If you are dealing with "infinite" height you want to split the process into blocks. Set internal canvas to block size, when exceeded enlarge internal canvas with new block size - but here you will have to do full redraw and setup again.
And this leads to option 2: The latter technique can be used directly with the visual canvas as well, and you can use CSS to clip it putting it inside a div element which you style with height and overflow:hidden.
Example 2
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
div = document.querySelector("div"),
line = 25,
maxHeight = 7 * line,
currentHeight = line,
chars = "abcdefghijklmnowxyzABCD#/&%/(#)=!LMNOPQRSTUVWXYZ".split(""),
x = 0, y = 0, ch;
// set canvas to max height, div to clip height
canvas.height = maxHeight;
div.style.height = currentHeight + "px";
// canvas setup
ctx.font = "20px sans-serif";
ctx.textBaseline = "top";
// draw someting to the canvas:
(function loop() {
ch = chars[(Math.random() * chars.length)|0];
ctx.fillStyle = "hsl(" + (360*Math.random()) + ",75%,50%)";
ctx.fillText(ch, x, y);
x += ctx.measureText(ch).width;
if (x > canvas.width) {
x = 0; y += line; currentHeight += line;
}
// copy to visual canvas:
if (currentHeight < maxHeight) {
div.style.height = currentHeight + "px"; // increase clipping height
setTimeout(loop, 50)
}
})();
body{background:#eee} canvas{background:#fff}
div{border:1px solid #000; overflow:hidden; width:302px}
<div><canvas></canvas></div>
Resizing the canvas element will always reset its context to the default style states. (.save & .restore will not let the context styles survive a resizing)
The common canvas pattern to deal with changes to canvas content is:
Save data (eg your company)
Either save context styles as javascript variables or embed the style changes in functions (eg a specialized function to set appropriate styles and redraw the company heading).
Resize (or clear) the canvas
Redraw all the content using the saved data and saved styles/functions.
Example code:
Click "Full page" to see full receipt
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var lineSpace=20;
var leftOfForm=25;
var topOfForm=80;
var testingItems=110;
var company={
name:'MyCompany, Inc',
address:{
address_line_1: '123 Main Street',
city:'Anytown, Anywhere',
postcode:'12345'
}
}
var lineItems=[];
addLineItem(testingItems,'Description of sku#'+testingItems,testingItems);
$('#test').click(function(){
testingItems++;
addLineItem(testingItems,'Description of sku#'+testingItems,testingItems);
draw();
});
draw();
function addLineItem(sku,description,price){
lineItems.push({
sku:sku,
description:description,
price:price
});
}
function draw(){
// note: changing canvas.height auto-erases the content also
canvas.height=topOfForm+(6+2+lineItems.length)*lineSpace;
ctx.strokeRect(0,0,canvas.width,canvas.height);
drawHeader(leftOfForm,topOfForm);
for(var i=0;i<lineItems.length;i++){
drawLineItem(lineItems[i],leftOfForm,topOfForm+(6+2+i)*lineSpace);
}
}
function drawHeader(left,cursor){
var cx=canvas.width/2;
var line=function(linecount){ return(cursor+lineSpace*linecount); }
ctx.save();
ctx.beginPath();
ctx.moveTo(left,line(0)-2);
ctx.lineTo(526,line(0)-2);
ctx.moveTo(left,line(1)-2);
ctx.lineTo(526,line(1)-2);
ctx.lineWidth=2;
ctx.stroke();
ctx.font='18px verdana';
ctx.textAlign='center';
ctx.textBaseline='top';
ctx.fillText(company.name,cx,line(2));
ctx.fillText(company.address.address_line_1,cx,line(3));
ctx.fillText(company.address.city,cx,line(4));
ctx.fillText(company.address.postcode,cx,line(5));
ctx.restore();
}
function drawLineItem(item,left,cursor){
ctx.save();
ctx.font='14px verdana';
ctx.textAlign='left';
ctx.textBaseline='top';
ctx.fillText(item.sku,left,cursor);
ctx.fillText(item.description,left+40,cursor);
ctx.textAlign='right';
ctx.fillText(item.price,left+450,cursor);
ctx.restore();
}
body{ background-color: ivory; padding:10px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=test>Add another line</button>
<br>
<canvas id="canvas" width=550 height=300></canvas>

Highlighting part in canvas arc using Javascript or jQuery

I have drawn an arc on a canvas, this arc has 3 parts. If user clicks on any one of the part then my code will show an alert with the x and y position. Now I want to highlight this clicked region. How do I do that?
This code draws the arc:
var canvas = document.getElementById('zone');
if(!canvas.getContext){
alert("canvas not supported");
}
else {
var canvasContent = canvas.getContext('2d');
var zoneX = canvas.width / 2;
var zoneY = canvas.height / 2;
var radius = 100;
canvasContent.beginPath();
canvasContent.arc(zoneX,zoneY, radius, 0, 2 * Math.PI, false);
canvasContent.fillStyle = 'white';
canvasContent.fill();
canvasContent.lineWidth = 1;
canvasContent.strokeStyle = '#333';
canvasContent.stroke();
drawLine(canvasContent);
$('#zone').on('click',function(e){
var clickX = e.clientX;
var clickY = e.clientY;
alert(clickX + " : "+clickY);
});
}
function drawLine(canvasContentDrawLine) {
canvasContentDrawLine.beginPath();
canvasContentDrawLine.moveTo(canvas.width / 2, canvas.width / 2);
canvasContentDrawLine.lineTo(canvas.width / 2.5, canvas.height / 4.7);
canvasContentDrawLine.moveTo(338, 200 );
canvasContentDrawLine.lineTo(canvas.width / 2.5, canvas.height / 4.7);
canvasContentDrawLine.stroke();
}
Fiddle
This code will show an alert with the position:
$('#zone').on('click',function(e){
var clickX = e.clientX;
var clickY = e.clientY;
alert(clickX + " : "+clickY);
});

KineticsJs auto resize canvas

My autoresize canvas not works with kineticjs, the console say me that canvas.width and canvas.height is not defined.
Any people could help me.
Thank you .
Put the function and the call down.
function resize() {
console.log("ddddddddddddd");
//stage.setWidth((window.innerWidth / 100) * 80);
var canvas = document.getElementById('Contenedor');
console.log(canvas, canvas.height, canvas.width);
if(window.innerWidth < 1280){
var canvasRatio = canvas.height / canvas.width;
console.log(canvasRatio);
var windowRatio = window.innerHeight / window.innerWidth;
console.log(windowRatio);
var width;
var height;
if (windowRatio < canvasRatio) {
height = window.innerHeight;
width = height / canvasRatio;
} else {
width = window.innerWidth;
height = width * canvasRatio;
}
canvas.style.width = (parseFloat(width)*0.75) + 'px';
canvas.style.height = (parseFloat(height)*0.75) + 'px';
}else{
canvas.style.width=987+'px';
canvas.style.height=544+'px';
}
};
window.addEventListener('resize', resize, false);
What you can do is set the height of the canvas with respect to the width.
And use stage.setScale() and stage.setSize() to dynamically change the size of the stage
function resize() {
var canvasWidthRatio = 0.6; // canvas width to viewport width ratio
var viewPortWidth = window.innerWidth;
var canvasWidth = viewPortWidth * canvasWidthRatio;
var canvasHeight = canvasWidth * 0.6,
scale = stage.getScale(),
stageWidth = stage.getWidth(),
stageHeight = stage.getHeight(),
scaleFactor = Math.min(canvasWidth / stageWidth, canvasHeight / stageHeight),
newScale = scale * scaleFactor;
stage.setScale(newScale);
stage.setSize(canvasWidth, canvasHeight);
stage.draw();
}
window.addEventListener('resize', resize, false);
I think kineticjs sets the canvas dimensions.
set the stage width and height and don't touch the canvas directly.
Hello and sorry my bad english, also thank you to help me. I work with the code of VijayB, but with his code I have problems with multiply the object scale with a float.. I realease a few changes and for me are working.
I put the code for someone that have my own problem.
function resize() {
var __canvasWidthRatio = 0.6;
console.log( __canvasWidthRatio) ; // canvas width to viewport width ratio
var __viewPortWidth = window.innerWidth;
console.log(window.innerWidth);
var __canvasWidth = __viewPortWidth * __canvasWidthRatio;
console.log(__canvasWidth);
var aspec = 769 / 544;
var __canvasHeight = aspec *__canvasWidth * __canvasWidthRatio;
var __scale = ui.stage.getScale();
var __stageWidth = ui.stage.getWidth();
var __stageHeight = ui.stage.getHeight();
var __scaleFactor = Math.min( __canvasWidth / __stageWidth, __canvasHeight / __stageHeight);
stage.escala= __scale.x *__scaleFactor;
ui.scale=__scale.x *__scaleFactor;
stage.setScale(stage.escala,stage.escala);
stage.setSize(__canvasWidth, __canvasHeight);
stage.draw();
}
window.addEventListener('resize', resize, false);

Categories

Resources