Linear animation with multiple x,y coordinates - javascript

The below code is doing the animation from 2 points , Point (0,0) to Point (100,50) , which is working fine . But i need a function that takes an array of x,y coordinates and keep on running the same below script to draw path one by one . How can this be achieved .
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chain</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.js" integrity="sha512-XV5MGZ7Tv+G60rzU8P7tPUlaf0yz7SJ/ uI9CLAwyLcZKl9kzxJQFs3nsBNZVNVAwNOkBLqrzMvjGMEycDccqiA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script type="text/paperscript" canvas="canvas">
var path = new Path();
path.strokeColor = 'white';
path.add(new Point(0, 0));
path.add(new Point(100, 50));
var time = 0;
// On each frame...
function onFrame() {
console.log('Running frame ');
if (time <= 1) {
time += 0.01;
drawTmpPath(time);
}
}
var tmpPath;
function drawTmpPath(t) {
// Make sure that t is never over 1.
t = Math.min(t, 1);
// Remove the previously drawn temporary path.
if (tmpPath) {
tmpPath.remove();
}
// Draw the new temporary path from the reference one.
tmpPath = path.clone().set({
selected: false,
strokeColor: 'orange',
strokeWidth: 5
});
// Split it at the appropriate location.
var remainingPath = tmpPath.splitAt(tmpPath.length * t);
// Remove the eventual remaining part.
if (remainingPath) {
remainingPath.remove();
}
}
</script>
</head>
<body>
<canvas id="canvas" resize></canvas>
</body>
</html>

Related

Object Detection and Recognition in JS

I wanted to develop object detection system using ml5 & p5.js,where I can upload an image and system can provide me an output image with Rectangle around objects in image. Yolo and Cocossd datasets are working fine for recognition an object in image.
Like this image object is being identified:
But these datasets are not giving me results for detection where there is text or object with text. As I am expecting system to identify each word of text as different object, like for below image :
Result should be like this:
Rectangle around K
Rectangle around F
Rectangle around C
and one Rectangle around logo of KFC
Please help regarding this or suggest any other system which i can use in PHP/Js to detect objects in image.
let img;
let detector;
function preload(){
img = loadImage('e.jpeg');
detector = ml5.objectDetector('yolo');
}
function setup() {
createCanvas(800, 800);
image(img,0,0);
detector.detect(img,gotDetections);
}
function gotDetections(error, result){
if(error){
console.log(error)
}
console.log(result)
drawResults(result);
// for (let i = 0 ; i< result.length; i++){
// let object = result[i];
// stroke(0,255,255);
// strokeWeight(4);
// noFill();
// rect(object.x ,object.y,object.width,object.height);
// }
}
function drawResults(results) {
results.forEach((result) => {
// Generates a random color for each object
const r = Math.random()*256|0;
const g = Math.random()*256|0;
const b = Math.random()*256|0;
// Draw the text
stroke(0, 0, 0);
strokeWeight(2);
textSize(16);
fill(r, g, b);
text(`${result.label} (${result.confidence.toFixed(2)}%)`, result.x, result.y - 10);
// Draw the rectangle stroke
noFill();
strokeWeight(3);
stroke(r, g, b);
rect(result.x, result.y, result.width, result.height);
});
};
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<script src="https://unpkg.com/ml5#latest/dist/ml5.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>

How to shift an array of posenet points?

I'm a beginner at using p5.js but I'm currently currently attempting to create a brush sketch like this
ellipse brush
though using computer vision & posenet nose tracking (essentially a nose brush)
The problem is, while it doesn't state any errors, it doesn't work.
This is my code for the ellipse brush without posenet & camera vision
let mousePosition = [];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(0);
//Every frame of animation
//storing the mouse position in an array
mousePosition.push({x: mouseX, y: mouseY});
//shift the array so that the older ones deletes itself
if(mousePosition.length > 100) mousePosition.shift();
//loop
for(let i = 0; i < mousePosition.length; i++) {
//if the variable is less than 50, loop function
let x = mousePosition[i].x;
let y = mousePosition[i].y;
ellipse(x, y, r,r);
var r = 20
}
}
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/addons/p5.dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
and this is the one with computer vision & nose tracking w/ posenet
let capture;
let poseNet;
let pose;
let text;
let pg;
let nosePosition = []
function setup() {
createCanvas(700, 700);
capture = createCapture(VIDEO);
capture.hide();
pg = createGraphics(width, height);
poseNet = ml5.poseNet(capture, modelLoaded);
poseNet.on('pose', gotPoses);
// background(255)
// color picker
}
function gotPoses(poses) {
//console.log(poses);
if (poses.length > 0) {
pose = poses[0].pose;
}
}
function modelLoaded() {
console.log('poseNet.ready');
}
function draw() {
translate(width, 0); // move to far corner
scale(-1.0, 1.0); // flip x-axis backwards
image(capture, 0, 0, width, width * capture.height /
capture.width);
image(pg, 0, 0, width, height);
if (pose) {
nosePosition.push({x:pose.nose.x ,y: pose.nose.y});
if(nosePosition.length > 100) nosePosition.shift(); {
}
for(let i = 0; i < nosePosition.length; i++) {
//if the variable is less than 50, loop function
let x = nosePosition[i].x;
let y = nosePosition[i].y;
pg.ellipse(x, y, i/5,i/5);
var r = 20 //how big the ellipse is
pg.fill(255)
pg.noStroke();
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/addons/p5.sound.min.js"></script>
<script src="https://unpkg.com/ml5#latest/dist/ml5.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
The second is essentially very similar to the first, as I've only changed the mouseX/Ys into the posenet Nose keypoint.
Any insight/solution would be highly appreciated!
Thank you :)
You're shifting properly, but you forgot to clear the pg graphic, which is kind of like forgetting to put background(0) in your original sketch. So instead of drawing all the ellipses on a blank background, you're drawing them on top of the previous frame.
Adding pg.clear() anywhere in draw() after you display pg on the canvas (image(pg, ...)) and before you draw the ellipses (for (...) {... ellipse(nosePosition[i].x...)}) should do the trick. Here's where I put it:
image(pg, 0, 0, width, height);
pg.clear();//HERE
if (pose) {//...

why this functions can't be found outside the setInterval loop? (javascript)

I'm using planetaryjs package to draw a globe in js.
There's a function planetary.plugins.pings.add. It works when it's in this loop:
setInterval(function() {
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
}, 200);
But I only want to draw one ping, so I did
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
But firefox tells me
TypeError: globe.plugins.pings is undefined
Does somebody know why is this? Complete code is here (see line 67-77). Source is here
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type='text/javascript' src='http://d3js.org/d3.v3.min.js'></script>
<script type='text/javascript' src="http://d3js.org/topojson.v1.min.js"></script>
<script type='text/javascript' src="http://labs.rivendellweb.net/data-vis/planetary/planetaryjs.js"></script>
</head>
<body>
<canvas id='rotatingGlobe' width='800' height='600' style='width: 800px; height: 600px; cursor: move;'></canvas>
<script>
(function() {
var globe = planetaryjs.planet();
// Load our custom `autorotate` plugin; see below.
globe.loadPlugin(autorotate(0));
// The `earth` plugin draws the oceans and the land; it's actually
// a combination of several separate built-in plugins.
// Note that we're loading a special TopoJSON file
// (world-110m-withlakes.json) so we can render lakes.
globe.loadPlugin(planetaryjs.plugins.earth({
topojson: { file: 'world-110m-withlakes.json' },
oceans: { fill: '#000080' },
land: { fill: '#339966' },
borders: { stroke: '#008000' }
}));
// Load our custom `lakes` plugin to draw lakes; see below.
globe.loadPlugin(lakes({
fill: '#000080'
}));
// The `pings` plugin draws animated pings on the globe.
globe.loadPlugin(planetaryjs.plugins.pings());
// The `zoom` and `drag` plugins enable
// manipulating the globe with the mouse.
globe.loadPlugin(planetaryjs.plugins.zoom({
scaleExtent: [100, 2000]
}));
globe.loadPlugin(planetaryjs.plugins.drag({
// Dragging the globe should pause the
// automatic rotation until we release the mouse.
onDragStart: function() {
this.plugins.autorotate.pause();
},
onDragEnd: function() {
this.plugins.autorotate.resume();
}
}));
// Set up the globe's initial scale, offset, and rotation.
globe.projection
.scale(400)
.translate([400, 300])
.rotate([-100, -30, 0]);
// Every few hundred milliseconds, we'll draw another random ping.
//var colors = ['red', 'yellow', 'white', 'orange', 'green', 'cyan', 'pink'];
setInterval(function() {
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
}, 200);
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
var canvas = document.getElementById('rotatingGlobe');
// Special code to handle high-density displays (e.g. retina, some phones)
// In the future, Planetary.js will handle this by itself (or via a plugin).
if (window.devicePixelRatio == 2) {
canvas.width = 800;
canvas.height = 800;
context = canvas.getContext('2d');
context.scale(2, 2);
}
// Draw that globe!
globe.draw(canvas);
// This plugin will automatically rotate the globe around its vertical
// axis a configured number of degrees every second.
function autorotate(degPerSec) {
// Planetary.js plugins are functions that take a `planet` instance
// as an argument...
return function(planet) {
var lastTick = null;
var paused = false;
planet.plugins.autorotate = {
pause: function() { paused = true; },
resume: function() { paused = false; }
};
// ...and configure hooks into certain pieces of its lifecycle.
planet.onDraw(function() {
if (paused || !lastTick) {
lastTick = new Date();
} else {
var now = new Date();
var delta = now - lastTick;
// This plugin uses the built-in projection (provided by D3)
// to rotate the globe each time we draw it.
var rotation = planet.projection.rotate();
rotation[0] += degPerSec * delta / 1000;
if (rotation[0] >= 180) rotation[0] -= 360;
planet.projection.rotate(rotation);
lastTick = now;
}
});
};
};
// This plugin takes lake data from the special
// TopoJSON we're loading and draws them on the map.
function lakes(options) {
options = options || {};
var lakes = null;
return function(planet) {
planet.onInit(function() {
// We can access the data loaded from the TopoJSON plugin
// on its namespace on `planet.plugins`. We're loading a custom
// TopoJSON file with an object called "ne_110m_lakes".
var world = planet.plugins.topojson.world;
lakes = topojson.feature(world, world.objects.ne_110m_lakes);
});
planet.onDraw(function() {
planet.withSavedContext(function(context) {
context.beginPath();
planet.path.context(context)(lakes);
context.fillStyle = options.fill || 'black';
context.fill();
});
});
};
};
})();
</script>
</body>
</html>
Replace setInterval by setTimeout.
The reason your direct call fails is because globe.plugins.pings is not initialized till after globe.draw(canvas); is called. You could also move it to after this.
When compared to replacing it by the code block, setTimeout moves the execution of the code block to the end of the execution queue i.e. till after globe.draw(canvas); is called and globe.plugins.pings is initialized - but unlike setInterval, it runs only once.
it would be better to use some sort of callback rather than just replying on a random timeout.
Something like this.
planet.onInit( function([done]){} )
The DOM is not initialized at the point of execution, you should wrap the initialization in document.addEventListener('DOMContentLoaded', function () { /* your code here */ });

Dynamically add SVG circle in a SVG group?

I am using SnapSVG library. I am trying to add a dynamically created SVG circle into a SVG group. A new circle is added every time I click a link (Add Composite). Then I try to push that newly created circle to an array and pass the array to the group (drag) function. I basically want to drag all the circles and rectangle as a group. But its not working. Here is my code ...
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.1.4" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="snap.svg-min.js"></script>
</head>
<body>
<svg id="svg"></svg>
<div id="addComp">Add Composite</div>
<script>
// JavaScript Document
(function() {
var s = Snap("#svg");
// Construct Composite
function composite(y, i) {
var CirArray = [];
$("svg g").remove();
$("svg rect").remove();
$("svg circle").remove();
var square = s.rect(30, 40, y, 40);
console.log("Square:" + y);
square.attr({
fill: 'lightblue',
stroke: 'lightblue',
//strokeOpacity: .3,
//strokeWidth: 10
});
CirArray.push(square);
var k = 0;
for (z = 1; z <= i; z++) {
k = k + 45;
console.log("Circle:" + k);
var mycircle = s.circle(k, 120, 20);
mycircle.attr({
fill: 'coral',
stroke: 'coral',
strokeOpacity: .3,
strokeWidth: 10
});
CirArray.push(mycircle);
} // For loop end
drag.apply(null, CirArray);
} // Construct Composite End
// Group
function drag(CirArray) {
var tableset = s.group(CirArray);
for (p = 0; p < CirArray.length; p++) {
console.log(CirArray[p])
}
console.log(CirArray.length)
// Drag
var move = function(dx, dy) {
this.attr({
transform: this.data('origTransform') + (this.data('origTransform') ? "T" : "t") + [dx, dy]
});
}
var start = function() {
this.data('origTransform', this.transform().local);
}
var stop = function() {
console.log('finished dragging');
}
tableset.drag(move, start, stop);
} //Drag End
// Add Composite
var x = 0;
var clct = 0;
$("#addComp").click(function() {
x = x + 45;
clct = clct + 1;
composite(x, clct);
}); // Add Composite End
}()); // Iffe End
</script>
</body>
</html>
Visit this site and click on 'Add composite' link a couple of times to see it in action
Any help is very appreciated ....
Thanks
Basically adding the array on the .group(CirArray) does not seem to add all the array items into a group (Inspect the SVG output) the group tag is empty.
Instead adding them in the for-loop below. Made the following changes and it seems to work as expected and moving all squares and circles together.
var tableset = s.group();
for (p = 0; p < CirArray.length; p++) {
tableset.add(CirArray[p]);
console.log(CirArray[p])
}
In the drag function also calling it simply drag(cirArray) (as suggested by #Paul-lebeau ie. drag(CirArray);).
Forked Plunker
The second argument to the function.apply() method is supposed to be an array of parameters.
But you are passing in an array of Snap elements. So in your drag() function, the CirArray parameter is getting set to the first element of your original CirArray, not the whole array.
Either change the call to
drag.apply(null, [CirArray]);
or just call it normally
drag(CirArray);

Draw HTML5 Canvas pulse line

Hey guys I've been trying to wrap my head around the HTML5 Canvas animation but failed miserably I wanted to achieve the below figure by animating this custom shape in an interval of 10 seconds.
I've pretty much screwed the math of it so I ended up just writing every lineTo statement manually, tried Paul Irish's requestAnimationFrame at the end to animate the line but no luck.
Any help would be highly appreciated, here is
thelive demo
Thanks guys
It's not moving cause you are basically not moving anything - the same shape is drawn to the same position each iteration.
Here is a modified version which animates the pulse to the left (adjust dlt to change speed):
Modified fiddle here
var segX = canvas.width / 6;
var segY = canvas.height / 2;
function draw() {
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(0, segY);
for(var i = dlt, h = true; i < canvas.width + segX; i += segX) {
if (h) {
ctx.lineTo(i, segY);
ctx.lineTo(i, segY + segX);
} else {
ctx.lineTo(i, segY + segX);
ctx.lineTo(i, segY);
}
h = !h;
}
ctx.stroke();
dlt--;
if (dlt < -segX * 2) dlt = 0;
requestAnimFrame(draw);
}
You're basically needing a function that returns only 2 values--high and low.
Here's a function that returns only low/high values based on a period and oscillation values:
// squared wave
// p = period (how long it takes the wave to fully complete and begin a new cycle)
// o = oscillation (change in wave height)
function squareY(x) {
return( (x%p)<o?o:0 );
}
Demo: http://jsfiddle.net/m1erickson/A69ZV/
Example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineWidth=3;
var p=30; // period
var o=15; // oscillation
var fps = 60;
var n=0;
animate();
function animate() {
setTimeout(function() {
requestAnimationFrame(animate);
// Drawing code goes here
n+=1.5;
if(n>300){
n=0;
}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
for(var x=0;x<n;x++){
var y=squareY(x);
ctx.lineTo(x,y+50);
}
ctx.stroke();
}, 1000 / fps);
}
// squared sine
function squareY(x) {
return( (x%p)<o?o:0 );
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>

Categories