I have such a problem:
I have an array of data, and I have an array of time.
These are the arrays:
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
After a second I want to display the number 60, after 2.5 seconds the number 85, and so these ...
This is the code I've been trying to do so far, but it's not working for me
import React from "react";
function App() {
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
const scoreValue = (time, score) => {
time.forEach((timePoint, i) => {
setInterval(() => {
<p>{score[i]}</p>
}, timePoint * 1000);
});
}
return (
<div className="App">
{scoreValue(Reps.TimeOfMove, Reps.ScoreOfMove)}
</div>
);
}
export default App;
I want to display different text each time, according to the time it appears.
Try to create a state (currentScore) and set the value to it on interval, This is done by the forEach loop and setInterval.
import React, { useState } from "react";
function App() {
const [currentScore, setCurrentStore] = useState(null);
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
useEffect(() => {
Reps.TimeOfMove.forEach((time, index) => {
setTimeout(() => {
setCurrentStore(Reps.ScoreOfMove[index])
}, time * 1000)
})
},[])
return (
<div className="App">
<p>{currentScore}</p>
</div>
);
}
export default App;
This should work.
import React, {useEffect, useState} from 'react';
import './App.css';
function App() {
const [score, setScore] = useState('');
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
useEffect(() => {
Reps.TimeOfMove.forEach((time, index) => {
const interval = setInterval(() => setScore(Reps.ScoreOfMove[index]), time * 1000);
return () => {
clearInterval(interval);
};
})
}, [])
return (
<div>
{score}
</div>
);
}
export default App;
here a solution in Vanilla JS, you can apply in React or where you want
This is a recursive solution.
const arrs = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
}
const runTimer = (index) => {
if (index === arrs.TimeOfMove.length - 1) {
console.log('Timer is finished!')
return;
}
setTimeout(() => {
console.log(arrs.ScoreOfMove[index]);
runTimer(index + 1);
}, arrs.TimeOfMove[index] * 1000)
}
const INDEX_START = 0;
runTimer(INDEX_START);
Aditional, share codepen
https://codepen.io/niko20/pen/MWpryRB
if you want show text "score of move" in DOM can use useState of ReactJS and set score when timer run.
Related
I've successfully generated the pattern in the picture. Now i need to figure out how i can do it automatically. Basically every second square needs to be mirrored.
If there's an easier way to do this i'm happy to take suggestions.
image
This is how my code looks:
// For widthSegments
for (let x = 0; x < world.plane.widthSegments; x++){
for (let y = 0; y < world.plane.heightSegments; y++){
vertices.push(x, y, 0) // 0, 4, 8, 12, 16, 20, 24, 28, 32,
vertices.push(x+1, y, 0) // 1, 5, 9, 13, 17, 21, 25, 29, 33,
vertices.push(x+1, y+1, 0) // 2, 6, 10, 14, 18, 22, 26, 30, 34,
vertices.push(x, y+1, 0) // 3, 7, 11, 15, 19, 23, 27, 31, 35,
}
}
planeMesh.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3))
planeMesh.geometry.setIndex([ // I want to generate these automatically
0, 1, 3, 3, 1, 2, // 1
2, 6, 3, 3, 6, 7, // 2
7, 6, 11, 11, 6, 10, // 3
10, 14, 11, 11, 14, 15, // 4
1, 17, 18, 18, 2, 1, // 5
2, 18, 6, 6, 18, 22, // 6
6, 22, 26, 26, 10, 6, // 7
10, 26, 14, 14, 26, 30, // 4
17, 33, 18, 18, 33, 34, // 9
18, 34, 38, 38, 22, 18, // 10
22, 38, 26, 26, 38, 42, // 11
26, 42, 46, 46, 30, 26, // 4
33, 49, 50, 50, 34, 33, // 13
34, 50, 38, 38, 50, 54, // 14
38, 54, 58, 58, 42, 38, // 15
42, 58, 46, 46, 58, 62, // 16
]);
You can take PlaneGeometry and re-calculate its index.
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
60,
innerWidth / innerHeight,
0.1,
100
);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", (event) => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
let controls = new OrbitControls(camera, renderer.domElement);
let g = new THREE.PlaneGeometry(10, 10, 10, 10);
recalcIndex(g);
let m = new THREE.MeshBasicMaterial({ color: "aqua", wireframe: true });
let o = new THREE.Mesh(g, m);
scene.add(o);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
function recalcIndex(plane) {
let w = plane.parameters.widthSegments;
let h = plane.parameters.heightSegments;
let idx = [];
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let a = x + ((w + 1) * y);
let b = x + ((w + 1) * (y + 1));
let c = (x + 1) + ((w + 1) * (y + 1));
let d = (x + 1) + ((w + 1) * y);
if ((x + (y % 2)) % 2 == 0) {
idx.push(a, b, d, b, c, d);
} else {
idx.push(b, c, a, c, d, a);
}
}
}
plane.setIndex(idx);
}
</script>
var array = [[10, 20, 30, 20, 50], [40, 50, 60, 20, 20], [70, 80, 90, 20, 20], [70, 80, 90, 20, 20]];
For example i want to delete elements == 50
I want this result -> array= [[10,30,20], [40,60,20], [70,90,20], [70,90,20]];
I try this solution but it is not working ->
for (var i = 0; i < array.length; i++) {
for (var j = 0; j < array[i].length; j++) {
if (array[i][j] == 50) {
array[i].splice(j, 1);
}
}
}
You need to collect unwanted indices first and then return.
const
data = [
[10, 20, 30, 20, 50],
[40, 50, 60, 20, 20],
[70, 80, 90, 20, 20],
[70, 80, 90, 20, 20]
],
// ^^ ^^ cols with 50
//
indices = data.reduce(
(r, a) => a.map((v, i) => v === 50 ? false : r[i] ?? true),
[]
),
result = data.map(a => a.filter((_, i) => indices[i]));
result.forEach(a => console.log(...a));
const array = [[10, 20, 30, 20, 50], [40, 50, 60, 20, 20], [70, 80, 90, 20, 20], [70, 80, 90, 20, 20]];
const filteredArr = array.map(item => [...new Set(item.filter(i => i !== 50))])
// filterdArr = [[10, 30, 20], [40, 60, 20], [70, 80, 90, 20], [70, 80, 90, 20]];
I'm plotting a graph that needs to combine data of a selected date range to weekdays i mean if i selected a date range from ex: 2021-05-01 to 2021-05-31 in that consider 2021-05-01,2021-05-08,2021-05-15 these days are Friday so i need to combine datas of these dates and show as one data with label friday. With the current options that i used the chart is plotting like this. Is there any ways to display it correctly.
Demo Fiddle
This is the way that i currently getting the result
This is the result that i'm expecting
These are the current configd that i'm using in the highchart.
Highcharts.chart("multistackedbarchart-II", {
chart: {
type: "column",
},
title: {
text: "Sent/Received Comparison",
},
xAxis: {
title: {
text: "Day",
},
categories: [labels],
},
yAxis: {
min: 0,
title: {
text: "",
},
stackLabels: {
enabled: false,
style: {
fontWeight: "bold",
color:
// theme
(Highcharts.defaultOptions.title.style && Highcharts.defaultOptions.title.style.color) ||
"gray",
},
},
},
legend: {
align: "center",
verticalAlign: "bottom",
x: 0,
y: 0,
},
tooltip: {
headerFormat: "<b>{point.x}</b><br/>",
pointFormat: "{series.name}: {point.y}",
},
plotOptions: {
column: {
stacking: "normal",
dataGrouping: {
forced: true,
units: [['day', [1]]]
}
},
},
series: chartdata.multistackedbarchart,
credits: {
enabled: false,
},
});
Highcharts.setOptions({ lang: { noData: "No Data Available" } });
You can make a special function to do this sorting by using Array.map() and Array.filter() methods:
const categories = [
"2021-08-04",
"2021-08-05",
"2021-08-06",
"2021-08-07",
"2021-08-08",
"2021-08-09",
"2021-08-10",
"2021-08-11",
"2021-08-12",
"2021-08-13",
"2021-08-14",
"2021-08-15",
"2021-08-16",
"2021-08-17",
"2021-08-18",
"2021-08-19",
"2021-08-20",
"2021-08-21",
"2021-08-22",
"2021-08-23",
"2021-08-24",
"2021-08-25",
"2021-08-26",
"2021-08-27",
"2021-08-28",
"2021-08-29",
"2021-08-30",
"2021-08-31",
"2021-09-01",
"2021-09-02",
"2021-09-03",
"2021-09-04",
"2021-09-05",
"2021-09-06",
"2021-09-07",
"2021-09-08",
"2021-09-09",
"2021-09-10",
"2021-09-11",
"2021-09-12",
"2021-09-13",
"2021-09-14",
"2021-09-15",
"2021-09-16",
"2021-09-17",
"2021-09-18",
"2021-09-19",
"2021-09-20",
"2021-09-21",
"2021-09-22",
"2021-09-23",
"2021-09-24",
"2021-09-25",
"2021-09-26",
"2021-09-27",
"2021-09-28",
"2021-09-29",
"2021-09-30",
"2021-10-01",
"2021-10-02",
"2021-10-03",
"2021-10-04",
"2021-10-05",
"2021-10-06",
"2021-10-07",
"2021-10-08",
"2021-10-09",
"2021-10-10",
"2021-10-11",
"2021-10-12"]
const messagesSent = [ 32,
60,
71,
3,
1,
25,
16,
23,
28,
25,
2,
1,
43,
49,
32,
35,
26,
2,
1,
8,
36,
47,
15,
20,
2,
1,
2,
18,
20,
30,
43,
4,
4,
15,
14,
48,
39,
3,
2,
0,
48,
34,
15,
9,
1,
3,
1,
85,
27,
72,
11,
4,
2,
0,
29,
13,
21,
15,
32,
2,
0,
58,
37,
37,
24,
5,
1,
0,
0,
0]
const messagesReceived = [29,
79,
80,
7,
2,
24,
32,
23,
44,
42,
3,
1,
65,
69,
46,
47,
23,
3,
1,
28,
35,
65,
22,
19,
4,
1,
7,
10,
32,
31,
13,
8,
2,
4,
48,
53,
46,
7,
4,
0,
48,
40,
23,
18,
2,
6,
2,
79,
25,
86,
9,
8,
5,
0,
25,
18,
18,
14,
37,
2,
0,
52,
70,
27,
25,
17,
1,
0,
0,
0]
const organizeData = (days, sent, received) => {
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
// get name of weekday
const getDayOfWeek = date => {
const dayOfWeek = new Date(date).getDay();
return isNaN(dayOfWeek) ? null : dayNames[dayOfWeek];
}
return dayNames.map((dayName) => {
let correspondingMessagesSent = []
let correspondingMessagesReceived = []
const matchedDays = days.filter((day, index) => {
if(dayName === getDayOfWeek(day)) {
correspondingMessagesSent.push(sent[index])
correspondingMessagesReceived.push(received[index])
return day
}
})
return { [dayName]: { dates: matchedDays,
sent: correspondingMessagesSent,
received: correspondingMessagesReceived} }
})
}
console.log(organizeData(categories, messagesSent, messagesReceived))
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have two arrays, one of them represents data, and the other one - intervals. Both are sorted and their start and end values match. I go through nested for loops to calculate the average of data points in a given interval. As a result, I end up with one data value for each interval. For smaller size arrays, < 100-500 length, these linear loops do the work, however, this approach becomes an issue with several thousand data points. Any recommendation will be appreciated.
Please see a simplified code below with a link to JSfiddle at the end
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
DataArrayA = [];
for (i = 0; i < TimelineArray.length-1; i++) {
var dataPointsInGivenTimeInterval = [];
for (j = 0; j < DataArray.length; j++) {
if (DataArray[j] > TimelineArray[i] && DataArray[j] <= TimelineArray[i+1]) {
dataPointsInGivenTimeInterval.push(DataArray[j]);
}
};
if (dataPointsInGivenTimeInterval.length == 0) {
DataArrayA.push(null);
}
else {
var sumOfdataPoints = null;
for (k = 0; k < dataPointsInGivenTimeInterval.length; k++) {
sumOfdataPoints += dataPointsInGivenTimeInterval[k];
}
var avg = sumOfdataPoints / dataPointsInGivenTimeInterval.length;
DataArrayA.push(avg);
}
} // end for
console.log(TimelineArray);
console.log(DataArrayA);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
The console output is
[0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100]
[4.75, 15, 25.25, 36, null, 56.2, 64, 75, 89, 95]
Here is the code at JSfiddle - calculating average values for given intervals
Since the arrays are sorted, you can do it linearly with respect to the size of the timeline and data:
var timeline = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
data = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
var averages = new Array(timeline.length - 1);
for (var i = 0, j = 0; i < timeline.length; i++) {
var sum = 0,
items = 0;
for (; data[j] <= timeline[i]; j++) {
sum += data[j];
++items;
}
if(i) averages[i-1] = sum / items;
}
console.log(averages);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
You don't need to re-scan DataArray from the beginning on each iteration.
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100];
var DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
var res = [], pos = 0;
TimelineArray.forEach(function(v, i) {
for(var sum = 0, n = 0; DataArray[pos] <= v; n++) {
sum += DataArray[pos++];
}
i && res.push(n ? sum / n : null);
});
console.log(res);
Not sure if it'll be any faster, but here's a crack at it in a different way:
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
DataArrayA = [];
function avg(arr){
if(arr!= null && arr.length > 0)
return arr.reduce(function(a, b){ return a+b;}, 0) / arr.length;
return null;
}
for(var i = 0; i < TimelineArray.length-1; i++){
var interval = [TimelineArray[i], TimelineArray[i+1]];
var data = DataArray.filter(function(a){ return a > interval[0] && a <= interval[1]});
DataArrayA.push(avg(data));
}
console.log(DataArrayA);
edit 1: removed a loop.
The highcharts is rendering the chart when the series data is hardcoded and when the data is passed through a variable from backend, it doesn't generate a chart.
series: [{
name: 'T1',
stack: 'Tasks',
color: 'blue',
data: [ { x: 0,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 14, 15, 53)},
{ x: 1,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 11, 42, 02)},
{ x: 2,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 15, 54, 23)},
{ x: 3,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 14, 17, 08)},
{ x: 4,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 17, 23, 13)} ]
}, {
name: 'T2',
stack: 'Tasks',
color: 'green',
data: [ { x: 0,
low: Date.UTC(2015, 2, 13, 14, 15, 53),
high: Date.UTC(2015, 2, 13, 14, 17, 08)},
{ x: 1,
low: Date.UTC(2015, 2, 13, 11, 42, 02),
high: Date.UTC(2015, 2, 13, 13, 23, 02)},
{ x: 3,
low: Date.UTC(2015, 2, 13, 14, 17, 08),
high: Date.UTC(2015, 2, 13, 14, 24, 55)} ]
}, {
name: 'T3',
stack: 'Tasks',
color: 'red',
data: []
}]
When the value is coming from backend, the code is
series: [{
name: 'T1',
stack: 'Tasks',
color: 'blue',
data: (function(){
var data = [];
var temp = {};
for(i in msg.T1){
temp.x = msg.T1[i].x;
// temp.low = new Date(msg.T1[i].low) or Date.UTC(new Date(msg.T1[i].low);
// temp.high = new Date(msg.T1[i].high);
temp.low = parseInt(i);
temp.high = parseInt(i)+2;
data.push(temp);
}
return data;
}())
}, {
name: 'T2',
stack: 'Tasks',
color: 'green',
data: (function(){
var data = [];
var temp = {};
for(i in msg.T2){
temp.x = msg.T2[i].x;
// temp.low = new Date(msg.T2[i].low);
// temp.high = new Date(msg.T2[i].high);
temp.low = parseInt(i);
temp.high = parseInt(i)+2;
data.push(temp);
}
return data;
}())
}, {
name: 'T3',
stack: 'Tasks',
color: 'red',
data: (function(){
var data = [];
var temp = {};
for(i in msg.T3){
temp.x = msg.T3[i].x;
// temp.low = new Date(msg.T3[i].low);
// temp.high = new Date(msg.T3[i].high);
temp.low = parseInt(i);
temp.high = parseInt(i)+2;
data.push(temp);
}
return data;
}())
}]
});
The second code, despite throwing no error, does not render the chart.
What is wrong in the data format
The problem is fixed, issue was that the value of x in temp.x, the data object passed to series, should be integer only, no Strings or any other data types are allowed. Fixing that fixed the chart