how to reset the axix of HTML5 Canvas - html5-canvas

I am very new to html5.
infact this is my first work.
I am working on a small project. Part of the project is to read an xml file which has shapes in it
<Graphic>
<object_type>LINE</object_type>
<field_1>3.6082475185394287</field_1>
<field_2>541.23712158203125</field_2>
<field_3>28.86598014831543</field_3>
<field_4>474.48452758789062</field_4>
<field_6 />
<field_7 />
<field_8 />
<field_9 />
</Graphic>
<Graphic>
<object_type>LINE</object_type>
<field_1>10.824742317199707</field_1>
<field_2>562.8865966796875</field_2>
<field_3>3.6082475185394287</field_3>
<field_4>541.23712158203125</field_4>
<field_6 />
<field_7 />
<field_8 />
<field_9 />
</Graphic>
after reading the xml file i am iterating through the coordinates. and drawing the object on the html5 canvas.
I have two troubles....
1) the photo is being drawn upside down... so i need to rotate the canvas
Image can be viewed here
2) i need to scale the whole object within the canvas. for now i am dividing every coordinate with 8 to scale it down. how i can scale it according to screen resolution and canvas...
cannot get my head around this

If you are able to get the object width and height, you just need to calculate the scale factor related to the canvas:
var scaleFactorW = canvas.width/obj.width,
scaleFactorH = canvas.height/obj.height;
context.scale(scaleFactorW , scaleFactorH);
startDrawing(obj);
See this DEMO at jsfiddle.net
EDIT:
To maintain the object proportions for different canvas resolutions we need to calculate a scale factor that verifies the max scale based on canvas aspect ratio and the object proportions.
var canvasAspectRatio = canvas.width / canvas.height;
var objAspectRatio = obj.width / obj.height;
var scaleFactor = 1;
if (canvasAspectRatio > objAspectRatio) {
scaleFactor = canvas.height / obj.height;
} else {
scaleFactor = canvas.width / obj.width;
}
context.scale(scaleFactor, scaleFactor);
startDrawing(obj)

Found answer to the first question after doing bit of maths...
my canvas was
<canvas id="myCanvas" width="800" height="500" style="background: #FFFFFF; border: 5px solid black;" role="img">
Your browser does not support the canvas element.
</canvas>
and javascript became...
startDrawing(obj);
// rotate 180 degrees clockwise
context.rotate(180*(Math.PI/180));
// translate context to opposite of your actual canvas
context.translate(-800, -500);
still need the answer for the 2nd question.... the scaling

Related

How to use x2 canvas elements and rendering paper.js on img capture of html5 video to base64

Still very much a newbie to coding, so please be gentle :)
I'm hoping someone might be able to help how to use Paper.js on a second canvas after the first one has been executed?
I'm trying to use x2 canvas elements:
Canvas 1 - to capture a html5 video image still and convert to base64 (tick :-) = done)
Canvas 2 - Use the base64 image and perform the 'Working with Rasters to find the colors of pixels' and convert to circle paths (boo = fail :-( )
Something like this:
The code:
<script src="https://cdn.jsdelivr.net/npm/hls.js#latest"></script>
<video id="video" preload="auto" muted="" playsinline="" width="580" src="blob:https://www.georgefisher.co.uk/78e3a45c-ae07-4ea5-af56-45a5ed9cf1b0"></video>
<script>
var video = document.getElementById('video');
var videoSrc = 'https://camsecure.co/HLS/georgefisher.m3u8';
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
}
video.play()
</script>
<br>
<button onclick="capture()">Capture</button>
<br>
<canvas id="canvas" style="overflow:auto">
</canvas>
<canvas id="canvas2" resize>
<img src="" id="myImg"/></canvas>
var resultb64="";
function capture() {
var canvas = document.getElementById('canvas');
var video = document.getElementById('video');
canvas.width = video.videoWidth/4;
canvas.height = video.videoHeight/4;
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth/4, video.videoHeight/4);
resultb64=canvas.toDataURL();
document.querySelector("#myImg").src = canvas.toDataURL();
}
/*Paper JS Setup for working in CodePen */
/* ====================== *
* 0. Initiate Canvas *
* ====================== */
// expose paperjs classes into global scope
paper.install(window);
// Only executed our code once the DOM is ready.
window.onload = function() {
// bind paper to the canvas
paper.setup('canvas2');
// paper.activate();
// Get a reference to the canvas object
var canvas = document.getElementById('canvas2');
var ctx = canvas.getContext('2d');
// console.log(ctx, image);
// ctx.drawImage(image, 0, 0);
// return;
// }
// Create a raster item using the image id='' tag
var image = document.querySelector('img');
var raster = new Raster(image);
// Hide the raster:
raster.visible = false;
// The size of our grid cells:
var gridSize = 15;
// Space the cells by 120%:
var spacing = 1
;
// As the web is asynchronous, we need to wait for the raster to load before we can perform any operation on its pixels.
raster.onLoad = function() {
// Since the example image we're using is much too large, and therefore has way too many pixels, lets downsize it to 40 pixels wide and 30 pixels high:
raster.size = new Size(40, 30);
for (var y = 0; y < raster.height; y++) {
for(var x = 0; x < raster.width; x++) {
// Get the color of the pixel:
var color = raster.getPixel(x, y);
// Create a circle shaped path:
var path = new Path.Circle({
center: new Point(x, y).multiply(gridSize),
radius: gridSize / 2 / spacing,
});
// Set the fill color of the path to the color
// of the pixel:
path.fillColor = color;
}
}
// Move the active layer to the center of the view, so all the created paths in it appear centered.
project.activeLayer.position = view.center;
}
}
I've tried giving the second canvas a different Id="canvas2" and referencing that, which I can see in the console. However, nothing appears in the second canvas and the paper.js script doesn't seem to execute, can someone help me understand why?
Please see also see link to the fiddle below:
https://jsfiddle.net/jmnes/o4Lpkfs6/1/
Alternatives method.
You don't need to capture the video, you don't need to capture the pixels using paper.js and raster. You don't need to find the color of each circle and draw it.
All these methods are slow, complex, and power hungry.
You can create a mask and mask out the circles, with the colors drawn from a smaller canvas with a res that matches the number off circles.
How to
Add one (main canvas) canvas to the DOM. This will display the result
Create 2 offscreen canvas.
One (color canvas) has the same resolution as the circles you want to display. Eg if you have 30 by 40 circle the canvas res should be 30 by 40
One (mask canvas) is the circle mask. It is the same resolution as the main canvas. Draw the circles all in one color on this canvas.
Then rendering once a frame
Draw the video on the color canvas to fit.
Turn off smoothing on the main canvas eg ctxMain.imageSmoothingEnabled = false
Draw the color canvas onto the main canvas to fit.
This will draw a color square at each circle position. ctx.drawImage(colorCanvas, 0, 0, mainCanvas.width, mainCanvas.height)
Set composite operation "destination-in" eg ctxMain.globalCompositeOperation = "destination-in"
Draw the mask canvas (canvas with circles on it) onto the main canvas. This will remove pixels outside each circle.
Restore default composite operation for the main canvas ctxMain.globalCompositeOperation = "source-over"
All done for a real-time FX on almost any device.
The above methods is the fastest way to render the effect you are after using the 2D API

360 panorama image quality problem in three

We implement panorama 360 in our project. We load 9000x4500px textures (360 image). The problem appears on some resolutions, e.g. on 1920x1080, it is quite legible (in adjust zoom 75%), when we zoom to 100/125%, we start to pixelose.
enter image description here
The biggest problem appears at the resolutions of 1536x864 (125% adjust zoom) and 1280x800 then the image is practically blurry.
enter image description here
If I use a panorama viewer, the image behaves very well and these problems do not occur.
https://renderstuff.com/tools/360-panorama-web-viewer/
I will just add that I have a few points on the panorama that are clicked and some information pops up.
We used react-three-fiber
function Dome() {
const texture = new THREE.TextureLoader().load(
"../models/innerOkaglak-v4.jpg"
);
texture.mapping = EquirectangularReflectionMapping;
texture.encoding = sRGBEncoding;
texture.generateMipmaps = false;
texture.minFilter = LinearMipMapLinearFilter;
return (
<mesh>
<sphereBufferGeometry attach="geometry" args={[500, 60, 30]} />
<meshBasicMaterial
attach="material"
map={texture}
side={THREE.BackSide}
/>
</mesh>
);
}

How to crop the canvas to fit a specific area size in Fabric js

Among the functions of fabric js, there is a method or property that crops objects except canvas, but I did not find a function to crop the canvas itself. I tried changing the canvas to an image in the following way, cropping it, and then inserting it back into the canvas.
fabric.Image.fromURL(canvas.toDataURL(), img => {
currentImage = img; //save current canvas as image
currentImage.set({
scaleX : canvas.width / currentImage.width,
scaleY : canvas.height / currentImage.height,
cropX: selectionRect.left,
cropY: selectionRect.top,
width: selectionRect.getScaledWidth(),
height: selectionRect.getScaledHeight(),
});
canvas.setDimensions({
width: selectionRect.getScaledWidth(),
height: selectionRect.getScaledHeight()
});
canvas.setBackgroundImage(currentImage).renderAll();
but in this case, an image with a transparent background becomes a background.
If you look at the following picture, a picture of a flower without a background is on the canvas, and What I want is to resize the canvas by the dotted rectangle area without making any objects on the canvas an image as follows.
before crop:
after crop:
Just as the starting range and area are determined with attributes such as cropX or cropY when cropping an object, I would like to know how to apply this to the canvas as well.

hmtl5 canvas: transparant animation on top of website elements

How do I put the canvas on top of my website, with position: absolute, so that my animation happens on top of my regular website. Now when I animate, the canvas background becomes white so I can't see my website. BUT I want to see both my website and the animation that is lying on top of it.?
My end goal is to have tiny circles follow my fingers when I touch the screen on a mobile phone, but before I can achieve that, I have to know that I can animate on top of other elements first. At least, that is what I think at the moment.
Please help :)
Use ctx.clearRect() for your animation. I also added background-color:transparent just in case, but it works without it.
var ctx = canvas.getContext('2d');
canvas.height = innerHeight;
canvas.width = innerWidth;
function rad(deg){
return deg*Math.PI/180;
}
var t = 360;
function loop(){
requestAnimationFrame(loop);
ctx.clearRect(0,0,innerHeight,innerWidth);
ctx.beginPath();
ctx.arc(100+50*Math.sin(rad(t)),100+50*Math.cos(rad(t)),40+20*Math.sin(rad(t)),0,Math.PI*2);
ctx.fillStyle='rgba(255,255,20,0.8)';
ctx.strokeStyle='red';
ctx.lineWidth = 5;
ctx.fill();
ctx.stroke();
t=t>0?t-5:360;
}
loop();
canvas{
position:absolute;
background-color:transparent;
}
<canvas id=canvas></canvas>
<h1>
Your website.
</h1>
<h2>
Words words words.
</h2>
words words words words

KineticJS rotating/animating text

I have this fiddle where I have text arranged in a circle, I would like now to animate it and rotate the text in a clockwise/counter clockwise motion.
Every animation demo I have seen uses a container as the starting point however all the examples i could find about manipulating text in a circular arrangement have all started with the element. I have tried 100's of variations trying to get this working but I am either missing something or it's not possible with the construction i have used thus far.
Here is the fiddle for the circular text I have so far:
http://jsfiddle.net/jamesburt/Sa2G8/
<canvas id="canvas1" width="500" height="500"></canvas>
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
Where as the animation examples start off with:
<div id="container"></div>
var stage = new Kinetic.Stage({container: 'container'});
I'm open to any ideas / rewrites needed as ultimately my goal is an animated text circle.
Also if this is easily accomplished in an alternative to KineticJS I'd be interested in trying that out.
Here is a demo I made using KineticJS: http://jsfiddle.net/Moonseeker/Xf7hp/
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
var myText = "My text in a circle. ";
var centerCoords = {x:250, y:250};
for(var i=0;i<myText.length;i++){
var rotation = i*360/myText.length;
var oneChar = new Kinetic.Text({
x: centerCoords.x,
y: centerCoords.y,
text: myText[i],
fontSize: 30,
fontFamily: 'Calibri',
fill: 'green',
offset: {x:0, y:100},
rotationDeg: rotation
});
layer.add(oneChar);
}
// add the layer to the stage
stage.add(layer);
var angularSpeed = Math.PI / 2;
var anim = new Kinetic.Animation(function(frame){
var angleDiff = frame.timeDiff * angularSpeed / 1000;
for(var i=0;i<layer.children.length;i++){
layer.children[i].rotate(angleDiff);
};
}, layer);
anim.start();
You can rotate at every direction or speed you wish, you can change the style of the circle.
You should be able to use layer.find('Text').each() instead of the for-loop for looping through the text to rotate but the KineticJS library at jsfiddle seems outdated as it doesn't know the find method.
One efficient way:
Render your text-around-a-circle on an offscreen canvas.
Save that offscreen canvas as an image using .toDataURL
Create a Kinetic.Image from that offscreen image.
You can then efficiently rotate/animate the Kinetic.Image as you need.

Resources