Render Three.js into a div element - html

I am using Three.js. Having a html site with two div elements, is it possible to render just in one div element?
HTML Code:
<body>
<div id="twocols">
<div id="detailinfo">
<span class="c">Detailinformationen:</span><br/>
<span id="tb" class="g"></span><br/>
<span class="c">Grafiken:</span>
<div id="chart"></div>
<div id="chart2"></div>
</div>
<div id="city">
</div>
</div>
</body>
I want to render into the city div.
Three.js Code:
function initScene() {
//container = document.createElement('div');
//document.body.appendChild(container);
scene = new THREE.Scene();
createCamera();
createLight();
createProjector();
createRenderer();
createControls();
//...
}
createRenderer:
function createRenderer() {
renderer = new THREE.WebGLRenderer({
antialias : ANTIALIAS,
preserveDrawingBuffer : DRAWINGBUFFER
});
renderer.setSize(document.getElementById("city").offsetWidth, document.getElementById("city").offsetHeight);
document.getElementById("city").appendChild(renderer.domElement);
THREEx.Screenshot.bindKey(renderer); // add the printscreen shortcut with "p"
}
createControls:
function createControls() {
controls = new InteractionManager(camera, document.getElementById("city"));
//...
}
InteractionManager.js
initialize: function(camera, domElement) {
this.object = camera;
this.domElement = (domElement !== undefined) ? domElement : document;
this.target = new THREE.Vector3( 0, 0, 0 );
//this.chartManager = new ChartsManager();
if ( this.domElement === document ) {
this.viewHalfX = window.innerWidth / 2;
this.viewHalfY = window.innerHeight / 2;
} else {
this.viewHalfX = this.domElement.offsetWidth / 2;
this.viewHalfY = this.domElement.offsetHeight / 2;
//alert(domElement.offsetWidth + " " + domElement.offsetHeight);
//this.domElement.setAttribute( 'tabindex', -1 );
}
//...
},
so far..

Instead of:
container = document.createElement('div');
Use:
container = document.getElementById('city');

Related

How do I convert this to an OOP structure?

Currently, this codepen I forked displays one tv monitor on the webpage as shown below where the channel button allows the user to toggle different gif's. This gif data is stored as an array in the js file. I want to create multiple tv sets, so I am thinking it may be better to create a TV class and instantiate the TV object n-times through a loop. I am new to OOP in a web dev context, so I haven't yet figured out how to rearchitect the code to accomplish this. Since id's only allow for one HTML element, duplicating the chunk of code below would visually create another tv but without any dynamic features. What then becomes of the tv-body display elements? Would they be enveloped with a show() fx nested with the script's TV class? Thank you so much in advance!
[Cropped Output Displayed Here][1]
HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - Vintage Analog TV</title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><link rel="stylesheet" href="./style.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
</head>
<body>
<!-- partial:indexe.partial.html -->
<main>
<div class="tv-set">
<div class="tv-body">
<div class="screen-container">
<canvas class="static" width="380" height="280"></canvas>
<img class="displayed" src="" alt="Nothing" width="380" height="280">
<div class="screen">
<div class="screen-frame"></div>
<div class="screen-inset"></div>
</div>
</div>
<div class="logo-badge">
<div class="logo-text">Bush</div>
</div>
<div class="controls">
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="channel dial-label pristine">Channel</button>
</div>
</div>
<div class="vents">
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
</div>
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="dial-label" disabled>Volume</button>
</div>
</div>
</div>
</div>
<div class="legs">
<div class="leg"></div>
<div class="leg"></div>
</div>
</div>
</main>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
JS
document.addEventListener("DOMContentLoaded", tv);
// Helper Functions
//returns tagname
jQuery.fn.tagName = function () {
return this.prop("tagName").toLowerCase;
};
// returns nth parent from target element
$.fn.nthParent = function (n) {
var p = this;
for (var i = 0; i < n; i++)
p = p.parent();
return p;
}
phases = [{
channels: ["red", "blue"]
},
{
channels: ["green", "yellow"]
},
{
channels: ["red", "green"]
},
{
channels: ["blue", "green"]
}
]
const container = document.getElementsByTagName("main")[0];
const template = document.getElementsByClassName("tv-set")
for (let i = 0; i < phases.length; i++) {
const clone = template[i].cloneNode(true);
clone.setAttribute("id", "tv-" + (i + 1))
console.log("clone id: ", clone.getAttribute("id"))
clone.setAttribute("data-channel", 0)
clone.setAttribute("name", "tv-" + i)
// clone.style.backgroundColor = phases[i].channels[0]
container.appendChild(clone)
}
function tv() {
let cnvs = document.querySelectorAll(".static");
//Gather all static elements
// let scrns = $(".static").getContext
// console.log("Screen 01: ", scrns)
// var cnv = document.getElementById("static"),
// var cnv = document.querySelector(".static"), //works in place of line above
// Need to establish a boolean array for the isStatic
let c = []
let isStatic_arr = []
// Need to establish a boolean array for the isStatic
cnvs.forEach((cnv) => {
isStatic_arr.push(false)
var c = cnv.getContext("2d"),
cw = cnv.offsetWidth,
ch = cnv.offsetHeight,
staticScrn = c.createImageData(cw, ch),
staticFPS = 30,
// isStatic_arr.push(false),
// isStatic = false,
staticTO,
gifData = [{
// file: "https://i.ibb.co/chSK1Zt/willie.gif",
file: "./media/back-to-school-chacha.gif",
desc: "Stephen Chow Fight Back to School"
// <video controls autoplay>
// <source src="fbts_chacha_sound.mp4" type="video/mp4">
// <source src="movie.ogg" type="video/ogg">
// Your browser does not support the video tag.
// </video>
},
{
file: "https://i.ibb.co/chSK1Zt/willie.gif",
desc: "Steamboat Willie (Mickey Mouse) steering a ship"
},
{
file: "https://i.ibb.co/0FqQVrj/skeletons.gif",
desc: "Spooky scary skeletons sending shivers down your spine"
},
{
file: "https://i.ibb.co/Hpnwgq2/kingkong.gif",
desc: "King Kong waving on Empire State Building",
},
{
file: "https://i.ibb.co/fp0PSjv/tracks.gif",
desc: "Looking at train tracks from behind a train",
},
{
file: "https://i.ibb.co/5FM7BtH/nuke.gif",
desc: "Nuclear explosion at sea",
}
],
gifs = [],
channel = 0;
for (g in gifData) {
gifs.push(new Image());
gifs[g].src = gifData[g].file;
gifs[g].alt = gifData[g].desc;
}
/* Static */
var runStatic = function () {
isStatic = true;
c.clearRect(0, 0, cw, ch);
for (var i = 0; i < staticScrn.data.length; i += 4) {
let shade = 127 + Math.round(Math.random() * 128);
staticScrn.data[0 + i] = shade;
staticScrn.data[1 + i] = shade;
staticScrn.data[2 + i] = shade;
staticScrn.data[3 + i] = 255;
}
c.putImageData(staticScrn, 0, 0);
staticTO = setTimeout(runStatic, 1e3 / staticFPS);
};
runStatic();
/* Channels */
var changeChannel = function (button, idx) {
console.log("Tv-set: ", idx)
console.log("Tv-set- " + idx + "button: " + button)
// var displayed = document.getElementById("displayed");
var displayed = document.querySelectorAll(".displayed")[idx];
var display_parent = $(".displayed")[1]
console.log("Display: ", displayed)
console.log("Display's parent: ", display_parent)
++channel;
if (channel > gifData.length)
channel = 1;
// this.classList.remove("pristine");
button.classList.remove("pristine");
// this.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
button.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
theCanvas = document.querySelectorAll(".static")[idx]
// cnv.classList.remove("hide");
theCanvas.classList.remove("hide");
displayed.classList.add("hide"); //CAUSING PROBLEMS
if (!isStatic[idx])
runStatic();
setTimeout(function () {
// cnv.classList.add("hide");
theCanvas.classList.add("hide");
displayed.classList.remove("hide");
displayed.src = gifs[channel - 1].src;
displayed.alt = gifs[channel - 1].alt;
isStatic = false;
clearTimeout(staticTO);
}, 300);
};
function iterate(item, index) {
console.log(`${item} has index ${index}`);
}
// const buttons = document.getElementsByClassName("channel dial-label pristine");
// const btns_arr = Array.from(document.querySelectorAll(".channel"))
const buttons = document.querySelectorAll(".channel")
buttons.forEach((btn, i) => {
btn.addEventListener('click', () => changeChannel(btn, i));
});
});
}
[1]: https://i.stack.imgur.com/INtzP.png
[2]: https://i.stack.imgur.com/aOxoQ.png
(11/14/20) #ggirodda, thank you so much for the example. Unfortunately, I am still a bit stuck. Why is it when I use const template = document.getElementsByClassName("tv-body").children[0], I get the error: script_001.js:154 Uncaught TypeError: Cannot read property '0' of undefined
at HTMLDocument.tv (script_001.js:154) Shouldn't the tv-body class have children based on the code snippet below?
(11/14/20) Addressed error above by removing .children[0] but unsure as to why that works and why it was undefined.
(11/19/20) Resolved! Sort of, that is. All tv clones can will run as intended, meaning the static display will remain active on all tv's whose channel button has not been pressed, and the channels can be changed independently. Here were the main changes I made on the original code:
All id's replaced with classes so that they can be accessed and wrapped the "tv-body" and "legs" in a separate div so that they can be cloned as a set.
Gathered all the "tv-set" class elements outside of the tv function() and then performed the setup functions forEach()
Converted a few of the variables e.g canvas, isStatic into arrays so that their states and displays could be toggled independently. I am sure there is more work to be done here as some of the variables may still be shared among the clones.
You can take some inspiration from the code below, the example is less complex but the idea is the same
const tvs = [
{ channels: ["red", "blue"] },
{ channels: ["green", "yellow"] }
]
function changeChannel(idx) {
const tv = tvs[idx]
const tvNode = document.getElementById("tv-" + idx)
const currentChannelIdx = parseInt(tvNode.getAttribute("data-channel"))
const nextChannelIdx = tv.channels[currentChannelIdx + 1] ? currentChannelIdx + 1 : 0;
tvNode.style.backgroundColor = tv.channels[nextChannelIdx]
tvNode.setAttribute("data-channel", nextChannelIdx)
}
const container = document.getElementById("container")
const template = document.getElementById("tv-template").children[0]
for (let i = 0; i < tvs.length; i++) {
const clone = template.cloneNode(true);
clone.setAttribute("id", "tv-" + i)
clone.setAttribute("data-channel", 0)
clone.style.backgroundColor = tvs[i].channels[0]
container.appendChild(clone)
}
const buttons = document.getElementsByClassName("channel-btn")
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', () => changeChannel(i), false);
}
<div id="container"></div>
<div id="tv-template" style="display: none;">
<div class="tv" style="width: 70px; height: 70px; margin-bottom: 20px;">
<button class="channel-btn">next</button>
</div>
</div>

p5 sketch always below other angular components

I've built a p5 sketch in my app.component file but it seems to always be at the bottom of all other components. Right now I'm at a loss on how to fix this so my sketch is always at the top. Any help on how I can control the positioning of my sketch would be greatly appreciated!
<!-- this is the main app.component.html -->
<div class="nav">
<button [routerLink]="['/']"> Landing </button>
<button [routerLink]="['/resume']"> Resume </button>
<button [routerLink]="['/projects']"> Projects </button>
<button [routerLink]="['/pagenotfound']"> pagenotfound </button>
</div>
<div style="text-align:center">
<h1> {{ title }} </h1>
</div>
<router-outlet></router-outlet>
This is the app.component.ts
import {
Component
} from '#angular/core';
import 'p5';
declare
var p5: any;
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = '';
test: any
private p5sketch;
constructor() {}
ngOnInit() {
this.createCanvas();
if (window.innerWidth < 600) {
this.title = 'Welcome to my Portfolio'
}
}
private createCanvas() {
this.p5sketch = new p5(this.sketch);
}
private sketch(p: any) {
// not showing for mobile because it looks horrible and takes up processing
if (window.innerWidth < 600) {
return;
}
var canvasVector = {
'width': 1200,
'height': 200
}
var font;
var vehicles = [];
// preload
p.preload = () => {
font = p.loadFont('../assets/AvenirNextLTPro-Demi.otf');
}
// setup
p.setup = () => {
p.createCanvas(window.innerWidth, canvasVector.height);
p.background(51);
let verticies = font.textToPoints("Welcome to my Portfolio", p.width * .1, p.height / 1.5, 100);
verticies.map((dot) => vehicles.push(new Vehicle(dot.x, dot.y)));
};
function Vehicle(x, y) {
this.pos = p.createVector(p.random(p.width), p.random(p.height));
this.target = p.createVector(x, y);
this.vel =
p5.Vector.random2D();
// p.createVector();
this.acc = p.createVector();
this.maxspeed = 10;
this.maximumforce = 1;
}
Vehicle.prototype.update = function() {
this.pos.add(this.vel);
this.vel.add(this.acc);
this.acc.mult(0);
}
Vehicle.prototype.show = function() {
p.stroke(255);
p.strokeWeight(5);
p.point(this.pos.x, this.pos.y);
}
Vehicle.prototype.behaviors = function() {
var arrive = this.arrive(this.target);
var mouse = p.createVector(p.mouseX, p.mouseY);
var flee = this.flee(mouse).mult(5);
this.applyForce(arrive);
this.applyForce(flee);
}
Vehicle.prototype.applyForce = function(f) {
this.acc.add(f);
}
Vehicle.prototype.flee = function(target) {
var desired = p5.Vector.sub(target, this.pos);
var d = desired.mag();
if (d < 50) {
desired.setMag(this.maxspeed);
desired.mult(-1);
var steer = p5.Vector.sub(desired, this.vel);
steer.limit(this.maximumforce)
return steer;
} else {
return p.createVector(0, 0);
}
}
Vehicle.prototype.arrive = function(target) {
var desired = p5.Vector.sub(target, this.pos);
var d = desired.mag();
var speed = (d < 100) ?
speed = p.map(d, 0, 100, 0, this.maxspeed) :
this.maxspeed;
desired.setMag(speed);
var steer = p5.Vector.sub(desired, this.vel);
steer.limit(this.maximumforce)
return steer;
}
// draw
p.draw = () => {
p.background(51);
for (let i = 0; i < vehicles.length; i++) {
var v = vehicles[i];
v.behaviors();
v.update();
v.show();
}
}
// end draw
}
}
If you're using the default createCanvas() function, then it creates a new canvas and adds it to the bottom of the page.
You can move that canvas using the P5.dom library, specifically the parent() function. From the reference:
// in the html file:
// <div id="myContainer"></div>
// in the js file:
var cnv = createCanvas(100, 100);
cnv.parent('myContainer');
This will move the canvas into the myContainer div element.

How to apply z-index for fabric js handlers

setTimeout(function () {
var myImg = document.querySelector("#background");
var realWidth = myImg.naturalWidth;
var realHeight = myImg.naturalHeight;
$("canvas").attr("width", realWidth);
$("canvas").attr("height", realHeight);
var source = document.getElementById('background').src;
var canvas = new fabric.Canvas('canvas');
canvas.width = realWidth;
canvas.height = realHeight;
var ctx = canvas.getContext('2d');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({
left: 320
, top: 180
, angle: 00
, width: 200
, height: 200
});
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({
format: 'png'
, quality: 0.8
});
});
};
reader.readAsDataURL(file);
});
canvas.setOverlayImage(source, canvas.renderAll.bind(canvas), {
backgroundImageOpacity: 0.5
, backgroundImageStretch: false
});
canvas.on('mouse:over', function (e) {
canvas.item(0).hasBorders = true;
canvas.item(0).hasControls = true;
canvas.setActiveObject(canvas.item(0));
});
canvas.on('mouse:out', function (e) {
canvas.item(0).hasBorders = false;
canvas.item(0).hasControls = false;
canvas.setActiveObject(canvas.item(0));
});
canvas.renderAll();
}, 2000);
$("#save").click(function () {
function blobCallback(iconName) {
return function (b) {
var a = document.getElementById('download');
a.download = iconName + ".jpg";
a.href = window.URL.createObjectURL(b);
}
}
canvas.toBlob(blobCallback('wallpaper'), 'image/vnd.microsoft.jpg', '-moz-parse-options:format=bmp;bpp=32');
});
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cricmovie.com/bb-asserts/js/fabric.min.js"></script>
<body>
<div class="container"> <img src="http://cricmovie.com/bb-asserts/images/person.png" id="background" class="hide">
<input type="file" id="file">
<br />
<canvas id="canvas" class="img-responsive"></canvas>
</div>
<div class="container"> <a class="btn btn-primary" id="save">Save</a> <a class="btn btn-primary" id="download">Download</a> </div>
</body>
I am using fabric js to build a facemask application when i have two images
1) Image without face which is applied to canvas using setOverlayImage method
2) Only head where the user will upload and adjust accordingly.
I have almost done with functionality but I want to show fabric handlers above the first image where now they are hiding behind first image.
Reference Image : Click here for reference Image
Please find the Run Code Snippet
I think all you need to do is specify controlsAboveOverlay when you get the fabric instance.
var canvas = new fabric.Canvas('canvas', {
controlsAboveOverlay : true
});

Div content resizing

I have 3 different charts inside 3 different div tags that appear and hide when specified. However, two of the charts randomly resize and i know why.
How do i fix this?
I have wordpress and using visualizer plugin for my charts. have the code in the header.php file and in the text portion of the page specific code.
Code below:
Header.php snippet -
<script>
var divs = ["Daily", "Weekly", "Monthly"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
HTML page snippet -
<div class="inner_div">
<div id="Daily">[visualizer id="431"]</div>
<div id="Weekly" style="display: none;">[visualizer id="430"]</div>
<div id="Monthly" style="display: none;">[visualizer id="429"]</div>
</div>
<div class="main_div">
<div class="buttons">
Daily | Weekly | Monthly
</div>
A quick fix is to include call visualizer.render(); at the end of your toggleVisibility function:
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
visualizer.render();
}
The problem is caused by invalid calculation of available area for divs that aren't visible at the time. Calling this method forces a re-calulcation of the svgs and ensures the right size.

Prevent dragging of child element within a draggable element

I have an element that I want to be able to drag, but I have elements inside of it that I don't want to be able to drag. I'm hoping there is a simple answer without (a lot of) jQuery.
Here is what I am trying to accomplish.
<html>
<head>
</head>
<style>
.a {
width:400px;
height:400px;
border:1px solid black;
}
.b{
width:200px;
height:200px;
border:1px solid black;
margin:20px;
}
</style>
<body>
<div class="a" draggable="true">
<span>I can drag this!</span>
<div class="b" draggable="false">
I can drag this as well, but I don't want to.
</div>
</div>
</body>
</html>
http://plnkr.co/edit/Xto7lPO32TRVScewJkS9
Any ideas?
Don't know if this question is still relevant, but I found a way to solve your problem like this:
<body>
<div class="a" draggable="true">
<span>I can drag this!</span>
<div class="b" draggable="true" ondragstart="event.preventDefault()">
I can drag this as well, but I don't want to.
</div>
</div>
</body>
Seems a little hacky, but it does the trick. I haven't found any other way to solve this. Hope it helps you.
Cheers
Sam
What you want to do is availlable in this code (that allows touch with finger too) :
var draggables = document.querySelectorAll('.is-draggable');
[].forEach.call(draggables, function (el) {
var startX, startY, initialX, initialY,
auth = function (target) {
var notDraggables = el.querySelectorAll('.is-not-draggable');
return [].filter.call(notDraggables, function (element) {
return target !== element;
}).length > 0;
};
function move(gesture) {
var deltaGestureX = gesture.clientX - initialX,
deltaGestureY = gesture.clientY - initialY,
deltaPositionX = startX + deltaGestureX,
deltaPositionY = startY + deltaGestureY,
limitX = parseInt(window.innerWidth - el.clientWidth, 10),
limitY = parseInt(window.innerHeight - el.clientHeight, 10);
if (deltaPositionY <= 0) {
el.style.top = '0px';
} else if (deltaPositionY >= limitY) {
el.style.top = limitY + 'px';
} else {
el.style.top = startY + deltaGestureY + 'px';
}
if (deltaPositionX <= 0) {
el.style.left = '0px';
} else if (deltaPositionX >= limitX) {
el.style.left = limitX + 'px';
} else {
el.style.left = startX + deltaGestureX + 'px';
}
return false;
}
function mousemove(e) {
move(e);
}
function mouseup() {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
}
function touchmove(e) {
move(e.touches[0]);
}
function touchend() {
document.removeEventListener('touchmove', touchmove);
document.removeEventListener('touchend', touchend);
}
el.addEventListener('touchstart', function (e) {
if (auth(e.target)) {
startX = el.offsetLeft;
startY = el.offsetTop;
initialX = e.touches[0].clientX;
initialY = e.touches[0].clientY;
document.addEventListener('touchmove', touchmove);
document.addEventListener('touchend', touchend);
}
});
el.addEventListener('mousedown', function (e) {
if (auth(e.target)) {
startX = el.offsetLeft;
startY = el.offsetTop;
initialX = e.clientX;
initialY = e.clientY;
document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
return false;
}
});
});
See demo : http://plnkr.co/edit/d6wVpTDcGDxLHAwkAVgD?p=preview