p5 sketch always below other angular components - html

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.

Related

I am drawing a real-time chart using React html canvas. The chart flashes when data is updated. is there any solution

If you run the code below, the chart graph will be updated while flashing. Is there any way to get rid of the glitter?
When the data changes, the value of the child changes, so it seems to be my rendering problem, but I don't know what format to change. Any help please
import CanvasLine from '#components/CanvasLine';
import { memo, useContext, useEffect, useState } from 'react';
const CHART_DUMMY_DATA2 = (): Array<number> => {
const date = new Date();
date.setSeconds(date.getSeconds() - 249);
return [...new Array(249)].map((_, _idx) => {
return 0;
});
};
const CanvasLineChartDemo = () => {
const [chartHRArray, setChartHRArray] = useState(CHART_DUMMY_DATA2);
const [chartSP02Array, setChartSP02Array] = useState(CHART_DUMMY_DATA2);
const [chartRESPArray, setChartRESPArray] = useState(CHART_DUMMY_DATA2);
const returnRandomFloat = (min: number, max: number) => {
return (Math.random() * (max - min) + min).toFixed(2);
};
const validate = () => {
setChartHRArray((prevState: any) =>
[...prevState, returnRandomFloat(-100, 100)].slice(1),
);
setChartSP02Array((prevState: any) =>
[...prevState, returnRandomFloat(-100, 100)].slice(1),
);
setChartRESPArray((prevState: any) =>
[...prevState, returnRandomFloat(-100, 100)].slice(1),
);
};
useEffect(() => {
const interval = setInterval(() => {
validate();
}, 100);
return () => {
clearInterval(interval);
};
}, [connectStatus]);
return (
<>
<div
style={{ width: '700px', background: '#000', marginRight: 10 }}
>
vdrDevice {vdrDevice}
<CanvasLine
height={50}
canvasData={chartHRArray}
/>
<CanvasLine
height={50}
canvasData={chartSP02Array}
/>
<CanvasLine
height={50}
canvasData={chartRESPArray}
/>
</div>
</>
);
};
export default memo(CanvasLineChartDemo);
import React, { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
type CanvasType = {
yMin?: number;
yMax?: number;
height: number;
lineColor: string;
canvasData: number[];
};
const CanvasLine = ({
yMax,
yMin,
height,
lineColor,
canvasData,
}: CanvasType) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
let CanvasContext: CanvasRenderingContext2D | null = null;
// Array Max number
const getYMax = (data: number[]) => {
return Math.max.apply(null, data);
};
// Array Min number
const getYMin = (data: number[]) => {
return Math.min.apply(null, data);
};
const calculateY = (
canvasData: number[],
index: number,
height: number,
yMaxNum: number,
yMinNum: number,
) => {
const xAxis = (yMaxNum / (yMaxNum - yMinNum)) * height;
const yScale = -height / (yMaxNum - yMinNum);
const valueRatio = canvasData[index] * yScale + xAxis; // 마이너스영역 및 플러스 영역
return valueRatio;
};
const createCanvas = () => {
const canvas = canvasRef.current;
if (canvas) {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
canvas.style.width = '100%';
canvas.style.height = `${height}px`;
}
};
useEffect(() => {
createCanvas();
}, []);
useEffect(() => {
const canvas = canvasRef.current;
const yMaxNum = yMax ?? getYMax(canvasData);
const yMinNum = yMin ?? getYMin(canvasData);
if (canvas) {
let xStep = canvas.width / canvasData.length,
xAxis = xStep,
xStart = 0,
yAxis = calculateY(
canvasData,
0,
canvas.height,
yMinNum,
yMaxNum,
);
CanvasContext = canvas.getContext('2d');
if (!canvas.hasChildNodes()) {
CanvasContext?.clearRect(0, 0, canvas.width, canvas.height);
} else {
CanvasContext?.clearRect(0, 0, canvas.width, canvas.height);
}
const canvasDraw = (canvas: HTMLCanvasElement) => {
if (CanvasContext) {
CanvasContext?.clearRect(0, 0, canvas.width, canvas.height);
CanvasContext.lineWidth = 1.5;
CanvasContext.lineJoin = 'miter';
CanvasContext.beginPath();
CanvasContext.moveTo(xStart, yAxis);
CanvasContext.lineCap = 'round';
CanvasContext.strokeStyle = lineColor;
CanvasContext.fillStyle = lineColor;
for (let i = 1; i < canvasData.length; i++) {
yAxis = calculateY(
canvasData,
i,
canvas.height,
yMinNum,
yMaxNum,
);
CanvasContext.lineTo(xAxis, yAxis);
CanvasContext.moveTo(xAxis, yAxis);
xAxis = xAxis + xStep;
}
CanvasContext.stroke();
CanvasContext.fill();
}
};
canvasDraw(canvas);
}
}, [canvasData]);
return (
<>
<canvas id="canvas" style={{ width: '100%' }} ref={canvasRef} />
</>
);
};
export default React.memo(CanvasLine);
CanvasLine.defaultProps = {
height: 50,
lineColor: '#2C82C9',
canvasData: [],
};
You can see that the chart line flickers finely.
[1]: https://i.stack.imgur.com/XvtTd.gif
If you look at the gif, you can find the sparkling phenomenon.
Please suggest a way to solve the problem. Thanks in advance.
`

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. In React I am gettinf this error

Here I am trying to put that screening function at the radius of the TagCloud Object. The screening function returns different number according to the screen width.
But I am getting that error. Any Solution is most welcome. :)
import { useEffect, useRef } from "react";
import "../Skills/Skills.css";
import useWindowSize from "./Screen";
const Skills = () => {
const shoudLog = useRef(true);
useEffect(() => {
if (shoudLog.current) {
shoudLog.current = false;
const myTags = [
"JavaScript",
"CSS",
];
const TagCloud = require("TagCloud");
const container = ".content";
TagCloud(container, myTags, {
radius: Screening(),
maxSpeed: "normal",
});
}
}, []);
const Screening = () => {
const windowSize = useWindowSize();
if (windowSize.width > 1240) {
return 250;
} else if (windowSize.width < 1240 && windowSize.width > 1000) {
return 200;
} else if (windowSize.width < 1000 && windowSize.width > 900) {
return 180;
} else if (windowSize.width < 900 && windowSize.width > 750) {
return 150;
} else if (windowSize.width < 750 && windowSize.width > 600) {
return 130;
} else if (windowSize.width < 600) {
return 200;
}
};
return (
<div className="skillsset" id="skills">
<h1 className="skills-title">Skills</h1>
</div>
);
};
export default Skills;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
With the rules of hooks, you can't use hooks outside the render method, or use them conditionally.
In this part:
const Screening = () => {
const windowSize = useWindowSize();
// ...
}
You are using a hook inside a nested function, which is a no-no. You might want to do something like this:
// put the hook *directly* in the render method
const windowSize = useWindowSize();
const Screening = () => {
// ...
}

Google Map Custom Marker not draggable

I have created a Google Map custom marker in a Vue component. I have set draggable = "true" but the marker is not draggable. How can I make the marker draggable and get the coordinates once it has been dragged?
/////////////////////////////////////////////////////////////
// basemap
<template>
<div>
<GmapMap :style="'height:500px'" :center="center" :zoom="zoom">
<Location :location="location1"/>
</GmapMap>
</div>
</template>
////////////////////////////////////////////////////////
// Location
<template>
<div>
<GmapCustomMarker
ref="editMarker"
:marker="location.pos"
:draggable="true"
class="g_marker"
alignment="center"
:z-index="999"
>
<div style="background-color: red; width: 50px; height: 50px; border: 2px solid black;"></div>
</GmapCustomMarker>
</div>
</template>
<script>
import GmapCustomMarker from "vue2-gmap-custom-marker";
I guess you are utilizing vue2-gmap-custom-marker package, right? If so, it does not seem to support dragging option. But the following example demonstrates how to implement a draggable marker as a Vue component (which is based on this example):
<template>
<div :draggable="true" :style="{'position': 'absolute'}">
<slot />
</div>
</template>
<script>
import * as VueGoogleMaps from "vue2-google-maps";
/* global google */
export default {
mixins: [VueGoogleMaps.MapElementMixin],
props: {
position: {
type: Object,
default: undefined
}
},
methods: {},
data() {
return {
current: null,
origin: null
};
},
provide() {
const self = this;
return this.$mapPromise.then(map => {
class Overlay extends google.maps.OverlayView {
constructor(map) {
super();
this.setMap(map);
self.current = new google.maps.LatLng(
self.position.lat,
self.position.lng
);
}
draw() {
const container = self.$el;
let pos = this.getProjection().fromLatLngToDivPixel(self.current);
container.style.left = pos.x + "px";
container.style.top = pos.y + "px";
}
onAdd() {
const container = self.$el;
const panes = this.getPanes();
panes.floatPane.appendChild(container);
google.maps.event.addDomListener(
self.$map.getDiv(),
"mouseleave",
() => {
google.maps.event.trigger(container, "mouseup");
}
);
google.maps.event.addDomListener(container, "mousedown", e => {
container.style.cursor = "move";
self.$map.set("draggable", false);
self.origin = e;
const mouseMoveHandler = google.maps.event.addDomListener(
self.$map.getDiv(),
"mousemove",
e => {
let left = self.origin.clientX - e.clientX;
let top = self.origin.clientY - e.clientY;
let pos = self.$overlay
.getProjection()
.fromLatLngToDivPixel(self.current);
let latLng = self.$overlay
.getProjection()
.fromDivPixelToLatLng(
new google.maps.Point(pos.x - left, pos.y - top)
);
self.origin = e;
self.current = latLng;
this.draw();
}
);
google.maps.event.addDomListener(container, "mouseup", () => {
self.$map.set("draggable", true);
container.style.cursor = "default";
google.maps.event.removeListener(mouseMoveHandler);
});
});
}
onRemove() {
self.$el.remove();
}
}
this.$overlay = new Overlay(map);
});
},
destroyed() {
this.$overlay.setMap(null);
this.$overlay = undefined;
}
};
</script>
Here is a demo

Getting NaN when a directive is used in angularJs

I am using a directive to show the number count effect for my dashboard when i used the directive for the h3 i am getting the result as NaN. when i remove the directive from the h3 i am getting the correct output.
When i looked into the directive i can the the value is get from element which shows the value as NaN. can anyone tell me what is wrong in the code?
Output with directive:
<h3 animate-numbers="" class="ng-binding">NaN</h3>
Html:
<h3 animate-numbers>{{vm.dashboard.no_of_applications}}</h3>
Controller:
vm.dashboard = {
no_of_users: 0,
no_of_applications: 0,
no_of_departments: 0,
no_of_schemes: 0,
};
Directive:
'use strict';
angular.module('ss')
.directive('animateNumbers', function ($timeout, $log) {
return {
replace: false,
scope: true,
link: function (scope, element) {
var e = element[0];
$log.log('e is', e);
var refreshInterval = 30;
var duration = 1000; //milliseconds
var number = parseInt(e.innerText);
var step = 0;
var num = 0;
var steps = Math.ceil(duration / refreshInterval);
var increment = (number / steps);
var percentCompleted = 0;
var lastNumberSlowCount = 3;
if (number > lastNumberSlowCount) {
number = number - lastNumberSlowCount;
}
scope.timoutId = null;
var slowCounter = function () {
scope.timoutId = $timeout(function () {
lastNumberSlowCount --;
if (lastNumberSlowCount < 0) {
$timeout.cancel(scope.timoutId);
} else {
number++;
e.textContent = number;
slowCounter();
}
}, 500);
};
var counter = function () {
scope.timoutId = $timeout(function () {
num += increment;
percentCompleted = Math.round((num / number) * 100);
if (percentCompleted > 60 && percentCompleted < 80) {
refreshInterval = refreshInterval + 10;
} else if (percentCompleted > 90) {
refreshInterval = 200;
}
step++;
if (step >= steps) {
$timeout.cancel(scope.timoutId);
num = number;
e.textContent = number;
if (number > lastNumberSlowCount) {
slowCounter();
}
} else {
e.textContent = Math.round(num);
counter();
}
}, refreshInterval);
};
counter();
return true;
}
};
});

How to set a video current time on page load in HTML5 then add a seek listener synchronously

I have the following React component that grabs a video frame and loads the frame image into another image component upon specific events(pause, seek).
I wish to be able to set the current video frame position on rendering of the video element then add a seek event afterwards .
The problem I am experiencing is setting the frame position in componentDidMount with: video.currentTime = this.props.currentVideoFramePosition actually calls the seek event even though I added the event afterwards.
How can I modify the below code to set the current time of the video without triggering the seek event.
I am trying to avoid this on page load because the draw function is returning a value to another component which I do not want…….
import React from 'react';
export default class MyComponent extends React.Component {
constructor() {
super();
const self = this;
this.frameCaptureListener = function(e){
self.draw();
};
}
componentDidMount() {
var video = document.getElementById('video');
document.getElementById('video-canvas').style.display='none';
video.currentTime = this.props.currentVideoFramePosition;
video.addEventListener('pause', this.frameCaptureListener, false);
video.addEventListener('seeked', this.frameCaptureListener, false);
}
componentWillUnmount(){
var video = document.getElementById('video');
video.removeEventListener('pause', this.frameCaptureListener, false );
video.removeEventListener('seeked', this.frameCaptureListener, false);
}
draw(){
var video = document.getElementById('video');
var canvas = document.getElementById('video-canvas');
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = 1280;
canvas.height = 720;
context.drawImage( video, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
video.setAttribute('crossOrigin', 'anonymous');
var frameData = {imgSrc:dataURL, lastFramePosition:video.currentTime};
return this.props.onPause(frameData);
}
onArrowNavClick(navNum){
const self = this;
var video = document.getElementById('video');
video.currentTime = video.currentTime + navNum;
video.pause();
}
render(){
const videoUrl = this.props.videoUrl;
return(
<div>
<div className="framegrab-videocontainer">
<img src="/images/arrow_left_grab.svg" className="arrow-left" onClick={() => this.onArrowNavClick(-1)}></img>
<video id="video" src={videoUrl} className="framegrab-video" controls crossOrigin="anonymous" />
<img src="/images/arrow_right_grab.svg" className="arrow-right" onClick={() => this.onArrowNavClick(1)}></img>
</div>
<canvas id="video-canvas" ></canvas>
</div>
);
}
}
Here is how I am doing it with audio. Your problem with triggering seeking might be fixed by using a if (video.captureTime == props.captureTime) return; in frameCaptureListener.
import React from 'react';
import kshuffle, {knuthShuffle} from 'knuth-shuffle';
import JProgressBar from '../common/jProgressBar';
import PlayerActions from './player.actions';
let PlayerCtrlSty = {
backgroundColor: '#072202',
color: '#eaab5f',
margin: 'auto',
padding: '3px',
width: '320px'
}
let timerLeftSty = {minWidth: '40px'}
let timerRightSty = {textAlign: 'right', minWidth: '40px'}
let getTime = (time) => {
var minutes = time < 60 ? 0 : Math.floor(time / 60);
var seconds = Math.floor(time - (minutes * 60)) * .01;
return (minutes + seconds).toFixed(2);
}
class PlayerCtrlRender extends React.Component {
render() {
let index = this.state.playIndex;
let currentTrack = this.state.randomOn ? this.state.shuffledQueue[index] : this.props.queue[index];
let source = 'http://192.168.0.101:3950/play/' + currentTrack.location;
let title = currentTrack.title;
let progressData = {count: this.state.progressCount * 100, index: this.state.progressIndex * 100};
return (
<div id='PlayerCtrlSty' style={PlayerCtrlSty}>
<div className='FlexBox'>
<div style={timerLeftSty}>{this.state.progressIndex}</div>
<PlayerActions playing={this.state.isPlaying} clickHandler={this.clickHandler}/>
<div style={timerRightSty}>{this.state.progressCount}</div>
</div>
<JProgressBar data={progressData} position='none' />
<div id="title" style={{textAlign: 'center'}}>{title}</div>
<audio
ref="audioDiv"
src={source}
onDurationChange={this.onDurationChange}
onTimeUpdate={this.onTimeUpdate}
onEnded={this.nextSong}
/>
</div>
);
}
}
export default class PlayerCtrl extends PlayerCtrlRender {
constructor() {
super();
this.state = {
playIndex: 0,
queueLength: 1,
isPlaying: false,
progressCount: 0,
progressIndex: 0,
shuffledQueue: [{title: '', location: ''}],
randomOn: false
};
}
componentDidMount = () => {
let queue = knuthShuffle(this.props.queue.slice(0));
this.setState({queueLength: queue.length, shuffledQueue: queue});
this.refs.audioDiv.volume = .1;
};
clickHandler = (buttonid) => {
this.refs.audioDiv.autoplay = false;
switch (buttonid) {
case 'play': this.refs.audioDiv.play(); this.setState({isPlaying: true}); break;
case 'pause': this.refs.audioDiv.pause(); this.setState({isPlaying: false}); break;
case 'back': this.refs.audioDiv.currentTime = 0; break;
case 'next': this.nextSong(); break;
case 'random': this.refs.audioDiv.autoplay = this.state.isPlaying;
this.setState({randomOn: !this.state.randomOn}); break;
}
};
nextSong = () => {
this.refs.audioDiv.autoplay = this.state.isPlaying;
this.refs.audioDiv.currentTime = 0;
let newIndex = this.state.playIndex + 1;
if (newIndex == this.state.queueLength) newIndex = 0;
this.setState({playIndex: newIndex});
};
onDurationChange = () => {
let duration = this.refs.audioDiv.duration;
duration = getTime(Math.floor(duration));
this.setState({progressCount: duration})
this.setState({progressIndex: 0})
};
onTimeUpdate = () => {
let currentTime = this.refs.audioDiv.currentTime;
currentTime = getTime(Math.floor(currentTime));
this.setState({progressIndex: currentTime})
};
}