I am using the visualisation arborjs and I am trying to implement the zoom-function. This isn't included in the visualisation itself so I had to try some different approches.
I can't use the html5 canvasfunction .scale because with this the positions given by the visualisation don't match the real positions anymore.
For the moment I just increase the height and width of the canvas to zoom in. This doesn't give any problems with the positioningproblem, but I can't scroll in the canvas.
The only problem that I have to solve is the scrollfunction to make this work. So my question is: can I add scrollbars to the canvas when the canvas becomes too big.
Initially the canvas has width 100% and height 100%, so no scrollbars are needed, but when I enlarge this I need those scrollbars.
I tried the css-style overflow:scroll for both the canvas and the surrounding div, but no results.
Here is the relevant code:
HTML:
<div class="explore_area">
<canvas class="explore_area" id="viewport">
</canvas>
</div>
javascript:
zoom: function(){
var canvas = document.getElementById("viewport");
var ctx = canvas.getContext('2d');
sys.screenSize((canvas.width*1.5), (canvas.height*1.5));
}
css:
div.explore_area {
position:relative;
width:100%;
height:600px;
overflow:hidden;
}
canvas.explore_area{
float:left;
height:550px;
width:100%;
}
Setting the width and height of canvas using css is not a good idea. To achieve what you required you should not give width and height of canvas in css. Even if you change the dimension css will reset it.
so first you need to give dimension like this
<canvas class="explore_area" id="viewport" width="400" height="300">
css for container
div.explore_area {
position:relative;
width:400px;
height:300px;
overflow:auto;
}
see the demo here : http://jsfiddle.net/diode/sHbKD/22/ ( not using arborjs)
I can't use the html5 canvasfunction .scale because with this the positions given by the visualisation don't match the real positions anymore.
What do you mean by that ?? If you want to draw an image same place, but zoomed, you can do :
ctx.save();
ctx.scale(ratio, ratio);
ctx.drawImage(myImage, x/ratio, y/ratio ) ;
ctx.restore();
Or if you want to zoom from the middle of the image :
ctx.save();
ctx.translate(x + myImage.width/2, y + myImage.height/2 );
ctx.scale(ratio, ratio);
ctx.drawImage(myImage, - myImage.width/(2*ratio), - myImage.width/(2*ratio) ) ;
ctx.restore();
Rq : For clarity, i did not use Math.floor() on drawImage coordinates, but do it to save draw time in
case your ratio (or your coordinates) are not integer.
My solution is to append a <div>(position:absolute) covering the canvas. It's not good if canvas has interactive.
Related
I am starting a small javascript project and I want to define a canvas to be the user's viewport size, so clientHeight/Width
However when I use this methods:
<canvas id="myCanvas" style="border:1px solid #d3d3d3;">
</canvas>
<script>
myCanvas.height = document.documentElement.clientHeight;
myCanvas.width = document.documentElement.clientWidth;
console.log(screen.height);
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillRect(20,20,150,100);
</script>
My canvas is just a little too big for the screen so there are scrollbars
as you can see here
So how exactly should I make the canvas exactly the clients size? Thanks
First, body has a default margin.
body { margin: 0; }
But the canvas still pushes the window down a little because it behaves like an inline element.
canvas { display: block; }
Now (assuming it doesn't still have a border on it like your example, or you use box-sizing: border-box) your canvas' height and width shouldn't be too large to fit in the window. Beware of elements collapsing margins at the top of body as they will still push the canvas down and cause more scrollbars.
Is it possible to skew an image on a canvas to make it appear as a reflection of another image?
Here is an illustration:
I need to flip and skew the image to get the desired effect, but I have not been able to get it to look like that. How can this be achieved?
I have found this example:
http://jsfiddle.net/jpnrzc9y/
ctx.save();
ctx.transform(1,0,0.3,-1,0,0);
ctx.drawImage(tree1,74,-117,20,40);
ctx.restore();
They seem to set the transform based on some random values.
But I cannot make sense of it. The values seem very random to me. Im trying to create a dynamic function that allows me to determine the amount of skew and that works for all images.
You can use context.scale to flip an image vertically:
// flip the canvas vertically
context.scale(1,-1);
Here are the steps to create a skewed reflection of an image:
Move (move==translate) the 0,0 origin to the desired x,y: ctx.translate(x,y);
Draw the original image image: ctx.drawImage(img,0,0);
Move to the bottom of the original image: ctx.translate(0,img.height);
Scale to vertically flip the image: ctx.scale(1,-1);
Apply a skew: ctx.transform(1,0,skewAngle,1,0,0);
Shrink the reflected image (just for aesthetics): ctx.scale(1,0.50);
Make the reflected image 50% opacity: ctx.globalAlpha=0.50;
Draw the reflected image: ctx.drawImage(img,0,-img.height);
Clean up by setting all transforms to default: ctx.setTransform(1,0,0,1,0,0);
Here's example code and a demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/character1.png";
function start(){
// 60x110
skewedReflection(img,25,25)
}
function skewedReflection(img,x,y){
// calc the 45 degree skew angle needed by ctx.transform
var skewAngle=-Math.tan(Math.PI/4);
// move the 0,0 origin to x,y
ctx.translate(x,y);
// draw the original image image
ctx.drawImage(img,0,0);
// move to the bottom of the original image
ctx.translate(0,img.height);
// use scale to flip the image
ctx.scale(1,-1);
// apply a skew
ctx.transform(1,0,skewAngle,1,0,0);
// shrink the reflected image
ctx.scale(1,0.50);
// make the reflected image 50% opacity
ctx.globalAlpha=0.50;
// draw the reflected image
ctx.drawImage(img,0,-img.height);
// clean up by setting all transforms to default
ctx.setTransform(1,0,0,1,0,0);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
Im currently doing something that goes like:
create a canvas and append it to a divider
set a background image via CSS on that canvas.
draw a hexgrid on the canvas
draw PNGs on the canvas.
animate those PNGs to display "movement".
However, its a pain having to redraw the entire canvas including the non-moving PNGs.
Im wondering if it would be smarter or better to have a single canvas for the Background/hexgrid and create the PNGs on additional, small canvas elements which are then zIndex'ed on top of the Background canvas. I then could make the animations (PNGs moving) easier.
However, im running into problems in regards to actually placing the "new" canvas's at the right x/y coordinates of the Background canvas.
this.drawShipImage = function(name, id, x, y){
var div = document.getElementById("grid");
// initial, big canvas with background is created elsewhere but has the same width/height than "grid"
var canvas = document.createElement("canvas");
canvas.id = name + id;
canvas.width = 30;
canvas.height = 30;
canvas.style.position = "absolute";
canvas.style.zIndex = 1;
var context = canvas.getContext("2d");
context.scale(0.75, 0.75);
context.drawImage(ship, 0, 0);
div.appendChild(canvas);
}
Basicly, this function has 2 important Parameters, that is the x/y Parameter where the new canvas SHOULD be drawn in context to the width/height of the Background canvas.
However im unable to conclude a way to get the Image to appear at the right coordinates.
I suppose the only way it could work is adding
canvas.style.margin = x/y-ish
into the mix ?
Using a second canvas (or just an img element holding your background) might be a good solution since your background will be redrawn less frequently than your animated foreground.
This is particularly true if your device has a GPU because the background element will be cached in the GPU and will redraw very quickly as compared with the relatively slower drawings on your animating foreground canvas.
You can use the CSS position property to stack 2 elements.
Wrap your 2 canvases (or canvas + img elements) in a wrapping div.
Set the wrapper div's position property to relative (meaning children will be positioned relative to the wrapper instead of relative to the page).
Set the 2 canvases (or canvas + img elements) position to 'absolute' (meaning they are subject to being positioned relative to the wrapper).
Set the top & left properties of the child elements to 0 so they will overlap. The default top & left values are zero, so assigning them to zero is optional--but explicitly assigning them to zero is more clear.
HTML
<div id='wrapper'>
<canvas id="canvasBottom" width=300 height=200></canvas>
<canvas id="canvasTop" width=300 height=200></canvas>
</div>
CSS
#wrapper{
position:relative;
width:300px;
height:200px;
}
#canvasTop,#canvasBottom{
position:absolute; top:0px; left:0px;
border:1px solid green;
width:300px;
height:200px;
}
#canvasTop{
border:1px solid red;
}
Layer canvas elements via KineticJS
It's really easy to layer canvas elements via KineticJS from Eric Rowell. It's a very useful library to work with the HTML5 canvas element.
The lib is not maintained anymore but its very stable.
Get it here: KineticJS Download
Find the reference here: KineticJS Reference
If you search a little bit on the web for examples you will clearly understand that every node in KineticJS is an own canvas element. This library relies on layering canvas elements via groups and so on.
I have a canvas inside a div and it fills the whole div. I draw a line on canvas but when I resize browser window, width of the line on the canvas changes, as I increase browser window size its thickness increases and adds some blur to the line.
I figured out that problem occurs here; I dont use a fixed size for canvas instead I use %100 for the width and height.
#myCanvas{
margin:0;
padding: 0;
border:0;
width: 100%;
height: 100%;
background-color: white;
}
When I used fixed size in pixeel for width and height, it's ok. But I want my canvas to resize without disturbing the drawing inside.
You can play around here: http://codepen.io/ertugrulmurat/pen/nxhof
Just try to change the heigth of browser window.
Any idea would be appreciated.
This is unfortunately quite involved to fix. Essentially you need to:
Add an event listener to the window for the resize event and
change the width/height attributes on the canvas tag (not the css, that stays at 100%) every time the window resizes
You will also need to redraw the line every time the resize happens.
Remember the width/height attributes are unitless so make sure you set it to something like width="100" and not width="100px"
Here is the relevant section of your code with the corrections in place:
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
var draw = function(){
ctx.lineWidth = 0.5;
ctx.shadowBlur = 0;
ctx.strokeStyle="#FF0000";
ctx.beginPath();
ctx.lineWidth=0.5;
ctx.lineCap="round";
ctx.moveTo(20,20);
ctx.lineTo(200,20);
ctx.stroke();
ctx.closePath();
}
window.addEventListener('resize', function(){
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
draw();
});
draw();
}
I've taken a look around and it seems that the canvas element doesn't deal well with CSS, and it's best to define the width and height as part of the tag, such as
<canvas width="200" height="100"></canvas>
Of course the only problem is that those values are only in px. My work around would be to use javascript to therefore collect the parent size and enter the new value on the resize event. I have wrote all this out in a jsfiddle for you and it works brilliantly if you resize.
Note that I call the redraw function every time it is resized. If you fail to do this, it goes blank until the next click.
http://jsfiddle.net/N23w2/1/
I am drawing a series of rectangles and text on an HTML5 Canvas. But this canvas will ultimately be printed. The rectangles are drawn according of the height of the paper(canvas)
The only canvas width that doesn't distort the text is the 300dpi or 2400x3300 canvas. This works well for print but its obviously huge on the screen.
I would like the user to have a scaled down version of the canvas on the left side that fits 100% height of the parent container with scroll bars for overflow.
I have tried div overflow:auto.. and this does work but its not scaled (still scrolling a huge version). So basically I would like to scale the image for the browser window but do all drawing/printing from the big canvas.
For this scenario you can use CSS rules with the canvas.
ONLINE DEMO HERE
Keep the pixel size but add the following rules to the canvas element itself (assuming the id of the canvas is canvas):
canvas.style.width = 'auto';
canvas.style.height = '100%';
or apply a CSS rule to the element via CSS and HTML:
.printCanvas {
width:auto;
height:100%;
}
and then in the HTML:
<canvas id="canvas" class="printCanvas" width="2400" height="3300"></canvas>
This should allow the browser to use the actual content of the canvas when printing even when the canvas is scaled down (like with an image).
In this example the canvas will fit the height of parent provided the parent has height defined. You can use as you already do overflow:auto to get scroll-bars.
If you want to show 50% of the canvas inside the parent just set height:200% for the canvas element and so on.
Note that you might loose some details on the screen if the canvas is scaled much but these should show on the print. This would be due to sub-pixeling which kicks in when a pixel is drawn as less than an actual pixel on the screen.