Give id to a canvas - javascript

I have it so that when you (the PaintBrush) hit the finish everything clears and a button appears. When the button is clicked it starts level two, here it creates a new canvas. I've added some code so that when the button is clicked the old canvas is deleted, then the new one is made. However, this requires the canvas to have an id. how do i get this code:
canvas: document.createElement("canvas"),
To also include an id for it? I cannot have it say var canvas = blah blah and then have
canvas.id = "canvas";
because of the way i have it set up.
P.S the remove code is this if you need to know:
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = this.length - 1; i >= 0; i--) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
and in the button "click" function area i put this for the remove:
document.getElementById("canvas").remove();
Please help! Thanks in Advance!
EDIT: Here is some extra code to help, it is what occurs when the PaintBrush hits the finish:
else if (PaintBrush.crashWith(Finish)) {
PaintBrush.y = 50;
var button = document.createElement("button");
button.innerHTML = "Level 3";
button.id = "button-2"; // add the id to the button
document.body.appendChild(button); // append to body
GameArena2.clear();
GameArena2.stop();
button.addEventListener ("click", function() {
startGame2();
document.getElement("canvas").remove();
document.getElementById("button-2").remove();
});
EDIT 2: Game canvas code:
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 1280;
this.canvas.height = 480;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea2, 20);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
},
drawGameOver: function() {
ctx2 = GameArena2.context;
ctx2.fillStyle = "rgba(0,0,0,"+fader +")";
ctx2.fillRect(0,0,GameArena2.width,GameArena2.height);
drawStatic(fader/2);
fader += .1 * 1/fps
ctx2.fillStyle = "rgba(255,255,255," + fader + ")";
ctx2.font = "72px sans-serif";
ctx2.fillText("GAME OVER",GameArena2.width/2 - 220,GameArena2.height/2);
}
}
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
else if ((GameArena.frameNo / n) % 1 == 0) {
return true;
}
return false;
}

I think the best way is to create a static function like this:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
console.log(createElementOnDom('CANVAS','myId'));
So you can simply create the canvas adding it his specific id using a simple single row function call like you need.
I only know a way to do direcly this on jQuery, that you wouldn't like to use.
simply you need to do that:
function createElementOnDom (type,id) {
var element=document.createElement(type);
element.id=id;
return element;
}
var GameArena2 = {
canvas: createElementOnDom('CANVAS','myId'),

Simple! Just assign it immediately after the GameArena2 object is created.
var GameArena2 = {
canvas: document.createElement("canvas"),
start: function() {
...
...
}
// give id to a canvas
GameArena2.canvas.id = "GameArena2";
function everyinterval(n) {
if ((GameArena.frameNo / n) % 1 == 0) {
...
...
}

Related

p5js is adding div each time when click

#Hey-PeePs. The issue is happening in p5js:
I have: 1 function(), 1 draw(), 2 sketches(canvas)
Using: Instance Mode
All I want is a gallery! there is an image in thumbnail size, when click goes full-size, which is the reason I have 2 canvases. The following code is working. It will create a canvas with the thumbnail size of the image and then when I click on it, it will create a DIV which contains the full-screen image.
The issue is, every time I click on the thumbnail, it will create another DIV and it just goes on. How can I set a condition for this? So it will only draw once!
var PictureThumbnail = function(p) {
let ThumbImage;
let fullSize;
p.preload = function() {
ThumbImage = p.loadImage('https://www.paulwheeler.us/files/Coin120.png');
};
p.setup = function() {
var canvas = p.createCanvas(100, 100);
canvas.parent('#Thumbnail');
fullSize = createDiv('Full Size Image');
fullSize.addClass('fullSize');
fullSize.hide();
};
p.draw = function() {
p.image(ThumbImage, 0, 0, 700, 70);
if (mouseIsPressed) {
if ((p.mouseX > 0) && (p.mouseX < 100) && (p.mouseY > 0) && (p.mouseY < 100)) {
fullSize.show();
let sketch2 = function(p) {
p.setup = function() {
p.createCanvas(500, 500);
p.background(255);
}
};
new p5(sketch2, window.document.getElementById('fullSize'));
}
}
};
};
let sketch = new p5(PictureThumbnail);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
<div id="Thumbnail"></div>
</body>
</html>
The last line of code is the issue.
new p5(sketch2, window.document.getElementById('fullSize'));
There are a number of issues:
1. Invalid references:
You have several references to global p5.js methods and properties where you should be referencing the instance methods (createDiv and mouseIsPressed).
2. Action in draw() that should be in mousePressed()
The way you're using mouseIsPressed is flawed. Draw is going to be running repeatedly and mouseIsPressed will be true over several calls so you're going to be repeatedly creating sketch2.
3. Attempt to get an element by id that does not exist
You create a div with the class 'fullSize' and no id and then you attempt to get an element with the id 'fullSize' but no such element exist.
Here's a working example:
var PictureThumbnail = function(p) {
let ThumbImage;
let fullSize;
let fullSizeOpen = false;
p.preload = function() {
ThumbImage = p.loadImage('https://www.paulwheeler.us/files/Coin120.png');
};
p.setup = function() {
var canvas = p.createCanvas(100, 100);
canvas.parent('#Thumbnail');
fullSize = p.createDiv('Full Size Image');
fullSize.addClass('fullSize');
fullSize.id('fullSize');
fullSize.hide();
};
p.mousePressed = function() {
if ((p.mouseX > 0) && (p.mouseX < 100) && (p.mouseY > 0) && (p.mouseY < 100)) {
if (!fullSizeOpen) {
fullSizeOpen = true;
fullSize.show();
let sketch2 = function(p) {
p.setup = function() {
p.createCanvas(500, 500);
p.background('red');
}
};
new p5(sketch2, window.document.getElementById('fullSize'));
}
}
}
p.draw = function() {
p.image(ThumbImage, 0, 0, 700, 70);
};
};
let sketch = new p5(PictureThumbnail);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>
<div id="Thumbnail"></div>
</body>
</html>

how to make a video preview with canvas?

this is my first question here!
im trying to make a website that show videos that i make and i want my viewers can see a preview of video when they hover mouse on the a element or element .
i just do it but i have some problems and questions. lemme show you code example first and then i ask my questions.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="thumbs" style="width:216px;height:468px;border: 5px solid blue;background-color:red;"><canvas onmouseover="getid1(this);" onmouseout="getid2(this);" id="canvas1"></canvas></div>
<script>
var thumbsList = [];
var delay = 100;
var i = 0;
var video = document.createElement("video");
var a = 0;
var m = document.getElementById("canvas1");
var mtx = m.getContext("2d");
var generate = true;
var animstop = false;
var vidFrames = 64;
m.width = 216;
m.height = 468;
video.preload = "auto";
video.src = "aaaa.mp4";
function stranim(bb){
if(generate){
animstop = false;
video.currentTime = i;
generateVid();
generate = false;
}else{
animstop = false;
startAnim();
}
}
function stpanim(bb) {
clearTimeout();
animstop = true;
mtx.drawImage(thumbsList[0], 0, 0);
}
// if i replace this section with generateVid() the code is working
/*video.addEventListener('seeked', function() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid()
if(d == i){
startAnim();
}
}
});*/
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid();
if(d == i){
startAnim();
}
}
}
function generateFirstThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
thumbs.appendChild(m);
mtx.drawImage(thumbsList[0], 0, 0);
i += video.duration / vidFrames;
}
function generateThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
}
function startAnim() {
var currentFrame = 0;
function anim() {
if(currentFrame != (vidFrames - 1) && animstop == false){
currentFrame = (currentFrame + 1) % thumbsList.length;
mtx.drawImage(thumbsList[currentFrame], 0, 0);
setTimeout(anim, delay);
}
}
anim();
}
function getid1(obj) {
stranim(obj.id)
}
function getid2(obj) {
stpanim(obj.id)
}
window.onload = function(){
generateFirstThumbnail();
};
</script>
</body>
</html>
the questions are :
1- why my generatevid() function is not working? this function is just like that eventlistener.
2- i want to add this code on a class to use it on multiple videos but idk how and i think this cant be done with js classes.( i search so many sites for it)
3-i can use 2d arrays for saving my video previews but is it dont make my site lower on load speed or it dont fill the ram of user?
4-there is any way that i make this code better and easyer?(i dont want to use jquery for no reason).
For a pure js approach you can check this not mine btw: https://codepen.io/tepexic/pen/BazYgJe
html:
<input type="file" accept="video/*" id="input-tag"/>
<hr>
<video controls id="video-tag">
<source id="video-source" src="splashVideo">
Your browser does not support the video tag.
</video>
JS
const videoSrc = document.querySelector("#video-source");
const videoTag = document.querySelector("#video-tag");
const inputTag = document.querySelector("#input-tag");
inputTag.addEventListener('change', readVideo)
function readVideo(event) {
console.log(event.target.files)
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
console.log('loaded')
videoSrc.src = e.target.result
videoTag.load()
}.bind(this)
reader.readAsDataURL(event.target.files[0]);
}
}
But for other approach i would probably use http://ffmpeg.org/ library to generate a preview video (e.g 10 seconds video) and https://videojs.com library for video player so you have a control when user hover the player.
I just did some test on your code, your video is getting seeked only once. No event is raised after that, which means your thumbnail will remain same.
Here is how I was able to fix it
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
console.log("starting seeking");
if(d == i){
startAnim();
}
}
}
video.onseeked = (event) => {
if (animstop == false)
{
setTimeout(generateVid, delay);
}
console.log("seeked");
};

HTML5/Javascript Game

I'm currently working on a game where I need a bunch of random bubbles to fall, and a rectangle below it that can move to "burst" these bubbles. I have a code currently that is not dropping these bubbles. Can someone tell me where I am going wrong? Here is my code:
var canvasColor;
var x,y,radius,color;
var x=50, y=30;
var bubbles= [];
var counter;
var lastBubble=0;
var steps=0, burst=0, escaped=0;
var xx=200;
var moveRectangleRight=false;
var moveRectangleLeft=false;
function startGame()
{
var r, g, b;
canvasColor= '#f1f1f1';
x=10;
y=10;
radius=10;
clearScreen();
counter=0;
while (counter<100)
{
x= Math.floor(450*Math.random()+1);
r = Math.floor(Math.random()*256);
g = Math.floor(Math.random()*256);
b = Math.floor(Math.random()*256);
color='rgb('+r+','+g+','+b+')';
bubbles[counter]=new Bubble(x,y,radius,color);
counter+=1;
}
setInterval('drawEverything()',50);
}
function Bubble(x,y,radius,color)
{
this.x=x;
this.y=y;
this.radius=radius;
this.color=color;
this.active=false;
}
function drawEverything()
{
var canvas=document.getElementById('myCanvas');
var context= canvas.getContext('2d');
steps+=1;
clearScreen();
if (steps%20==0 && lastBubble <100) {
bubbles[lastBubble].active=true;
lastBubble+=1;
}
drawRectangle();
counter=0;
while(counter<100)
{
if (bubbles[counter].active==true) {
context.fillStyle= bubbles[counter].color;
context.beginPath();
context.arc(bubbles[counter].x, bubbles[counter].y,
bubbles[counter.radius], 0, 2*Math.PI);
context.fill();
bubbles[counter].y+=2;
}
y=bubbles[counter].y;
x=bubbles[counter].x;
if (y>=240 && y<=270 && x>=xx-10 && x<=xx+60)
{
bubbles[counter]=false;
}
else if (y>=450)
{
bubbles[counter]=false;
}
counter+=1;
}
}
function clearScreen ()
{
var canvas=document.getElementById('myCanvas');
var context= canvas.getContext('2d');
context.fillStyle= canvasColor;
context.fillRect(0,0,450,300);
}
function drawRectangle()
{ var canvas, context;
if (moveRectangleRight==true && xx<400){
xx+=20;
}
if (moveRectangleLeft==true && xx>0){
xx-=20;
}
canvas=document.getElementById('myCanvas');
context= canvas.getContext('2d');
context.fillStyle = 'blue';
context.fillRect(xx,250,50,10);
}
function moveLeft () {
moveRectangleLeft=true;
}
function moveRight() {
moveRectangleRight=true;
}
function stopMove () {
moveRectangleRight=false;
moveRectangleLeft=false;
}
Your problem is that you initialize counter as 1, so when you add items to counter, you begin with the index of 1, which is actually the 2nd item. Thus, when you try to access bubbles[0], it returns undefined. Instead, initialize counter as 0.
A bracket was located in the wrong place, and this solved the problem.

multiple HTML5 canvas with Neurosky sensor input is not working

I have created multiple html5 canvas using instantiation mode in P5JS. I am using Neurosky mindwave EEG sensor to activate and deactivate canvas one by one. Neurosky mindwave EEG sensor can detect user's eye blink which I am using as input. When user blinks, it should activate one canvas and deactivate another canvas and vice-versa.I am using Neurosky mindwave EEG sensor to activate and deactivate canvas one by one. Neurosky mindwave EEG sensor can detect user's eye blink which I am using as input. When user blinks, it should activate one canvas and deactivate another canvas and vice-versa.
Just to check if my code logic works, I used mouse pressed input to switch between the canvas and it worked perfectly. But, when I used it with the sensor it didn't work.
What I did - I have created multiple HTML5 canvas using instantiation mode in P5JS. I have used node-neurosky node module to capture the eyeblink data from the sensor. Node Module
What worked - When I launch the app it takes the eye blink as input for the first time and activate the another canvas but when I blink again it doesn't deactivate the current canvas and activate another canvas. I have tried printing flags to check the code and it is doing fine. Eyeblink gets detected every time when I blink but it doesn't switch the canvas.
What didn't work - When I tried to use eye blink strength directly into the sketch.js it didn't work then I created another boolean variable eyeclick which also didn't work.
sketch.js
var stateTwo, stateOne = true;
// sketch one -----------------------------------
var first = new p5(firstSketch, "canvasOne");
function firstSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(255, 10, 100);
p.fill(255);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (eyeclicked) {
stateOne = false;
stateTwo = true;
console.log(" canvas <-- one");
// k = 0;
eyeclicked = false;
}
if (stateOne) {
$('#canvasOne').css('opacity', '1');
$('#canvasTwo').css('opacity', '0.5');
// console.log("canvas One");
p.fill(255, 0, 0);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
// sketch two -----------------------------------
var second = new p5(secondSketch, "canvasTwo");
function secondSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(60, 250, 100);
p.fill(0);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (eyeclicked) {
stateOne = true;
stateTwo = false;
console.log(" canvas <-- two");
// k = 0;
eyeclicked = false;
}
if (stateTwo) {
$('#canvasOne').css('opacity', '0.5');
$('#canvasTwo').css('opacity', '1');
// console.log("canvas Two");
p.fill(0, 0, 255);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
NodeCode to connect with sensor connect.js
var attention = 0;
var meditation = 0;
var blink;
var poorSignalLevel = 0;
var eyeclicked = false;
if ("WebSocket" in window) {
console.log("WebSocket is supported by your Browser. Proceed.");
// $('#connect-controls').show();
}
var ws = new WebSocket("ws://127.0.0.1:8080");
ws.onopen = function() {
console.log('opened connection');
ws.send("Hello from websocket client!");
};
// whenever websocket server transmit a message, do this stuff
ws.onmessage = function(evt) {
// parse the data (sent as string) into a standard JSON object (much easier to use)
var data = JSON.parse(evt.data);
// handle "eSense" data
if (data.eSense) {
$('#brain').css({
opacity: 1
});
attention = data.eSense.attention;
meditation = data.eSense.meditation;
// brainProgress('#focusProgress', attention);
// brainProgress('#medProgress', meditation);
$("#focus").text(attention);
$("#meditation").text(meditation);
}
// handle "blinkStrength" data
if (data.blinkStrength) {
blink = data.blinkStrength;
var blinkcol = "white";
var eyeVal = map_range(blink, 0, 255, 0, 100);
$('#eyeBlinkStrength').text(parseInt(eyeVal));
if (blink > 40) {
//blinkcol = "rgba(102,211,43,1.0)";
eyeclicked = true;
// k++;
console.log(blink + " " + eyeclicked);
} else blinkcol = "white";
$('#eyeBlink').css({
width: eyeVal,
height: eyeVal,
background: blinkcol
});
} else {
blink = 0;
eyeclicked = false;
}
// handle "poorSignal" data
if (data.poorSignalLevel != null) {
poorSignalLevel = parseInt(data.poorSignalLevel);
}
};
// when websocket closes connection, do this stuff
ws.onclose = function() {
// websocket is closed.
console.log("Connection is closed...");
};
function map_range(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
EDIT CODE PEN DEMO
Mouse Input Based Code which demonstrate the logic of switching between multiple canvas. It works perfectly. Try to click into the center circle
var stateTwo, stateOne = true;
var eyeIsBlinked;
// sketch one -----------------------------------
var first = new p5(firstSketch, "canvasOne");
function firstSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(255, 10, 100);
p.fill(255);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (p.mouseIsPressed && p.dist(p.mouseX, p.mouseY, p.width / 2, p.height / 2) < 50) {
stateOne = false;
stateTwo = true;
console.log(" <-- one");
// k = 0;
// window.eyeIsBlinked = false;
// blink = 0;
}
if (stateOne) {
$('#canvasOne').css('opacity', '1');
$('#canvasTwo').css('opacity', '0.5');
// console.log("canvas One");
p.fill(255, 0, 0);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
// sketch two -----------------------------------
var second = new p5(secondSketch, "canvasTwo");
function secondSketch(p) {
p.setup = function() {
p.createCanvas(400, 250);
}
p.draw = function() {
p.background(60, 250, 100);
p.fill(0);
p.ellipse(p.width / 2, p.height / 2, 50, 50);
if (p.mouseIsPressed && p.dist(p.mouseX, p.mouseY, p.width / 2, p.height / 2) < 50) {
stateOne = true;
stateTwo = false;
console.log(" <-- two");
// k = 0;
// window.eyeIsBlinked = false;
//blink = 0;
}
if (stateTwo) {
$('#canvasOne').css('opacity', '0.5');
$('#canvasTwo').css('opacity', '1');
// console.log("canvas Two");
p.fill(0, 0, 255);
p.ellipse(p.random(p.width), p.random(p.height), 50, 50);
}
}
}
I don't know how your project works. But I guess the problem might be a scope problem. Both files are using the eyeclicked variable, but they might be using two different variables. Try to make sure that they're using the same variable by using it inside the window global variable.
So instead of eyeclicked use window.eyeclicked.

rotating SVG rect around its center using vanilla JavaScript

This is not a duplicate of the other question.
I found this talking about rotation about the center using XML, tried to implement the same using vanilla JavaScript like rotate(45, 60, 60) but did not work with me.
The approach worked with me is the one in the snippet below, but found the rect not rotating exactly around its center, and it is moving little bit, the rect should start rotating upon the first click, and should stop at the second click, which is going fine with me.
Any idea, why the item is moving, and how can I fix it.
var NS="http://www.w3.org/2000/svg";
var SVG=function(el){
return document.createElementNS(NS,el);
}
var svg = SVG("svg");
svg.width='100%';
svg.height='100%';
document.body.appendChild(svg);
class myRect {
constructor(x,y,h,w,fill) {
this.SVGObj= SVG('rect'); // document.createElementNS(NS,"rect");
self = this.SVGObj;
self.x.baseVal.value=x;
self.y.baseVal.value=y;
self.width.baseVal.value=w;
self.height.baseVal.value=h;
self.style.fill=fill;
self.onclick="click(evt)";
self.addEventListener("click",this,false);
}
}
Object.defineProperty(myRect.prototype, "node", {
get: function(){ return this.SVGObj;}
});
Object.defineProperty(myRect.prototype, "CenterPoint", {
get: function(){
var self = this.SVGObj;
self.bbox = self.getBoundingClientRect(); // returned only after the item is drawn
self.Pc = {
x: self.bbox.left + self.bbox.width/2,
y: self.bbox.top + self.bbox.height/2
};
return self.Pc;
}
});
myRect.prototype.handleEvent= function(evt){
self = evt.target; // this returns the `rect` element
this.cntr = this.CenterPoint; // backup the origional center point Pc
this.r =5;
switch (evt.type){
case "click":
if (typeof self.moving == 'undefined' || self.moving == false) self.moving = true;
else self.moving = false;
if(self.moving == true){
self.move = setInterval(()=>this.animate(),100);
}
else{
clearInterval(self.move);
}
break;
default:
break;
}
}
myRect.prototype.step = function(x,y) {
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().translate(x,y));
}
myRect.prototype.rotate = function(r) {
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix().rotate(r));
}
myRect.prototype.animate = function() {
self = this.SVGObj;
self.transform.baseVal.appendItem(this.step(this.cntr.x,this.cntr.y));
self.transform.baseVal.appendItem(this.rotate(this.r));
self.transform.baseVal.appendItem(this.step(-this.cntr.x,-this.cntr.y));
};
for (var i = 0; i < 10; i++) {
var x = Math.random() * 100,
y = Math.random() * 300;
var r= new myRect(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16));
svg.appendChild(r.node);
}
UPDATE
I found the issue to be calculating the center point of the rect using the self.getBoundingClientRect() there is always 4px extra in each side, which means 8px extra in the width and 8px extra in the height, as well as both x and y are shifted by 4 px, I found this talking about the same, but neither setting self.setAttribute("display", "block"); or self.style.display = "block"; worked with me.
So, now I've one of 2 options, either:
Find a solution of the extra 4px in each side (i.e. 4px shifting of both x and y, and total 8px extra in both width and height),
or calculating the mid-point using:
self.Pc = {
x: self.x.baseVal.value + self.width.baseVal.value/2,
y: self.y.baseVal.value + self.height.baseVal.value/2
};
The second option (the other way of calculating the mid-point worked fine with me, as it is rect but if other shape is used, it is not the same way, I'll look for universal way to find the mid-point whatever the object is, i.e. looking for the first option, which is solving the self.getBoundingClientRect() issue.
Here we go…
FIDDLE
Some code for documentation here:
let SVG = ((root) => {
let ns = root.getAttribute('xmlns');
return {
e (tag) {
return document.createElementNS(ns, tag);
},
add (e) {
return root.appendChild(e)
},
matrix () {
return root.createSVGMatrix();
},
transform () {
return root.createSVGTransformFromMatrix(this.matrix());
}
}
})(document.querySelector('svg.stage'));
class Rectangle {
constructor (x,y,w,h) {
this.node = SVG.add(SVG.e('rect'));
this.node.x.baseVal.value = x;
this.node.y.baseVal.value = y;
this.node.width.baseVal.value = w;
this.node.height.baseVal.value = h;
this.node.transform.baseVal.initialize(SVG.transform());
}
rotate (gamma, x, y) {
let t = this.node.transform.baseVal.getItem(0),
m1 = SVG.matrix().translate(-x, -y),
m2 = SVG.matrix().rotate(gamma),
m3 = SVG.matrix().translate(x, y),
mtr = t.matrix.multiply(m3).multiply(m2).multiply(m1);
this.node.transform.baseVal.getItem(0).setMatrix(mtr);
}
}
Thanks #Philipp,
Solving catching the SVG center can be done, by either of the following ways:
Using .getBoundingClientRect() and adjusting the dimentions considering 4px are extra in each side, so the resulted numbers to be adjusted as:
BoxC = self.getBoundingClientRect();
Pc = {
x: (BoxC.left - 4) + (BoxC.width - 8)/2,
y: (BoxC.top - 4) + (BoxC.height - 8)/2
};
or by:
Catching the .(x/y).baseVal.value as:
Pc = {
x: self.x.baseVal.value + self.width.baseVal.value/2,
y: self.y.baseVal.value + self.height.baseVal.value/2
};
Below a full running code:
let ns="http://www.w3.org/2000/svg";
var root = document.createElementNS(ns, "svg");
root.style.width='100%';
root.style.height='100%';
root.style.backgroundColor = 'green';
document.body.appendChild(root);
//let SVG = function() {}; // let SVG = new Object(); //let SVG = {};
class SVG {};
SVG.matrix = (()=> { return root.createSVGMatrix(); });
SVG.transform = (()=> { return root.createSVGTransformFromMatrix(SVG.matrix()); });
SVG.translate = ((x,y)=> { return SVG.matrix().translate(x,y) });
SVG.rotate = ((r)=> { return SVG.matrix().rotate(r); });
class Rectangle {
constructor (x,y,w,h,fill) {
this.node = document.createElementNS(ns, 'rect');
self = this.node;
self.x.baseVal.value = x;
self.y.baseVal.value = y;
self.width.baseVal.value = w;
self.height.baseVal.value = h;
self.style.fill=fill;
self.transform.baseVal.initialize(SVG.transform()); // to generate transform list
this.transform = self.transform.baseVal.getItem(0), // to be able to read the matrix
this.node.addEventListener("click",this,false);
}
}
Object.defineProperty(Rectangle.prototype, "draw", {
get: function(){ return this.node;}
});
Object.defineProperty(Rectangle.prototype, "CenterPoint", {
get: function(){
var self = this.node;
self.bbox = self.getBoundingClientRect(); // There is 4px shift in each side
self.bboxC = {
x: (self.bbox.left - 4) + (self.bbox.width - 8)/2,
y: (self.bbox.top - 4) + (self.bbox.height - 8)/2
};
// another option is:
self.Pc = {
x: self.x.baseVal.value + self.width.baseVal.value/2,
y: self.y.baseVal.value + self.height.baseVal.value/2
};
return self.bboxC;
// return self.Pc; // will give same output of bboxC
}
});
Rectangle.prototype.animate = function () {
let move01 = SVG.translate(this.CenterPoint.x,this.CenterPoint.y),
move02 = SVG.rotate(10),
move03 = SVG.translate(-this.CenterPoint.x,-this.CenterPoint.y);
movement = this.transform.matrix.multiply(move01).multiply(move02).multiply(move03);
this.transform.setMatrix(movement);
}
Rectangle.prototype.handleEvent= function(evt){
self = evt.target; // this returns the `rect` element
switch (evt.type){
case "click":
if (typeof self.moving == 'undefined' || self.moving == false) self.moving = true;
else self.moving = false;
if(self.moving == true){
self.move = setInterval(()=>this.animate(),100);
}
else{
clearInterval(self.move);
}
break;
default:
break;
}
}
for (var i = 0; i < 10; i++) {
var x = Math.random() * 100,
y = Math.random() * 300;
var r= new Rectangle(x,y,10,10,'#'+Math.round(0xffffff * Math.random()).toString(16));
root.appendChild(r.draw);
}

Categories

Resources