Get center coordinates of circle sector - javascript

I need to set up <text> element in the center of pie chart segments in an svg <circle>. Right now I use this formula for coordinates:
x(t) = r cos(t) + j
y(t) = r sin(t) + j
where t must be radians. Actually, it works good the first point. But next points are wrong (see code snippet). The question is do I use the wrong formula?
It's my calculations for <text> coordinates
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
//Pie chart plugin
function initPieChart(segmentsData) {
var data = [];
for (var i = 0; i < segmentsData.length; i++) {
var percent = segmentsData[i].getAttribute('data-percent');
var bgcolor = segmentsData[i].getAttribute('data-bg-color');
var textcolor = segmentsData[i].getAttribute('data-text-color');
data.push({"bgcolor": bgcolor, "textcolor": textcolor, "value" : Number(percent)});
}
var angle = -90;
var textAngleOffset = -90;
// Setup global variables
var svg = document.getElementById('pie-chart'),
list = document.getElementById('pie-values'),
totalValue = 0,
radius = 94,
circleLength = Math.PI * (radius * 2), // Circumference = PI * Diameter
spaceLeft = circleLength;
// Get total value of all data.
for (var i = 0; i < data.length; i++) {
totalValue += data[i].value;
}
function degrees_to_radians(degrees){
var pi = Math.PI;
return degrees * (pi/180);
}
function animate(circle, segmentLength, circleLength) {
// circle.setAttribute("stroke-dasharray", spaceLeft + " " + circleLength);
circle.setAttribute("stroke-dasharray", circleLength *segmentLength + " " + circleLength);
}
var segmentOffset = 0;
var animationDelay = 0;
// Loop trough data to create pie
for (var c = 0; c < data.length; c++) {
var segmentLength = data[c].value/100;
var angleOffset = (data[c].value) *360 + angle;
animationDelay = animationDelay + 800;
if(c>0) {
segmentOffset = segmentOffset -data[c-1].value/100*circleLength;
textAngleOffset = (data[c].value/100) *360 + textAngleOffset;
}
// Create circle
var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
// Create group for each segment
var group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.classList.add("segment-group");
//Create text
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
text.setAttribute("text-anchor", "middle");
text.setAttribute("fill", data[c].textcolor);
text.innerHTML = data[c].value + '%';
// Set attributes (self explanatory)
circle.setAttribute("class", "pie-chart-value");
circle.setAttribute("cx", 188.5);
circle.setAttribute("cy", 188.5);
circle.setAttribute("r", radius);
circle.setAttribute("transform", "rotate(" + angleOffset + ", 188.5, 188.5)");
// Set dash on circle
circle.setAttribute("stroke-dasharray", "0" + " " + circleLength);
setTimeout(animate, animationDelay, circle, segmentLength, circleLength);
if(c>0) {
circle.setAttribute("stroke-dashoffset", segmentOffset);
}
// Set Stroke color
circle.style.stroke = data[c].bgcolor;
//Append circle and text to group
group.appendChild(circle);
group.appendChild(text);
// Append group to svg.
svg.appendChild(group);
}
}
//Pie chart call
var chartSegments = document.getElementsByClassName('pie-segment');
initPieChart(chartSegments);
/* Pie chart styles */
.pie-chart-value {
fill: none;
stroke-width: 188.5;
transition: stroke-dasharray 800ms linear;
}
/* */
.time-statistics {
padding-top: 30px;
}
.chart-value {
position: relative;
margin-bottom: 5px;
}
.chart-value:before {
display: none;
}
.chart-value .dot {
width: 8px;
height: 8px;
border-radius: 100%;
margin-right: 10px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.pie-chart-container {
position: relative;
}
.pie-chart-bg {
position: absolute;
top: 0px;
left: 0;
z-index: -1;
}
.pie-chart-content {
position: absolute;
top: 0px;
left: 0px;
}
<div class="pie-chart-container">
<span class="pie-segment" data-percent="20" data-bg-color="#d8d8d8" data-text-color="#123431"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#345a57" data-text-color="white"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#133532" data-text-color="white"></span>
<div class="pie-chart-content">
<svg id="pie-chart" width="377" height="377"></svg>
</div>
</div>

You need to adjust the textoffset for the previous value, not the current one. I.e.:
textAngleOffset = (data[c-1].value/100) *360 + textAngleOffset;
Here is working code:
//Pie chart plugin
function initPieChart(segmentsData) {
var data = [];
for (var i = 0; i < segmentsData.length; i++) {
var percent = segmentsData[i].getAttribute('data-percent');
var bgcolor = segmentsData[i].getAttribute('data-bg-color');
var textcolor = segmentsData[i].getAttribute('data-text-color');
data.push({"bgcolor": bgcolor, "textcolor": textcolor, "value" : Number(percent)});
}
var angle = -90;
var textAngleOffset = -90;
// Setup global variables
var svg = document.getElementById('pie-chart'),
list = document.getElementById('pie-values'),
totalValue = 0,
radius = 94,
circleLength = Math.PI * (radius * 2), // Circumference = PI * Diameter
spaceLeft = circleLength;
// Get total value of all data.
for (var i = 0; i < data.length; i++) {
totalValue += data[i].value;
}
function degrees_to_radians(degrees){
var pi = Math.PI;
return degrees * (pi/180);
}
function animate(circle, segmentLength, circleLength) {
// circle.setAttribute("stroke-dasharray", spaceLeft + " " + circleLength);
circle.setAttribute("stroke-dasharray", circleLength *segmentLength + " " + circleLength);
}
var segmentOffset = 0;
var animationDelay = 0;
// Loop trough data to create pie
for (var c = 0; c < data.length; c++) {
var segmentLength = data[c].value/100;
var angleOffset = (data[c].value) *360 + angle;
animationDelay = animationDelay + 800;
if(c>0) {
segmentOffset = segmentOffset -data[c-1].value/100*circleLength;
textAngleOffset = (data[c-1].value/100) *360 + textAngleOffset;
}
// Create circle
var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
// Create group for each segment
var group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.classList.add("segment-group");
//Create text
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
text.setAttribute("text-anchor", "middle");
text.setAttribute("fill", data[c].textcolor);
text.innerHTML = data[c].value + '%';
// Set attributes (self explanatory)
circle.setAttribute("class", "pie-chart-value");
circle.setAttribute("cx", 188.5);
circle.setAttribute("cy", 188.5);
circle.setAttribute("r", radius);
circle.setAttribute("transform", "rotate(" + angleOffset + ", 188.5, 188.5)");
// Set dash on circle
circle.setAttribute("stroke-dasharray", "0" + " " + circleLength);
setTimeout(animate, animationDelay, circle, segmentLength, circleLength);
if(c>0) {
circle.setAttribute("stroke-dashoffset", segmentOffset);
}
// Set Stroke color
circle.style.stroke = data[c].bgcolor;
//Append circle and text to group
group.appendChild(circle);
group.appendChild(text);
// Append group to svg.
svg.appendChild(group);
}
}
//Pie chart call
var chartSegments = document.getElementsByClassName('pie-segment');
initPieChart(chartSegments);
/* Pie chart styles */
.pie-chart-value {
fill: none;
stroke-width: 188.5;
transition: stroke-dasharray 800ms linear;
}
/* */
.time-statistics {
padding-top: 30px;
}
.chart-value {
position: relative;
margin-bottom: 5px;
}
.chart-value:before {
display: none;
}
.chart-value .dot {
width: 8px;
height: 8px;
border-radius: 100%;
margin-right: 10px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.pie-chart-container {
position: relative;
}
.pie-chart-bg {
position: absolute;
top: 0px;
left: 0;
z-index: -1;
}
.pie-chart-content {
position: absolute;
top: 0px;
left: 0px;
}
<div class="pie-chart-container">
<span class="pie-segment" data-percent="20" data-bg-color="#d8d8d8" data-text-color="#123431"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#345a57" data-text-color="white"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#133532" data-text-color="white"></span>
<div class="pie-chart-content">
<svg id="pie-chart" width="377" height="377"></svg>
</div>
</div>

Related

Not able to get the input text box editable inside animated javascript

I have added the code snippet over here. I was trying to do some random exercise. Can someone look why my textbox is not editable. There is falling leaf animation over here. Along with I have added one textbox on top of it. But currently I am not able to add any text to the textbox.
I am just adding more text in order to overcome the error message that the post is mostly having code and not much explanation.
var LeafScene = function(el) {
this.viewport = el;
this.world = document.createElement('div');
this.leaves = [];
this.options = {
numLeaves: 20,
wind: {
magnitude: 1.2,
maxSpeed: 12,
duration: 300,
start: 0,
speed: 0
},
};
this.width = this.viewport.offsetWidth;
this.height = this.viewport.offsetHeight;
// animation helper
this.timer = 0;
this._resetLeaf = function(leaf) {
// place leaf towards the top left
leaf.x = this.width * 2 - Math.random()*this.width*1.75;
leaf.y = -10;
leaf.z = Math.random()*200;
if (leaf.x > this.width) {
leaf.x = this.width + 10;
leaf.y = Math.random()*this.height/2;
}
// at the start, the leaf can be anywhere
if (this.timer == 0) {
leaf.y = Math.random()*this.height;
}
// Choose axis of rotation.
// If axis is not X, chose a random static x-rotation for greater variability
leaf.rotation.speed = Math.random()*10;
var randomAxis = Math.random();
if (randomAxis > 0.5) {
leaf.rotation.axis = 'X';
} else if (randomAxis > 0.25) {
leaf.rotation.axis = 'Y';
leaf.rotation.x = Math.random()*180 + 90;
} else {
leaf.rotation.axis = 'Z';
leaf.rotation.x = Math.random()*360 - 180;
// looks weird if the rotation is too fast around this axis
leaf.rotation.speed = Math.random()*3;
}
// random speed
leaf.xSpeedVariation = Math.random() * 0.8 - 0.4;
leaf.ySpeed = Math.random() + 1.5;
return leaf;
}
this._updateLeaf = function(leaf) {
var leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);
var xSpeed = leafWindSpeed + leaf.xSpeedVariation;
leaf.x -= xSpeed;
leaf.y += leaf.ySpeed;
leaf.rotation.value += leaf.rotation.speed;
var t = 'translateX( ' + leaf.x + 'px ) translateY( ' + leaf.y + 'px ) translateZ( ' + leaf.z + 'px ) rotate' + leaf.rotation.axis + '( ' + leaf.rotation.value + 'deg )';
if (leaf.rotation.axis !== 'X') {
t += ' rotateX(' + leaf.rotation.x + 'deg)';
}
leaf.el.style.webkitTransform = t;
leaf.el.style.MozTransform = t;
leaf.el.style.oTransform = t;
leaf.el.style.transform = t;
// reset if out of view
if (leaf.x < -10 || leaf.y > this.height + 10) {
this._resetLeaf(leaf);
}
}
this._updateWind = function() {
// wind follows a sine curve: asin(b*time + c) + a
// where a = wind magnitude as a function of leaf position, b = wind.duration, c = offset
// wind duration should be related to wind magnitude, e.g. higher windspeed means longer gust duration
if (this.timer === 0 || this.timer > (this.options.wind.start + this.options.wind.duration)) {
this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
this.options.wind.duration = this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
this.options.wind.start = this.timer;
var screenHeight = this.height;
this.options.wind.speed = function(t, y) {
// should go from full wind speed at the top, to 1/2 speed at the bottom, using leaf Y
var a = this.magnitude/2 * (screenHeight - 2*y/3)/screenHeight;
return a * Math.sin(2*Math.PI/this.duration * t + (3 * Math.PI/2)) + a;
}
}
}
}
LeafScene.prototype.init = function() {
for (var i = 0; i < this.options.numLeaves; i++) {
var leaf = {
el: document.createElement('div'),
x: 0,
y: 0,
z: 0,
rotation: {
axis: 'X',
value: 0,
speed: 0,
x: 0
},
xSpeedVariation: 0,
ySpeed: 0,
path: {
type: 1,
start: 0,
},
image: 1
};
this._resetLeaf(leaf);
this.leaves.push(leaf);
this.world.appendChild(leaf.el);
}
this.world.className = 'leaf-scene';
this.viewport.appendChild(this.world);
// set perspective
this.world.style.webkitPerspective = "400px";
this.world.style.MozPerspective = "400px";
this.world.style.oPerspective = "400px";
this.world.style.perspective = "400px";
// reset window height/width on resize
var self = this;
window.onresize = function(event) {
self.width = self.viewport.offsetWidth;
self.height = self.viewport.offsetHeight;
};
}
LeafScene.prototype.render = function() {
this._updateWind();
for (var i = 0; i < this.leaves.length; i++) {
this._updateLeaf(this.leaves[i]);
}
this.timer++;
requestAnimationFrame(this.render.bind(this));
}
// start up leaf scene
var leafContainer = document.querySelector('.falling-leaves'),
leaves = new LeafScene(leafContainer);
leaves.init();
leaves.render();
body, html {
height: 100%;
}
form {
width: 600px;
margin: 0px auto;
padding: 15px;
}
input[type=text] {
display: block;
padding: 10px;
box-sizing: border-box;
font-size: x-large;
margin-top: 25%;
}
input[type=text] {
width: 100%;
margin-bottom: 15px;
}
.falling-leaves {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 100%;
max-width: 880px;
max-height: 880px; /* image is only 880x880 */
transform: translate(-50%, 0);
border: 20px solid #fff;
border-radius: 50px;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/125707/sidebar-bg.png) no-repeat center center;
background-size: cover;
overflow: hidden;
}
.leaf-scene {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
transform-style: preserve-3d;
}
.leaf-scene div {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/125707/leaf.svg) no-repeat;
background-size: 100%;
transform-style: preserve-3d;
backface-visibility: visible;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style/style.css">
</head>
<body>
<div class="falling-leaves">
<form id="frmContact">
<input type="text" id="txtName" name="txtName" placeholder="Text goes here">
</form>
</div>
<script src="script/script.js"></script>
</body>
</html>

Different scroll speeds for elements in array

I have different randomly-styled stars in an array and I would like them to each have different scroll speeds between -.2 and -.8. The idea is to have them do a parallax effect, and it'd be cool to have everything a little random.
This was the original scroll speed code using images:
var starsOne = document.querySelector("#starsOne");
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + ", " + yPos + "px, 0)";
}
var xScrollPosition;
var yScrollPosition;
function scrollLoop() {
xScrollPosition = window.scrollX;
yScrollPosition = window.scrollY;
setTranslate(0, yScrollPosition * -0.6, starsOne);
requestAnimationFrame(scrollLoop);
}
window.addEventListener("load", scrollLoop, false);
I've been trying to integrate the above code somehow for the array:
let starScrollMin = 2;
let starScrollMax = 8;
var starScrollSpeed = -Math.abs((Math.floor(Math.random() * (starScrollMax - starScrollMin + 1)) + starScrollMin) / 10);
function starScroll() {
for (i = 0; i < starDivvyArr.length; i++) {
yScrollPos = window.scrollY;
starDivvyArr[i].style.transform = "translate3d(" + 0 + "px, " + yScrollPos * starScrollSpeed + "px, 0)";
}
requestAnimationFrame(starScroll);
}
window.addEventListener("load", starScroll, false);
If starScrollSpeed is global, then all the stars move in a big chunk. If it's within the starScroll() function, the values are at least different per star, but it gets crazy as it keeps randomizing and multiplying.
Any ideas on how to randomize the scroll speed for each star so it looks like a parallax effect, without them moving in one single chunk or going crazy? Or is it a safer bet to make a bunch of css lines and then randomly assign classes?
jsfiddle
It's a bit unclear what exactly you're after.
If you're trying to set a random scroll speed for each star, and not change it every time the startScroll triggers.
you could set a speed for each start separately inside the loop and use that in the startScroll function instead:
...
starDivvyArr[i].starScrollSpeed = -Math.abs((Math.floor(Math.random() * (starScrollMax - starScrollMin + 1)) + starScrollMin) / 10);
...
starDivvyArr[i].style.transform = "translate3d(" + 0 + "px, " + yScrollPos * starDivvyArr[i].starScrollSpeed + "px, 0)";
var starCount = 25;
let starContain = document.getElementById('starContain');
/*Create star divs*/
for (var i = 0; i < starCount; i++) {
var starDiv = document.createElement("div");
starDiv.className = 'star';
starContain.append(starDiv);
}
/*Make an array from the star divs*/
var starDivvy = document.querySelectorAll(".star");
var starDivvyArr = Array.from(starDivvy);
/*Create some possible styles*/
var starColor = ['yellow', 'blue', 'white'];
var starSizeMin = 5;
var starSizeMax = 25;
let starContainWidth = starContain.offsetWidth;
let starContainHeight = starContain.offsetHeight;
let starScrollMin = 2;
let starScrollMax = 8;
/*Give the star array some different styles*/
for (i = 0; i < starDivvyArr.length; i++) {
/*Change star color*/
starDivvyArr[i].style.backgroundColor = starColor[Math.floor(Math.random() * starColor.length)];
/*Change star position within container*/
starDivvyArr[i].style.left = Math.floor((Math.random() * starContainWidth) + 1) + "px";
starDivvyArr[i].style.top = Math.floor((Math.random() * starContainHeight) + 1) + "px";
/*Change star size*/
starDivvyArr[i].style.width = Math.floor(Math.random() * (starSizeMax - starSizeMin + 1)) + starSizeMin + "px";
starDivvyArr[i].style.height = starDivvyArr[i].style.width;
starDivvyArr[i].starScrollSpeed = -Math.abs((Math.floor(Math.random() * (starScrollMax - starScrollMin + 1)) + starScrollMin) / 10);
}
/*>>>>>>>POINT OF CONFUSION<<<<<<<*/
/*Randomize scroll speed between -0.2 and -0.8*/
/*Give the stars a scrolling function*/
function starScroll() {
for (i = 0; i < starDivvyArr.length; i++) {
yScrollPos = window.scrollY;
starDivvyArr[i].style.transform = "translate3d(" + 0 + "px, " + yScrollPos * starDivvyArr[i].starScrollSpeed + "px, 0)";
}
requestAnimationFrame(starScroll);
}
window.addEventListener("load", starScroll, false);
*{
margin:0 auto;
}
section{
width:100vw;
height:150vh;
}
.section1{
background-color:#000;
}
.section2{
background-color:#202;
}
h2{
text-align:center;
color:#ccc;
}
#starContain{
width:100vw;
height:500px;
position:absolute;
top:50vh;
z-index:2;
background-color:rgba(255,255,255,0.2);
}
.star{
background-color:green;
position:absolute;
z-index:100;
border-radius:50%;
}
<main>
<section class="section1">
<h2>
Section 1
</h2>
</section>
<div id="starContain">
</div>
<section class="section2">
<h2>
Section 2
</h2>
</section>
</main>
You could create an array for the randomly created numbers and push a value from a function that returns the randomly created speed into that array with in the loop and then use that array to get a random value for each element.
var starCount = 25;
let starContain = document.getElementById('starContain');
/*Create star divs*/
for (var i = 0; i < starCount; i++) {
var starDiv = document.createElement("div");
starDiv.className = 'star';
starContain.append(starDiv);
}
/*Make an array from the star divs*/
var starDivvy = document.querySelectorAll(".star");
var starDivvyArr = Array.from(starDivvy);
/*Create some possible styles*/
var starColor = ['yellow', 'blue', 'white'];
var starSizeMin = 5;
var starSizeMax = 25;
let starContainWidth = starContain.offsetWidth;
let starContainHeight = starContain.offsetHeight;
/*Give the star array some different styles*/
for (i = 0; i < starDivvyArr.length; i++) {
/*Change star color*/
starDivvyArr[i].style.backgroundColor = starColor[Math.floor(Math.random() * starColor.length)];
/*Change star position within container*/
starDivvyArr[i].style.left = Math.floor((Math.random() * starContainWidth) + 1) + "px";
starDivvyArr[i].style.top = Math.floor((Math.random() * starContainHeight) + 1) + "px";
/*Change star size*/
starDivvyArr[i].style.width = Math.floor(Math.random() * (starSizeMax - starSizeMin + 1)) + starSizeMin + "px";
starDivvyArr[i].style.height = starDivvyArr[i].style.width;
}
/*>>>>>>>POINT OF CONFUSION<<<<<<<*/
/*Randomize scroll speed between -0.2 and -0.8*/
let starScrollMin = 2;
let starScrollMax = 8;
//function for creating random scroll speed
const starScrollSpeed = (min,max) => {
return -Math.abs((Math.floor(Math.random() * (min - max + 1)) + min) / 10);
}
//==> added array
const starArray = [];
/*Give the stars a scrolling function*/
function starScroll() {
for (i = 0; i < starDivvyArr.length; i++) {
// array to hold randomly created scroll speeds
starArray.push(starScrollSpeed(starScrollMin,starScrollMax))
yScrollPos = window.scrollY;
starDivvyArr[i].style.transform = "translate3d(" + 0 + "px, " + yScrollPos * starArray[i] + "px, 0)";
}
requestAnimationFrame(starScroll);
}
window.addEventListener("load", starScroll, false);
* {
margin: 0 auto;
}
section {
width: 100vw;
height: 150vh;
}
.section1 {
background-color: #000;
}
.section2 {
background-color: #202;
}
h2 {
text-align: center;
color: #ccc;
}
#starContain {
width: 100vw;
height: 500px;
position: absolute;
top: 50vh;
z-index: 2;
background-color: rgba(255, 255, 255, 0.2);
}
.star {
background-color: green;
position: absolute;
z-index: 100;
border-radius: 50%;
}
<main>
<section class="section1">
<h2>
Section 1
</h2>
</section>
<div id="starContain">
</div>
<section class="section2">
<h2>
Section 2
</h2>
</section>
</main>

How to rotate point and place in the center?

I have tried to rotate point in case when parent container was rotated:
https://stackblitz.com/edit/js-qzfdbb?file=index.js
Code is:
var elParent = document.getElementById('parent');
var elCircle = document.getElementById('circle');
elCircle.addEventListener('click', function(e) {
const circleSvg = document.getElementById('circle');
const circleSvgRect = circleSvg.getBoundingClientRect();
const parentRect = document.getElementById('parent').getBoundingClientRect();
let leftTopX = circleSvgRect.left - parentRect.left;
let leftTopY = circleSvgRect.top - parentRect.top;
leftTopX = leftTopX + 15 - 5;
leftTopY = leftTopY + 15 - 5;
var degree = (20 * Math.PI) / 180;
var xc = 250;
var yc = 250;
leftTopX =
(leftTopX - xc) * Math.cos(degree) -
(leftTopY - yc) * Math.sin(degree) +
xc;
leftTopY =
(leftTopX - xc) * Math.sin(degree) +
(leftTopY - yc) * Math.cos(degree) +
yc;
let c = document.getElementById('c');
if (c) c.remove();
c = document.createElement('div');
c.setAttribute('id', 'c');
c.style.setProperty('left', leftTopX + 'px');
c.style.setProperty('top', leftTopY + 'px');
elParent.appendChild(c);
});
To see result make click inside red circle. Withour rotation a green circle is placed in the center of red circle. Otherwise has offset.
the maths should be something like this, but the solution needs some additional calculations for the rotation of the red circle itself within the outer rectangle.
Note 1: The margin of the body is removed for simplicity...
Note 2: Scrolls effect the script a lot. Therefore the solution also may not be very useful without taking it into consideration...
var elParent = document.getElementById('parent');
var elCircle = document.getElementById('circle');
elCircle.addEventListener('click', function(e) {
const circleSvg = document.getElementById('circle');
const circleSvgRect = circleSvg.getBoundingClientRect();
const parentRect = document.getElementById('parent').getBoundingClientRect();
const degree = getCurrentRotation(document.getElementById('parent'));
const xcenter = parentRect.width / 2 + parentRect.left;
const ycenter = parentRect.height / 2 + parentRect.top;
const dx = (circleSvgRect.left + 10) - xcenter;
const dy = ycenter - (circleSvgRect.top + 10);
console.log(dx + ' - ' + dy + '-' + Math.atan(dy / dx));
const r = Math.sqrt(dx * dx + dy * dy);
const curDegree = Math.atan(dy / dx) + degree;
xnew = xcenter + Math.sign(-dx) * Math.sin(curDegree) * r;
ynew = ycenter - Math.sign(-dx) * Math.cos(curDegree) * r;
let c = document.getElementById('c');
if (c) c.remove();
c = document.createElement('div');
c.setAttribute('id', 'c');
c.style.setProperty('left', xnew + 'px');
c.style.setProperty('top', ynew + 'px');
elParent.appendChild(c);
});
//https://stackoverflow.com/questions/19574171/how-to-get-css-transform-rotation-value-in-degrees-with-javascript
function getCurrentRotation(el) {
var st = window.getComputedStyle(el, null);
var tm =
st.getPropertyValue('-webkit-transform') ||
st.getPropertyValue('-moz-transform') ||
st.getPropertyValue('-ms-transform') ||
st.getPropertyValue('-o-transform') ||
st.getPropertyValue('transform') ||
'none';
if (tm != 'none') {
var values = tm
.split('(')[1]
.split(')')[0]
.split(',');
return (angle = Math.atan2(values[1], values[0]));
}
return 0;
}
<div id="parent">
<div id="circle" style="left: 100px; top: 100px"></div>
</div>
<style>
body {
margin:0px;
padding:0px;
}
#circle {
width: 30px;
height: 30px;
border-radius: 50%;
background: red;
position: relative;
}
#c {
position: absolute;
width: 10px;
height: 10px;
background: green;
border-radius: 50%;
}
#parent {
width: 500px;
position: relative;
height: 500px;
border: 1px solid #ccc;
transform: rotate(180deg);
}
</style>

How to link audio file and autoplay

I have an audio visualizer that creates audio waves based on the inputed music file. The file has to manually be put into the "choose file" area. How do I make it so that I can simply link a pr-existing file, so that when the page loads, it immediately starts playing audio.mp3
Here is the code that Im working with:
window.onload = function() {
var audio,
analyser,
audioContext,
sourceNode,
stream;
var svg = document.getElementById('svg'),
svgNS = svg.namespaceURI,
g = document.createElementNS(svgNS, "g");
var width = window.innerWidth,
height = window.innerHeight,
maxHeight = Math.max(height * 0.3, 300),
fftSize = 512, // 512
tilt = 40,
choke = 110,
c = 0;
var audioInput = document.getElementById('audiofile');
// choose file
audioInput.addEventListener('change', function(event) {
stream = URL.createObjectURL(event.target.files[0]);
audio = new Audio();
audio.src = stream;
setup();
});
function setup() {
audio.addEventListener('canplay', function () {
document.body.className+='loaded';
audioContext = new AudioContext();
analyser = (analyser || audioContext.createAnalyser());
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 1;//0.75;
analyser.fftSize = fftSize;
sourceNode = audioContext.createMediaElementSource(audio);
sourceNode.connect(analyser);
sourceNode.connect(audioContext.destination);
audio.play();
update();
});
}
function shape(g, freqValue, freqSequence, freqCount, colorSequence) {
var freqRatio = freqSequence/freqCount,
x = (width - (tilt * 2)) * freqRatio + tilt,
y = height / 2;
var polyline = document.createElementNS(svgNS, "polyline"),
// using power to increase highs and decrease lows
freqRatio = freqValue / 255,
throttledRatio = (freqValue - choke) / (255 - choke),
strokeWidth = width / freqCount * 0.6 * throttledRatio,
throttledY = Math.max(throttledRatio, 0) * maxHeight,
// color
color = "hsl(" +
((freqSequence / 2) + Math.floor(colorSequence)) + ", " +
100 + "%," +
freqRatio * 80 + "%" +
")";
var loc_x = x - strokeWidth / 2,
loc_y1 = y - throttledY / 2,
loc_y2 = y + throttledY / 2,
x_offset = tilt * throttledRatio;
if (throttledRatio > 0) {
var point_1 = (loc_x - x_offset) + "," + loc_y1,
point_2 = (loc_x + x_offset) + "," + loc_y2;
var points = [ point_1, point_2 ];
} else {
var points = [loc_x + "," + (y-1),loc_x + "," + (y+1)]
}
polyline.setAttribute("stroke-width", strokeWidth);
polyline.setAttribute("stroke", color);
polyline.setAttribute("points", points.join(" "));
g.appendChild(polyline);
}
svg.setAttribute("width", width+"px");
svg.setAttribute("height", height+"px");
svg.setAttribute("viewBox", "0 0 " + width + " " + height);
svg.appendChild(g);
function update() {
g.remove();
g = document.createElementNS(svgNS, "g");
var freqArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(freqArray);
for (var i = 0; i < freqArray.length; i++) {
var v = freqArray[i];
shape(g, v, i+1, freqArray.length, c);
}
svg.appendChild(g);
c += 0.5;
requestAnimationFrame(update);
}
};
jakealbaughSignature("light");
body {
margin: 0;
background-color: #000000;
font-family: 'Helvetica', sans-serif;
color: #FFFFFF;
}
input {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
z-index: 2;
}
body.loaded input {
display: none;
}
#svg {
display: block;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
}
#svg polyline {
stroke-linecap: round;
}
<input id=audiofile type=file>
<svg id=svg></svg>
You can't.
Autoplay of audio is disabled on most browsers. There must be some user interaction, and you can only start playback on that user interaction, such as a click event.

Random Keyframe Positions Every Iteration to Create Falling "Matrix Code"

I'm attempting to make an HTML web page with animated CSS classes on many independent DIVs moving to their own randomly generated positions. I have 20 elements with randomly generated characters falling from the top of the page and dissipating as they move along their y-axis (like the Matrix code).
EDIT: JsFiddle Demo Remember the range is wide, so sometimes the group of characters generate far off to the right (outside the small viewing window)
Generating random char in top JavaScript
<script type="text/javascript">
$(document).ready(function() {
});
function generateChar()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789«‘¥~‹÷´`≠¡ˆ()][¶##…•–!£$%&/?^*駰ç_:è+òàù,.-";
text = possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
</script>
HTML of 20 divs
<div id="m1 " class="timeSpan movement"></div>
...
<div id="m20" class="timeSpan movement"></div>
JavaScript: Here I've randomly generated characters (successfully) but only 1 random position. All the elements start in the same position instead of starting from their own spots.
<script type="text/javascript">
document.getElementById("m1 ").innerHTML = generateChar();
...
document.getElementById("m20").innerHTML = generateChar();
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++){
var xRandom = Math.round(Math.random() * 2000);
var yBegRan = Math.round(Math.random() * 150);
var yEndRan = Math.round(Math.random() * (2000 - 650) + 650);
var secRan = Math.round(Math.random() * (20));
var style = document.documentElement.appendChild(document.createElement("style")),
rule = " moveMinus {\
0% {\
opacity: 1;\
}\
100% {\
opacity: 0; \
}\
from {\
top: " + yBegRan + "px; left: " + xRandom + "px;\
}\
to {\
top: " + yEndRan + "px; left: " + xRandom + "px;\
}\
}";
if (CSSRule.KEYFRAMES_RULE) {
style.sheet.insertRule("#keyframes" + rule, 0);
} else if (CSSRule.WEBKIT_KEYFRAMES_RULE) {
style.sheet.insertRule("#-webkit-keyframes" + rule, 0);
}
divs[i].innerHTML = makeid();
}
</script>
CSS
.body-m{
background-color: black;
overflow: hidden;
}
.movement{
position: absolute;
font-size: 20px;
color: limegreen;
background-color: transparent;
overflow: hidden;
}
#keyframes moveMinus {
from { top: 0px; left: 21px; }
to { top: 600px; left: 21px; }
0% { opacity: 1; }
100% { opacity: 0; }
}
.timeSpan{
animation: moveMinus 7s infinite;
}
How do I properly iterate through the DIVs' styles?
Hi I just made this fiddle, Fiddle, I'm not sure that's what you wanted but I get a result that you can easily edit =)
Here is the main function :
function setDiv(_div){
var xRandom = Math.round(Math.random() * 2000);
var yBegRan = Math.round(Math.random() * 600);
var yEndRan = Math.round(Math.random() * (2000 - 650) + 650);
var secRan = Math.round(Math.random() * (20)) + 10;
_div.style.opacity = 1;
_div.style.top = yBegRan +"px";
_div.style.animationDuration = secRan +"s";
_div.style.left = xRandom + "px";
_div.innerHTML = generateChar();
}
function generateChar() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789«‘¥~‹÷´`≠¡ˆ()][¶##…•–!£$%&/?^*駰ç_:è+òàù,.-";
text = possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
var len = 500;
var style = document.createElement("style");
document.body.appendChild(style);
for (var i = 0; i < len; i++) {
var xRandom = Math.round(Math.random() * 2000);
var yBegRan = Math.round(Math.random() * 150);
var yEndRan = Math.round(Math.random() * (2000 - 650) + 650);
var secRan = Math.round(Math.random() * (20));
var rule = " moveMinus" + i +" {"
+ "0%{opacity: 1;top:"
+ yBegRan + "px; left:"
+ xRandom + "px;"
+ "}"
+ "100% {"
+ "opacity: 0;top:"
+ yEndRan + "px; left:"
+ xRandom + "px;"
+ "}}";
var div = document.createElement("div");
div.style.position = "absolute";
div.style.left = (Math.random() * window.innerWidth) + "px";
div.className = "timeSpan" + i;
div.innerHTML = generateChar();
if (!("webkitAnimation" in document.body.style)) {
style.textContent += "." + div.className
+"{animation:moveMinus"+i+" "+Math.random() * 7
+"s infinite;}\n" +"#keyframes" + rule;
} else {
style.textContent += "." + div.className
+"{-webkit-animation:moveMinus"+i+" "+Math.random() * 7
+"s infinite;}\n"
+"#-webkit-keyframes" + rule;
};
document.body.appendChild(div)
}
.body-m {
background-color: black;
overflow: hidden;
}
/*Base Class*/
.movement {
position: absolute;
font-size: 20px;
color: limegreen;
background-color: transparent;
overflow: hidden;
}
div {
color:lime;
}
<body class="body-m"></body>
jsfiddle http://jsfiddle.net/yLzkvb9e/2/

Categories

Resources