I am tracing a point in an HTML5 video using canvas overlay. The canvas is on top of the video tag with the following style:
#my-canvas { width: 100%; height: 100%; position:absolute !important; z-index:100000; margin: 0 auto; background-color:rgba(68, 170, 213, 0.0); }
The points were captured via separate (Android) app. Here's how I plot the points on the canvas:
MyClass.prototype.drawLine = function(_context, _ctr, _color) {
_context.lineWidth = 2;
_context.lineJoin = 'round';
_context.strokeStyle = _color;
_context.moveTo(this.data["xs"][_ctr]*this.xOffset, this.data["ys"][_ctr]*this.yOffset);
_context.lineTo(this.data["xs"][_ctr+1]*this.xOffset, this.data["ys"][_ctr+1]*this.yOffset);
_context.stroke();
_context.closePath();
}
I multiply the data points with an offset value to compensate for the screen size. This is how I calculate the offset:
MyClass.prototype.calculateOffsets = function() {
this.yOffset = this.video.offsetHeight/parseFloat(this.data["height"]);
this.xOffset = this.video.offsetWidth/parseFloat(this.data["width"]);
}
This code works fine in a landscape video but not in portrait. I might be missing something with the offset calculation. I would appreciate if you can point me to the proper direction.
Thanks in advance.
When you set canvas size using CSS your canvas will actually always be 300x150 pixels. What you draw to it will be relative to that size.
Try instead to remove the 100% width and height from the CSS rule and set the canvas size for its bitmap every time you get an onresize event etc. CSS sets the element size; this will set the bitmap size (element will follow if no CSS is overriding):
_context.canvas.width = window.innerWidth;
_context.canvas.height = window.innerHeight;
and
#my-canvas {width: 100%; height: 100%;position:absolute...
Notice though that changing the canvas size will also clear it so you will have to redraw everything up to that point if that is needed.
Related
I am trying to use signaturepad in a bootstrap modal, I have a canvas in a div:
<div class="modal-body">
<div class='signature-container' >
<canvas id="signature"></canvas>
</canvas>
</div>
On init, I do (coffeescript):
canvas = $("canvas#signature")[0]
signature_pad = new SignaturePad(canvas, backgroundColor: 'rgb(255, 255, 255)')
My css for the canvas is (because I want the canvas to fill the div)
width:100%;
height:100%;
Everything works, but the "ink" is offset from the mouse pointer. When I first click, the initial ink appears to the right and below of the mouse pointer. The farther down I move the mouse, the farther the vertical offset, same with horizontal (i.e. the offset appears to scale linearly). I tried implementing the resize function in the demo but chrome evaluates offsetWidth to 0 and the canvas just shrinks to 0x0.
Anyone have any ideas what I'm doing wrong?
I was having this same exact problem, adding height and width of 100% to the canvas was causing the signature to appear offset horizontally to the right.
This is what was happening:
Screenshot of signature issue
Found this elsewhere on stack - make canvas as wide and as high as parent ... the answer by Phrogz is key.
"3.The width and height attributes on a Canvas specify the number of pixels of data to draw to (like the actual pixels in an image), and are separate from the display size of the canvas."
He provided this bit of jQuery code to make canvas as wide and as high as its parent:
var canvas = document.querySelector('canvas');
fitToContainer(canvas);
function fitToContainer(canvas){
// Make it visually fill the positioned parent
canvas.style.width ='100%';
canvas.style.height='100%';
// ...then set the internal size to match
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
}
I also wanted to remove the line that appears across the sigpad when you clear it... and to do that I added these options to jquery:
signaturePad = $('.sigPad').signaturePad({
drawOnly: true,
bgColour: '#FFF',
defaultAction: 'drawIt',
penColour: '#2c3e50',
lineWidth: 0,
});
The last line (lineWidth) controls the line across the sigpad.
Happy coding!
Check #media screen zoom
/* Root */
html {
#media screen and (min-width: 1441px) {
zoom: 97%;
}
#media screen and (max-width: 1440px) {
zoom: 95%;
}
#media screen and (max-width: 1540px) {
zoom: 93%;
}
#media screen and (max-width: 1280px) {
zoom: 91%;
}
}
I am using draw2dtouch 6.1.66 version (latest version). Initially width and height of canvas was 1000px and 800px respectively. On button click, I am changing the canvas width and height to 2170px and 902px respectively.
Now I cannot drag rectangle figure beyond 1000px width-wise. It gets stuck to 1000px which was initial width.
Note: I check my html, both canvas div and svg shows width:2170px and height:902px.
<div _ngcontent-awi-17="" draw2d-canvas="" id="canvas" style="height: 902px; cursor: default; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); width: 2170px;">
<svg height="902" version="1.1" width="2170" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="overflow: hidden; position: absolute; left: -0.828125px;">
Here is my code:
$("#canvas").css("height",902);
$("#canvas").css("width", 2170);
canvas.setDimension(new draw2d.geo.Rectangle(0, 0, 2170, 902));
It may be and old post, but I had the same issue using same version, and my solution might be useful for some other people coming back.
It seems when the canvas is created Canvas.regionDragDropConstraint is initialized with the original size of the canvas, restrincting the area in which objects can be dragged inside. I had to modify the method Canvas.setDimension, and added the update of the attribute, so when resized, it's updated in all the figures referencing the same object.
/**
* #method
* Tells the canvas to resize. If you do not specific any parameters
* the canvas will attempt to determine the height and width by the enclosing bounding box
* of all elements and set the dimension accordingly. If you would like to set the dimension
* explicitly pass in an draw2d.geo.Rectangle or an object with <b>height</b> and <b>width</b> properties.
*
* #since 4.4.0
* #param {draw2d.geo.Rectangle} [dim] the dimension to set or null for autodetect
*/
setDimension: function(dim, height)
{
if (typeof dim === "undefined"){
var widths = this.getFigures().clone().map(function(f){ return f.getAbsoluteX()+f.getWidth();});
var heights = this.getFigures().clone().map(function(f){ return f.getAbsoluteY()+f.getHeight();});
this.initialHeight = Math.max.apply(Math,heights.asArray());
this.initialWidth = Math.max.apply(Math,widths.asArray());
}
else if(dim instanceof draw2d.geo.Rectangle){
this.initialWidth = dim.w;
this.initialHeight = dim.h;
}
else if(typeof dim.width ==="number" && typeof dim.height ==="number"){
this.initialWidth = dim.width;
this.initialHeight = dim.height;
}
else if(typeof dim ==="number" && typeof height ==="number"){
this.initialWidth = dim;
this.initialHeight = height;
}
this.html.css({"width":this.initialWidth+"px", "height":this.initialHeight+"px"});
this.paper.setSize(this.initialWidth, this.initialHeight);
this.setZoom(this.zoomFactor, false);
// MODIFICATION START TO CORRECT DRAG AND DROP PROBLEM
// Add modification to the Region Drap and Drop Policy, so it does not restricts objects movements on resize.
this.regionDragDropConstraint.constRect.w = this.getWidth();
this.regionDragDropConstraint.constRect.h = this.getHeight();
// MODIFICATION END
return this;
}
Setting the width and height of a canvas using css, will result in scale like effect, because the underlying imageData array is not updated to the new dimensions.
So if you need to scale your canvas, use the attributes of the canvas, like so:
$('#canvas').attr({width: <width>, height: <height>});
Keep in mind that changing those values will clear the canvas and you need to redraw everything.
I'm working on an HTML5 browser game that can be divided into 3 parts: two UI panels on the left and right of a center set of square canvases for the playing surface. The three panels need to be horizontally aligned, and the total game needs to keep an aspect ratio of 16:9. The left and right panels should be of equal widths, and all three panels must be of equal height. I have specified a minimum width and height inside a resize() function called when an onresize event is detected.
Currently, each panel is a div, and all three are contained inside a section. Right now, the section isn't necessary, but I want to keep the game separated from extra content at the bottom of the screen that I might choose to add later.
The CSS style is as follows:
* {
vertical-align: baseline;
font-weight: inherit;
font-family: inherit;
font-style: inherit;
font-size: 100%;
border: 0 none;
outline: 0;
padding: 0;
margin: 0;
}
#gameSection {
white-space: nowrap;
overflow-x: hide;
overflow-y: hide;
}
#leftPanel, #centerPanel, #rightPanel {
display: inline-block;
}
#leftPanel {
background-color: #6495ed;
}
#centerPanel {
background-color: #e0ffff;
}
#rightPanel {
background-color: #b0c4de;
Right now, I have set the background color of each div just to show me when I'm correctly setting the size of each div.
The body of my HTML document is as follows:
<body onresize="resize()">
<section id="gameSection">
<div id="leftPanel">Left Panel.</div>
<div id="centerPanel">Center Panel.</div>
<div id="rightPanel">Right Panel.</div>
</section>
</body>
And finally, my resize() function (I created a separate function for resizing the game in case I add more elements below later):
function resize() {
var MIN_GAME_WIDTH = 800;
var MIN_GAME_HEIGHT = 450;
var GAME_ASPECT_RATIO = 16 / 9;
var width = window.innerWidth;
var height = window.innerHeight;
var gWidth, gHeight;
if(width < MIN_GAME_WIDTH || height < MIN_GAME_HEIGHT) {
gWidth = MIN_GAME_WIDTH;
gHeight = MIN_GAME_HEIGHT;
}
else if ((width / height) > GAME_ASPECT_RATIO) {
<!-- width is too large for height -->
gHeight = height;
gWidth = height * GAME_ASPECT_RATIO;
}
else {
<!-- height is too large for width -->
gWidth = width;
gHeight = width / GAME_ASPECT_RATIO;
}
resizeGame(gWidth, gHeight, GAME_ASPECT_RATIO);
}
function resizeGame(var gWidth, var gHeight, var aspectRatio) {
var gSection = document.getElementById("gameSection");
var lPanel = document.getElementById("leftPanel");
var cPanel = document.getElementById("centerPanel");
var rPanel = document.getElementById("rightPanel");
gSection.height = gHeight;
gSection.width = gWidth;
<!-- should the below be taken care of in the CSS? -->
lPanel.height = gHeight;
cPanel.height = gHeight;
rPanel.height = gHeight;
cPanel.width = cPanel.height;
lPanel.width = (gWidth - cPanel.width) / 2;
rPanel.width = lPanel.width;
}
I've tried a number of different commands to resize the divs, but it just isn't working for me. When I try adding test canvases, color appears, but the boxes still aren't the correct size. I have also considered loading an invisible background image to each div and scaling it to the desired size; however, I was able to resize my canvas using the above method before and it seemed to work just fine.
Additional Notes
While I've already had pretty good success resizing a single canvas, I don't want to use just one canvas for the game because not all parts of the UI need to be drawn at the same time.
I'm trying to keep this solely in Javascript.
I suspect that I could just use CSS to handle resizing by fixing the aspect ratio to 16:9 and using width:56.25% for the center panel and width:21.875% for the side panels, but that limits me to one aspect ratio and doesn't explain why my above script isn't working.
I can provide the entire HTML file if needed. This is what it's supposed to look like:
End Goal (without right panel)
Thank you!
UDPATE:
jsfiddle
I got it kind of working here. I made a lot of changes/minor fixes to the code before finding what was wrong (other than various syntax errors):
You were using .width and .height instead of .style.width and .style.height, and you were applying integers to these instead of strings with "px" appended to them. Both of these things are completely understandable to miss.
I also moved the onresize from the body tag into the JS, don't know why it wasn't working on jsfiddle, but this is good practice anyways.
In the future: learn how to debug JS using the console and when you ask questions, use small examples, not your entire codebase. This question could have been simplified to "How do I resize a div?" with one line of JS and one div. You also should consider not doing this specific thing in JS, and using flexbox as redbmk said.
I see that there are ways to do this in webkit browsers, but I don't see ways to do it in others. Is this simply a feature that hasn't been implemented in all the browsers?
I don't have standard images, so clip won't work. I may have to render everything ahead of time, which will make my work exponential, but you deal with what you have, right?
I'd also want to be able to activate this stuff from javascript. :/
Thanks if you can provide support.
Just off the top of my head - and without an actual problem from you for us to solve - here's a possible way to accomplish what you want...
HTML
<div class="myImage">
<img src="path_to_image" title="Lorem ipsum" alt="Dolar sit amet" />
<div class="myMask">
</div><!-- /myMask -->
</div><!-- /myImage -->
CSS
.myImage {
position: relative;
}
.myMask {
position:absolute;
top: 0;
left: 0;
background-color: transparent;
background-image: url('path_to_masking_image');
}
Alternatively, use an <img /> inside the myMask div, and remove the background-image property from the CSS.
The way it's currently laid out, you would need two images: the image itself in all its glory, and the mask.
The way you would accomplish the 'masking effect' is to have the mask image be a static solid color that matches background of the container its in - ie white, black, whatever.
Kapeesh? This would work in all browsers, which is what you asked for. The background-clip property has -webkit and -moz selectors, but is not supported in browsers like IE or (to my knowledge) Opera.
Here are my 2 cents, if it is indeed CSS Sprites you are after.
<head>
<style type="text/css"><!--
#imagemask {
background-image: url(image.png);
background-repeat: no-repeat;
background-color: transparent;
height: 40px;
width: 40px;
}
.mask1 { background-position: top left; }
.mask2 { background-position: 0 40px; }
.mask3 { background-position: 0 80px; }/* And so on, however your image file is 'layed out' */
--></style>
<script type="text/javascript">
function mask1(){ document.getElementById("imagemask").setAttribute("class", "mask1"); }
function mask2(){ document.getElementById("imagemask").setAttribute("class", "mask1"); }
function mask3(){ document.getElementById("imagemask").setAttribute("class", "mask1"); }
</script>
</head>
<body>
mask 1
mask 2
mask 3
<div id="imagemask" class="mask1"></div>
</body>
We define the div#imagemask to contain 1 image file as a background and set it to not repeat around, as that would sort of defy the point.
We define how to "move around" the image inside the "mask" (div) with fixed width and height.
As a reference, I've then added the javascript you need to switch between the masks on the fly. I wrote that in about 10 seconds, you could probably write something a little more elegant if you want.
Add the links with onclick= events
Finally, add the div#imagemask to the body.
Given that I don't know the width or height of your image file or it's target masking, you'll have to do some substantial edits to this code. But you get the idea :)
I'm just going to skip the CSS variant in favor of this:
Example of a working mask: http://gumonshoe.net/NewCard/MaskTest.html
I acquired a javascript class from another website tutorial:
http://gumonshoe.net/js/canvasMask.js
It reads the image data and applies the alpha pixels from the mask to the target image:
function applyCanvasMask(image, mask, width, height, asBase64) {
// check we have Canvas, and return the unmasked image if not
if (!document.createElement('canvas').getContext) return image;
var bufferCanvas = document.createElement('canvas'),
buffer = bufferCanvas.getContext('2d'),
outputCanvas = document.createElement('canvas'),
output = outputCanvas.getContext('2d'),
contents = null,
imageData = null,
alphaData = null;
// set sizes to ensure all pixels are drawn to Canvas
bufferCanvas.width = width;
bufferCanvas.height = height * 2;
outputCanvas.width = width;
outputCanvas.height = height;
// draw the base image
buffer.drawImage(image, 0, 0);
// draw the mask directly below
buffer.drawImage(mask, 0, height);
// grab the pixel data for base image
contents = buffer.getImageData(0, 0, width, height);
// store pixel data array seperately so we can manipulate
imageData = contents.data;
// store mask data
alphaData = buffer.getImageData(0, height, width, height).data;
// loop through alpha mask and apply alpha values to base image
for (var i = 3, len = imageData.length; i < len; i = i + 4) {
imageData[i] = alphaData[i];
}
// return the pixel data with alpha values applied
if (asBase64) {
output.clearRect(0, 0, width, height);
output.putImageData(contents, 0, 0);
return outputCanvas.toDataURL();
}
else {
return contents;
}
}
So I am trying to insert an image to a page with JavaScript with 50% of its width and 50% of its height.
I do this:
someElement.html('<img src="/path/to/img.jpg" alt="" class="sImg" />');
The sImg class is defined in stylesheet like this:
.sImg{
border: 0;
width: 50%;
height: 50%;
}
Yet the image appears fullsize.
I have also checked via Firebug and the image has width and height both at 50%.
First of all, if you're setting a width and height, you should also include display: block; since inline elements don't generally enjoy being given a set height.
But more importantly, when you express a width (or height) as a percentage, that's a percentage of the parent element, so if the parent is 1000px wide, the image will be 500px wide (regardless of what size the actual image file is).
If you're using JavaScript to determine the current image size and change it, just express the new size in px instead of %.
The CSS you've got means that the width and height should be computed as half the size of the parent container, not the image itself.
What you can do is something like this: create an Image object and give it an "onload" handler. The handler can get reliable size information (because the image will have been loaded), and can then add the image element with the proper size.
var img = new Image();
img.onload = function() {
$(someElement).empty().append($('<img/>', {
src: img.src,
alt: '',
'class': 'sImg',
css: { width: Math.floor(img.width / 2) + 'px', height: Math.floor(img.height / 2) + 'px', display: 'inline-block' } // display should be set as you need it
});
};
img.src = yourUrl;
edit — the eerily knowledgeable Šime Vidas points out that setting the "width" or "height" attribute should make the right thing happen, with the size being reduced appropriately to maintain the aspect ratio.
Does the parent container have a height/width? it maybe that the browser does not know what 50% of x is and what 50% of y is. but if it knew what x and y were then it could apply it. Try
var myWidth = $('.sImg').width(),
myHeight = $('.sImg').height();
myWidth = myWidth / 2;
myHeight = myHeight / 2;
$('.sImg').attr('width', myWidth + 'px').attr('height', myHeight + 'px');
http://api.jquery.com/width/
http://api.jquery.com/height/