This is code for a spinning wheel. When a person clicks the spinning wheel, it rotates and gives a result after a few seconds (depending on the script's time settings). How can an edit the color of the below text? So, when the wheel stops, the result text font color must be red on black background. Which part of the code has the reference to this?
(function($) {
var venues = [{
"name": "1900 Mexican Grill",
"type": "Mexican"
}, {
"name": "300 East",
"type": "American/Upscale"
}, {
"name": "Angry Ale's",
"type": "American/Pub "
}, {
"name": "Azteca",
"type": "Mexican"
}, {
"name": "Bedder Bedder and Moore",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Boading",
"type": "Chinese"
}, {
"name": "Brazwell's Premium Pub",
"type": "American/Pub "
}, {
"name": "Brio Tuscan Grille",
"type": "Italian"
}, {
"name": "Brixx",
"type": "Pizza/Salads"
}, {
"name": "Café at 6100",
"type": "Home Cooking"
}, {
"name": "California Pizza Kitchen",
"type": "Pizza/Salads"
}, {
"name": "Chick-Fil-A",
"type": "Fast Food"
}, {
"name": "City Tavern",
"type": "American/Upscale"
}, {
"name": "Copper",
"type": "Indian"
}, {
"name": "Cowfish",
"type": "Sushi"
}, {
"name": "Duckworth's",
"type": "American/Pub "
}, {
"name": "Eddie's Place",
"type": "American/Pub "
}, {
"name": "El Camino",
"type": "Mexican"
}, {
"name": "Fairview Plaza Restaurant",
"type": "Home Cooking"
}, {
"name": "Firebird's Wood Fired Grill",
"type": "American/Upscale"
}, {
"name": "Firehouse Subs",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Flying Biscuit",
"type": "American/Fast"
}, {
"name": "Fuel",
"type": "Pizza"
}, {
"name": "Good Food on Montford",
"type": "American/Upscale"
}, {
"name": "Harper's Restaurant",
"type": "American/Upscale"
}, {
"name": "Hawthorne's Pizza",
"type": "Pizza/Italian"
}, {
"name": "Luisa's Brick Oven Pizza",
"type": "Pizza/Italian"
}, {
"name": "Maverick Rock Taco",
"type": "Mexican"
}, {
"name": "McAllister's",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Mellow Mushroom",
"type": "Pizza/Salads"
}, {
"name": "Moe's",
"type": "Mexican"
}, {
"name": "Moosehead Grill",
"type": "American/Pub "
}, {
"name": "Paco's Tacos and Tequila",
"type": "Mexican"
}, {
"name": "Panera ",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "PF Chang's",
"type": "Chinese"
}, {
"name": "Portofinos",
"type": "Pizza/Italian"
}, {
"name": "Qdoba",
"type": "Mexican"
}, {
"name": "Rooster's Wood Fire Kitchen",
"type": "American/Upscale"
}, {
"name": "Rusty's Deli",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Taco Bell",
"type": "Fast Food"
}, {
"name": "Taco Mac",
"type": "American/Pub "
}, {
"name": "Terrace Café",
"type": "American/Upscale"
}, {
"name": "The Roasting Company",
"type": "American/Fast"
}, {
"name": "Village Tavern",
"type": "American/Upscale"
}, {
"name": "Which Witch?",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Zack's Hamburgers",
"type": "American/Fast"
}];
// Helpers
var blackHex = '#333',
whiteHex = '#fff',
shuffle = function(o) {
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x)
;
return o;
},
halfPI = Math.PI / 2,
doublePI = Math.PI * 2;
String.prototype.hashCode = function() {
// See http://www.cse.yorku.ca/~oz/hash.html
var hash = 5381,
i;
for (i = 0; i < this.length; i++) {
char = this.charCodeAt(i);
hash = ((hash << 5) + hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
};
// WHEEL!
var wheel = {
timerHandle: 0,
timerDelay: 33,
angleCurrent: 0,
angleDelta: 0,
size: 290,
canvasContext: null,
colors: ['#003366', '#FF6600', '#CCCC00', '#006600', '#3333CC', '#CC0066', '#FF3300', '#009900', '#6600CC', '#33CC33', '#0066CC', '#FF0066', '#3300FF', '#00CC00', '#FFCC00'],
segments: [],
seg_colors: [], // Cache of segments to colors
maxSpeed: Math.PI / 16,
upTime: 1000, // How long to spin up for (in ms)
downTime: 5000, // How long to slow down for (in ms)
spinStart: 0,
frames: 0,
centerX: 300,
centerY: 300,
spin: function() {
// Start the wheel only if it's not already spinning
if (wheel.timerHandle == 0) {
wheel.spinStart = new Date().getTime();
wheel.maxSpeed = Math.PI / (16 + Math.random()); // Randomly vary how hard the spin is
wheel.frames = 0;
wheel.sound.play();
wheel.timerHandle = setInterval(wheel.onTimerTick, wheel.timerDelay);
}
},
onTimerTick: function() {
var duration = (new Date().getTime() - wheel.spinStart),
progress = 0,
finished = false;
wheel.frames++;
wheel.draw();
if (duration < wheel.upTime) {
progress = duration / wheel.upTime;
wheel.angleDelta = wheel.maxSpeed *
Math.sin(progress * halfPI);
} else {
progress = duration / wheel.downTime;
wheel.angleDelta = wheel.maxSpeed *
Math.sin(progress * halfPI + halfPI);
if (progress >= 1) {
finished = true;
}
}
wheel.angleCurrent += wheel.angleDelta;
while (wheel.angleCurrent >= doublePI) {
// Keep the angle in a reasonable range
wheel.angleCurrent -= doublePI;
}
if (finished) {
clearInterval(wheel.timerHandle);
wheel.timerHandle = 0;
wheel.angleDelta = 0;
if (console) {
console.log((wheel.frames / duration * 1000) + " FPS");
}
}
/*
// Display RPM
var rpm = (wheel.angleDelta * (1000 / wheel.timerDelay) * 60) / (Math.PI * 2);
$("#counter").html( Math.round(rpm) + " RPM" );
*/
},
init: function(optionList) {
try {
wheel.initWheel();
wheel.initAudio();
wheel.initCanvas();
wheel.draw();
$.extend(wheel, optionList);
} catch (exceptionData) {
alert('Wheel is not loaded ' + exceptionData);
}
},
initAudio: function() {
var sound = document.createElement('audio');
sound.setAttribute('src', 'wheel.mp3');
wheel.sound = sound;
},
initCanvas: function() {
var canvas = $('#canvas')[0];
canvas.addEventListener("click", wheel.spin, false);
wheel.canvasContext = canvas.getContext("2d");
},
initWheel: function() {
shuffle(wheel.colors);
},
// Called when segments have changed
update: function() {
// Ensure we start mid way on a item
//var r = Math.floor(Math.random() * wheel.segments.length);
var r = 0,
segments = wheel.segments,
len = segments.length,
colors = wheel.colors,
colorLen = colors.length,
seg_color = [], // Generate a color cache (so we have consistant coloring)
i
wheel.angleCurrent = ((r + 0.5) / wheel.segments.length) * doublePI;
for (i = 0; i < len; i++) {
seg_color.push(colors[segments[i].hashCode().mod(colorLen)]);
}
wheel.seg_color = seg_color;
wheel.draw();
},
draw: function() {
wheel.clear();
wheel.drawWheel();
wheel.drawNeedle();
},
clear: function() {
wheel.canvasContext.clearRect(0, 0, 1000, 800);
},
drawNeedle: function() {
var ctx = wheel.canvasContext,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
i,
centerSize = centerX + size,
len = wheel.segments.length,
winner;
ctx.lineWidth = 2;
ctx.strokeStyle = blackHex;
ctx.fillStyle = whiteHex;
ctx.beginPath();
ctx.moveTo(centerSize - 10, centerY);
ctx.lineTo(centerSize + 10, centerY - 10);
ctx.lineTo(centerSize + 10, centerY + 10);
ctx.closePath();
ctx.stroke();
ctx.fill();
// Which segment is being pointed to?
i = len - Math.floor((wheel.angleCurrent / doublePI) * len) - 1;
// Now draw the winning name
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillStyle = blackHex;
ctx.font = "2em Arial";
winner = wheel.segments[i] || 'Choose at least 1 Venue';
ctx.fillText(winner, centerSize + 20, centerY);
},
drawSegment: function(key, lastAngle, angle) {
var ctx = wheel.canvasContext,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
colors = wheel.seg_color,
value = wheel.segments[key];
//ctx.save();
ctx.beginPath();
// Start in the centre
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, size, lastAngle, angle, false); // Draw an arc around the edge
ctx.lineTo(centerX, centerY); // Now draw a line back to the center
// Clip anything that follows to this area
//ctx.clip(); // It would be best to clip, but we can double performance without it
ctx.closePath();
ctx.fillStyle = colors[key];
ctx.fill();
ctx.stroke();
// Now draw the text
ctx.save(); // The save ensures this works on Android devices
ctx.translate(centerX, centerY);
ctx.rotate((lastAngle + angle) / 2);
ctx.fillStyle = whiteHex;
ctx.fillText(value.substr(0, 20), size - 15, 0);
ctx.restore();
},
drawWheel: function() {
var ctx = wheel.canvasContext,
angleCurrent = wheel.angleCurrent,
lastAngle = angleCurrent,
len = wheel.segments.length,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
angle,
i;
ctx.lineWidth = 1;
ctx.strokeStyle = blackHex;
ctx.textBaseline = "middle";
ctx.textAlign = "right";
ctx.font = "1em Arial";
for (i = 1; i <= len; i++) {
angle = doublePI * (i / len) + angleCurrent;
wheel.drawSegment(i - 1, lastAngle, angle);
lastAngle = angle;
}
// Draw a center circle
ctx.beginPath();
ctx.arc(centerX, centerY, 20, 0, doublePI, false);
ctx.closePath();
ctx.fillStyle = whiteHex;
//ctx.strokeStyle = blackHex;
ctx.fill();
ctx.stroke();
// Draw outer circle
ctx.beginPath();
ctx.arc(centerX, centerY, size, 0, doublePI, false);
ctx.closePath();
ctx.lineWidth = 10;
//ctx.strokeStyle = blackHex;
ctx.stroke();
}
};
$(function() {
var $venues = $('#venues'),
$venueName = $('#name'),
$venueType = $('#types'),
venueTypes = [],
$list = $('<ul/>'),
$types = $('<ul/>'),
$filterToggler = $('#filterToggle'),
arrayUnique = function(a) {
return a.reduce(function(p, c) {
if (p.indexOf(c) < 0) {
p.push(c);
}
return p;
}, []);
};
$.each(venues, function(index, venue) {
$list.append(
$("<li/>")
.append(
$("<input />").attr({
id: 'venue-' + index,
name: venue.name,
value: venue.name,
type: 'checkbox',
checked: true
})
.change(function() {
var cbox = this,
segments = wheel.segments,
i = segments.indexOf(cbox.value);
if (cbox.checked && i === -1) {
segments.push(cbox.value);
} else if (!cbox.checked && i !== -1) {
segments.splice(i, 1);
}
segments.sort();
wheel.update();
})
).append(
$('<label />').attr({
'for': 'venue-' + index
})
.text(venue.name)
)
);
venueTypes.push(venue.type);
});
$.each(arrayUnique(venueTypes), function(index, venue) {
$types.append(
$("<li/>")
.append(
$("<input />").attr({
id: 'venue-type-' + index,
name: venue,
value: venue,
type: 'checkbox',
checked: true
})
.change(function() {
var $this = $(this),
i;
for (i = 0; i < venues.length; i++) {
if (venues[i].type === $this.val()) {
$('[name="' + venues[i].name + '"]').prop("checked", $this.prop('checked')).trigger('change');
}
}
})
).append(
$('<label />').attr({
'for': 'venue-' + index
})
.text(venue)
)
)
});
$venueName.append($list);
$venueType.append($types);
// Uses the tinysort plugin, but our array is sorted for now.
//$list.find('>li').tsort("input", {attr: "value"});
wheel.init();
$.each($venueName.find('ul input:checked'), function(key, cbox) {
wheel.segments.push(cbox.value);
});
wheel.update();
$venues.slideUp().data("open", false);
$filterToggler.on("click", function() {
if ($venues.data("open")) {
$venues.slideUp().data("open", false);
} else {
$venues.slideDown().data("open", true);
}
});
$('.checkAll').on("click", function() {
$(this).parent().next('div').find('input').prop('checked', $(this).prop('checked')).trigger("change");
});
});
}(jQuery));
body {
background: #fff;
font-family: sans-serif;
color: #666;
}
h1,
h2 {
font-weight: 700;
line-height: 2;
}
input[type='checkbox']+label {
padding-left: .5em;
}
label,
#filterToggle {
display: inline-block;
}
#venues,
#filterToggle {
background: #fefefe;
box-shadow: 0 1px 2px #efefef;
}
#venues {
padding: .5em;
overflow: hidden;
}
#venues ul,
#venues h2 {
clear: both;
}
#venues li {
float: left;
width: 25%;
line-height: 1.5;
vertical-align: middle;
}
#filterToggle {
border-radius: 0 0 3px 3px;
cursor: pointer;
margin-left: .5em;
margin-top: -1px;
padding: .5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="venues">
<h1>Venues <input type="checkbox" class="checkAll" checked /></h1>
<div id="name"></div>
<h2>Types <input type="checkbox" class="checkAll" checked /></h2>
<div id="types"></div>
</div>
<div id="filterToggle">. . .</div>
<div id="wheel">
<canvas id="canvas" width="1000" height="600"></canvas>
</div>
<div id="counter"></div>
How can I change text color and font of the text?
I can help you with the font size and the color:
// Now draw the winning name
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillStyle = '#fff000'; // text color
ctx.font = "5em Arial"; // font size and family
You have to edit this part.
(function($) {
var venues = [{
"name": "1900 Mexican Grill",
"type": "Mexican"
}, {
"name": "300 East",
"type": "American/Upscale"
}, {
"name": "Angry Ale's",
"type": "American/Pub "
}, {
"name": "Azteca",
"type": "Mexican"
}, {
"name": "Bedder Bedder and Moore",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Boading",
"type": "Chinese"
}, {
"name": "Brazwell's Premium Pub",
"type": "American/Pub "
}, {
"name": "Brio Tuscan Grille",
"type": "Italian"
}, {
"name": "Brixx",
"type": "Pizza/Salads"
}, {
"name": "Café at 6100",
"type": "Home Cooking"
}, {
"name": "California Pizza Kitchen",
"type": "Pizza/Salads"
}, {
"name": "Chick-Fil-A",
"type": "Fast Food"
}, {
"name": "City Tavern",
"type": "American/Upscale"
}, {
"name": "Copper",
"type": "Indian"
}, {
"name": "Cowfish",
"type": "Sushi"
}, {
"name": "Duckworth's",
"type": "American/Pub "
}, {
"name": "Eddie's Place",
"type": "American/Pub "
}, {
"name": "El Camino",
"type": "Mexican"
}, {
"name": "Fairview Plaza Restaurant",
"type": "Home Cooking"
}, {
"name": "Firebird's Wood Fired Grill",
"type": "American/Upscale"
}, {
"name": "Firehouse Subs",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Flying Biscuit",
"type": "American/Fast"
}, {
"name": "Fuel",
"type": "Pizza"
}, {
"name": "Good Food on Montford",
"type": "American/Upscale"
}, {
"name": "Harper's Restaurant",
"type": "American/Upscale"
}, {
"name": "Hawthorne's Pizza",
"type": "Pizza/Italian"
}, {
"name": "Luisa's Brick Oven Pizza",
"type": "Pizza/Italian"
}, {
"name": "Maverick Rock Taco",
"type": "Mexican"
}, {
"name": "McAllister's",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Mellow Mushroom",
"type": "Pizza/Salads"
}, {
"name": "Moe's",
"type": "Mexican"
}, {
"name": "Moosehead Grill",
"type": "American/Pub "
}, {
"name": "Paco's Tacos and Tequila",
"type": "Mexican"
}, {
"name": "Panera ",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "PF Chang's",
"type": "Chinese"
}, {
"name": "Portofinos",
"type": "Pizza/Italian"
}, {
"name": "Qdoba",
"type": "Mexican"
}, {
"name": "Rooster's Wood Fire Kitchen",
"type": "American/Upscale"
}, {
"name": "Rusty's Deli",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Taco Bell",
"type": "Fast Food"
}, {
"name": "Taco Mac",
"type": "American/Pub "
}, {
"name": "Terrace Café",
"type": "American/Upscale"
}, {
"name": "The Roasting Company",
"type": "American/Fast"
}, {
"name": "Village Tavern",
"type": "American/Upscale"
}, {
"name": "Which Witch?",
"type": "Sandwiches, Salads, Soups"
}, {
"name": "Zack's Hamburgers",
"type": "American/Fast"
}];
// Helpers
var blackHex = '#333',
whiteHex = '#fff',
shuffle = function(o) {
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x)
;
return o;
},
halfPI = Math.PI / 2,
doublePI = Math.PI * 2;
String.prototype.hashCode = function() {
// See http://www.cse.yorku.ca/~oz/hash.html
var hash = 5381,
i;
for (i = 0; i < this.length; i++) {
char = this.charCodeAt(i);
hash = ((hash << 5) + hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
};
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
};
// WHEEL!
var wheel = {
timerHandle: 0,
timerDelay: 33,
angleCurrent: 0,
angleDelta: 0,
size: 290,
canvasContext: null,
colors: ['#003366', '#FF6600', '#CCCC00', '#006600', '#3333CC', '#CC0066', '#FF3300', '#009900', '#6600CC', '#33CC33', '#0066CC', '#FF0066', '#3300FF', '#00CC00', '#FFCC00'],
segments: [],
seg_colors: [], // Cache of segments to colors
maxSpeed: Math.PI / 16,
upTime: 1000, // How long to spin up for (in ms)
downTime: 5000, // How long to slow down for (in ms)
spinStart: 0,
frames: 0,
centerX: 300,
centerY: 300,
spin: function() {
// Start the wheel only if it's not already spinning
if (wheel.timerHandle == 0) {
wheel.spinStart = new Date().getTime();
wheel.maxSpeed = Math.PI / (16 + Math.random()); // Randomly vary how hard the spin is
wheel.frames = 0;
wheel.sound.play();
wheel.timerHandle = setInterval(wheel.onTimerTick, wheel.timerDelay);
}
},
onTimerTick: function() {
var duration = (new Date().getTime() - wheel.spinStart),
progress = 0,
finished = false;
wheel.frames++;
wheel.draw();
if (duration < wheel.upTime) {
progress = duration / wheel.upTime;
wheel.angleDelta = wheel.maxSpeed *
Math.sin(progress * halfPI);
} else {
progress = duration / wheel.downTime;
wheel.angleDelta = wheel.maxSpeed *
Math.sin(progress * halfPI + halfPI);
if (progress >= 1) {
finished = true;
}
}
wheel.angleCurrent += wheel.angleDelta;
while (wheel.angleCurrent >= doublePI) {
// Keep the angle in a reasonable range
wheel.angleCurrent -= doublePI;
}
if (finished) {
clearInterval(wheel.timerHandle);
wheel.timerHandle = 0;
wheel.angleDelta = 0;
if (console) {
console.log((wheel.frames / duration * 1000) + " FPS");
}
}
/*
// Display RPM
var rpm = (wheel.angleDelta * (1000 / wheel.timerDelay) * 60) / (Math.PI * 2);
$("#counter").html( Math.round(rpm) + " RPM" );
*/
},
init: function(optionList) {
try {
wheel.initWheel();
wheel.initAudio();
wheel.initCanvas();
wheel.draw();
$.extend(wheel, optionList);
} catch (exceptionData) {
alert('Wheel is not loaded ' + exceptionData);
}
},
initAudio: function() {
var sound = document.createElement('audio');
sound.setAttribute('src', 'wheel.mp3');
wheel.sound = sound;
},
initCanvas: function() {
var canvas = $('#canvas')[0];
canvas.addEventListener("click", wheel.spin, false);
wheel.canvasContext = canvas.getContext("2d");
},
initWheel: function() {
shuffle(wheel.colors);
},
// Called when segments have changed
update: function() {
// Ensure we start mid way on a item
//var r = Math.floor(Math.random() * wheel.segments.length);
var r = 0,
segments = wheel.segments,
len = segments.length,
colors = wheel.colors,
colorLen = colors.length,
seg_color = [], // Generate a color cache (so we have consistant coloring)
i
wheel.angleCurrent = ((r + 0.5) / wheel.segments.length) * doublePI;
for (i = 0; i < len; i++) {
seg_color.push(colors[segments[i].hashCode().mod(colorLen)]);
}
wheel.seg_color = seg_color;
wheel.draw();
},
draw: function() {
wheel.clear();
wheel.drawWheel();
wheel.drawNeedle();
},
clear: function() {
wheel.canvasContext.clearRect(0, 0, 1000, 800);
},
drawNeedle: function() {
var ctx = wheel.canvasContext,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
i,
centerSize = centerX + size,
len = wheel.segments.length,
winner;
ctx.lineWidth = 2;
ctx.strokeStyle = blackHex;
ctx.fillStyle = whiteHex;
ctx.beginPath();
ctx.moveTo(centerSize - 10, centerY);
ctx.lineTo(centerSize + 10, centerY - 10);
ctx.lineTo(centerSize + 10, centerY + 10);
ctx.closePath();
ctx.stroke();
ctx.fill();
// Which segment is being pointed to?
i = len - Math.floor((wheel.angleCurrent / doublePI) * len) - 1;
// Now draw the winning name
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillStyle = '#fff000'
ctx.font = "5em Arial";
winner = wheel.segments[i] || 'Choose at least 1 Venue';
ctx.fillText(winner, centerSize + 20, centerY);
},
drawSegment: function(key, lastAngle, angle) {
var ctx = wheel.canvasContext,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
colors = wheel.seg_color,
value = wheel.segments[key];
//ctx.save();
ctx.beginPath();
// Start in the centre
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, size, lastAngle, angle, false); // Draw an arc around the edge
ctx.lineTo(centerX, centerY); // Now draw a line back to the center
// Clip anything that follows to this area
//ctx.clip(); // It would be best to clip, but we can double performance without it
ctx.closePath();
ctx.fillStyle = colors[key];
ctx.fill();
ctx.stroke();
// Now draw the text
ctx.save(); // The save ensures this works on Android devices
ctx.translate(centerX, centerY);
ctx.rotate((lastAngle + angle) / 2);
ctx.fillStyle = whiteHex;
ctx.fillText(value.substr(0, 20), size - 15, 0);
ctx.restore();
},
drawWheel: function() {
var ctx = wheel.canvasContext,
angleCurrent = wheel.angleCurrent,
lastAngle = angleCurrent,
len = wheel.segments.length,
centerX = wheel.centerX,
centerY = wheel.centerY,
size = wheel.size,
angle,
i;
ctx.lineWidth = 1;
ctx.strokeStyle = blackHex;
ctx.textBaseline = "middle";
ctx.textAlign = "right";
ctx.font = "1em Arial";
for (i = 1; i <= len; i++) {
angle = doublePI * (i / len) + angleCurrent;
wheel.drawSegment(i - 1, lastAngle, angle);
lastAngle = angle;
}
// Draw a center circle
ctx.beginPath();
ctx.arc(centerX, centerY, 20, 0, doublePI, false);
ctx.closePath();
ctx.fillStyle = whiteHex;
//ctx.strokeStyle = blackHex;
ctx.fill();
ctx.stroke();
// Draw outer circle
ctx.beginPath();
ctx.arc(centerX, centerY, size, 0, doublePI, false);
ctx.closePath();
ctx.lineWidth = 10;
//ctx.strokeStyle = blackHex;
ctx.stroke();
}
};
$(function() {
var $venues = $('#venues'),
$venueName = $('#name'),
$venueType = $('#types'),
venueTypes = [],
$list = $('<ul/>'),
$types = $('<ul/>'),
$filterToggler = $('#filterToggle'),
arrayUnique = function(a) {
return a.reduce(function(p, c) {
if (p.indexOf(c) < 0) {
p.push(c);
}
return p;
}, []);
};
$.each(venues, function(index, venue) {
$list.append(
$("<li/>")
.append(
$("<input />").attr({
id: 'venue-' + index,
name: venue.name,
value: venue.name,
type: 'checkbox',
checked: true
})
.change(function() {
var cbox = this,
segments = wheel.segments,
i = segments.indexOf(cbox.value);
if (cbox.checked && i === -1) {
segments.push(cbox.value);
} else if (!cbox.checked && i !== -1) {
segments.splice(i, 1);
}
segments.sort();
wheel.update();
})
).append(
$('<label />').attr({
'for': 'venue-' + index
})
.text(venue.name)
)
);
venueTypes.push(venue.type);
});
$.each(arrayUnique(venueTypes), function(index, venue) {
$types.append(
$("<li/>")
.append(
$("<input />").attr({
id: 'venue-type-' + index,
name: venue,
value: venue,
type: 'checkbox',
checked: true
})
.change(function() {
var $this = $(this),
i;
for (i = 0; i < venues.length; i++) {
if (venues[i].type === $this.val()) {
$('[name="' + venues[i].name + '"]').prop("checked", $this.prop('checked')).trigger('change');
}
}
})
).append(
$('<label />').attr({
'for': 'venue-' + index
})
.text(venue)
)
)
});
$venueName.append($list);
$venueType.append($types);
// Uses the tinysort plugin, but our array is sorted for now.
//$list.find('>li').tsort("input", {attr: "value"});
wheel.init();
$.each($venueName.find('ul input:checked'), function(key, cbox) {
wheel.segments.push(cbox.value);
});
wheel.update();
$venues.slideUp().data("open", false);
$filterToggler.on("click", function() {
if ($venues.data("open")) {
$venues.slideUp().data("open", false);
} else {
$venues.slideDown().data("open", true);
}
});
$('.checkAll').on("click", function() {
$(this).parent().next('div').find('input').prop('checked', $(this).prop('checked')).trigger("change");
});
});
}(jQuery));
body {
background: #fff;
font-family: sans-serif;
color: #666;
}
h1,
h2 {
font-weight: 700;
line-height: 2;
}
input[type='checkbox']+label {
padding-left: .5em;
}
label,
#filterToggle {
display: inline-block;
}
#venues,
#filterToggle {
background: #fefefe;
box-shadow: 0 1px 2px #efefef;
}
#venues {
padding: .5em;
overflow: hidden;
}
#venues ul,
#venues h2 {
clear: both;
}
#venues li {
float: left;
width: 25%;
line-height: 1.5;
vertical-align: middle;
}
#filterToggle {
border-radius: 0 0 3px 3px;
cursor: pointer;
margin-left: .5em;
margin-top: -1px;
padding: .5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="venues">
<h1>Venues <input type="checkbox" class="checkAll" checked /></h1>
<div id="name"></div>
<h2>Types <input type="checkbox" class="checkAll" checked /></h2>
<div id="types"></div>
</div>
<div id="filterToggle">. . .</div>
<div id="wheel">
<canvas id="canvas" width="1000" height="600"></canvas>
</div>
<div id="counter"></div>
Hi everyone I created a network graph using Pixi and d3 and my graph is to slow for that I have to work complex functions in the second thread
here is App.js
import './App.css';
import { ForceGraph } from './components/forceGraph';
import data from './data/data.json';
import React from 'react';
function App() {
const nodeHoverTooltip = React.useCallback((node) => {
return `<div>
<b>${node.name}</b>
</div>`;
}, []);
return (
<div className="App">
<ForceGraph
linksData={data.links}
nodesData={data.nodes}
nodeHoverTooltip={nodeHoverTooltip}
/>
</div>
);
}
export default App;
here is forceGraph.js
import React from 'react';
import { runForceGraphPixi } from './forceGraphGeneratorPixi';
import styles from './forceGraph.module.css';
export function ForceGraph({ linksData, nodesData, nodeHoverTooltip }) {
const containerRef = React.useRef(null);
React.useEffect(() => {
if (containerRef.current) {
runForceGraphPixi(
containerRef.current,
linksData,
nodesData,
nodeHoverTooltip
);
}
}, [linksData, nodesData, nodeHoverTooltip]);
return <div ref={containerRef} className={styles.container} />;
}
here is forceGraphGeneratorPixi.js
import * as d3 from 'd3';
import * as PIXI from 'pixi.js';
import { Viewport } from 'pixi-viewport';
import styles from './forceGraph.module.css';
export function runForceGraphPixi(
container,
linksData,
nodesData,
nodeHoverTooltip
) {
const links = linksData.map((d) => Object.assign({}, d));
const nodes = nodesData.map((d) => Object.assign({}, d));
const containerRect = container.getBoundingClientRect();
const height = containerRect.height;
const width = containerRect.width;
let dragged = false;
container.innerHTML = '';
const color = () => {
return '#f0f8ff';
};
// Add the tooltip element to the graph
const tooltip = document.querySelector('#graph-tooltip');
if (!tooltip) {
const tooltipDiv = document.createElement('div');
tooltipDiv.classList.add(styles.tooltip);
tooltipDiv.style.opacity = '0';
tooltipDiv.id = 'graph-tooltip';
document.body.appendChild(tooltipDiv);
}
const div = d3.select('#graph-tooltip');
const addTooltip = (hoverTooltip, d, x, y) => {
div.transition().duration(200).style('opacity', 0.9);
div
.html(hoverTooltip(d))
.style('left', `${x}px`)
.style('top', `${y - 28}px`);
};
const removeTooltip = () => {
div.transition().duration(200).style('opacity', 0);
};
const colorScale = (num) => parseInt(color().slice(1), 16);
const app = new PIXI.Application({
width,
height,
antialias: !0,
transparent: !0,
resolution: 1,
});
container.appendChild(app.view);
// create viewport
const viewport = new Viewport({
screenWidth: width,
screenHeight: height,
worldWidth: width * 4,
worldHeight: height * 4,
passiveWheel: false,
interaction: app.renderer.plugins.interaction, // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
});
app.stage.addChild(viewport);
// activate plugins
viewport
.drag()
.pinch()
.wheel()
.decelerate()
.clampZoom({ minWidth: width / 4, minHeight: height / 4 });
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links) // This force provides links between nodes
.id((d) => d.id) // This sets the node id accessor to the specified function. If not specified, will default to the index of a node.
.distance(50)
)
.force('charge', d3.forceManyBody().strength(-500)) // This adds repulsion (if it's negative) between nodes.
.force('center', d3.forceCenter(width / 2, height / 2))
.force(
'collision',
d3
.forceCollide()
.radius((d) => d.radius)
.iterations(2)
)
.velocityDecay(0.8);
/*
Implementation
*/
let visualLinks = new PIXI.Graphics();
viewport.addChild(visualLinks);
nodes.forEach((node) => {
const { name, gender } = node;
node.gfx = new PIXI.Graphics();
node.gfx.lineStyle(1, 0xd3d3d3);
node.gfx.beginFill(colorScale(node.id));
node.gfx.drawCircle(0, 0, 24);
node.gfx.endFill();
node.gfx
// events for click
.on('click', (e) => {
if (!dragged) {
e.stopPropagation();
}
dragged = false;
});
viewport.addChild(node.gfx);
node.gfx.interactive = true;
node.gfx.buttonMode = true;
// create hit area, needed for interactivity
node.gfx.hitArea = new PIXI.Circle(0, 0, 24);
// show tooltip when mouse is over node
node.gfx.on('mouseover', (mouseData) => {
addTooltip(
nodeHoverTooltip,
{ name },
mouseData.data.originalEvent.pageX,
mouseData.data.originalEvent.pageY
);
});
// make circle half-transparent when mouse leaves
node.gfx.on('mouseout', () => {
removeTooltip();
});
const text = new PIXI.Text(name, {
fontSize: 12,
fill: '#000',
});
text.anchor.set(0.5);
text.resolution = 2;
node.gfx.addChild(text);
});
const ticked = () => {
nodes.forEach((node) => {
let { x, y, gfx } = node;
gfx.position = new PIXI.Point(x, y);
});
for (let i = visualLinks.children.length - 1; i >= 0; i--) {
visualLinks.children[i].destroy();
}
visualLinks.clear();
visualLinks.removeChildren();
visualLinks.alpha = 1;
links.forEach((link) => {
let { source, target, number } = link;
visualLinks.lineStyle(2, 0xd3d3d3);
visualLinks.moveTo(source.x, source.y);
visualLinks.lineTo(target.x, target.y);
});
visualLinks.endFill();
};
// Listen for tick events to render the nodes as they update in your Canvas or SVG.
simulation.on('tick', ticked);
return {
destroy: () => {
nodes.forEach((node) => {
node.gfx.clear();
});
visualLinks.clear();
},
};
}
here is forceGraph.module.css
.container {
width: 100%;
height: 80vh;
position: relative;
background-color: white;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.6);
}
.container svg {
display: block;
width: 100%;
height: 100%;
}
.male {
fill: rgb(22, 130, 218);
}
.female {
fill: rgb(246, 0, 0);
}
.node text {
font: 12px sans-serif;
}
div.tooltip {
position: absolute;
text-align: center;
width: 110px;
padding: 10px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0;
border-radius: 8px;
pointer-events: none;
}
.contextMenu {
stroke: #00557d;
fill: #ffffff;
}
.menuEntry {
cursor: pointer;
}
.menuEntry text {
font-size: 12px;
stroke: #00557d;
}
here is my data.json
{
"nodes": [
{
"id": 1,
"name": "Andy",
"gender": "male"
},
{
"id": 2,
"name": "Betty",
"gender": "female"
},
{
"id": 3,
"name": "Cate",
"gender": "female"
},
{
"id": 4,
"name": "Dave",
"gender": "male"
},
{
"id": 5,
"name": "Ellen",
"gender": "female"
},
{
"id": 6,
"name": "Fiona",
"gender": "female"
},
{
"id": 7,
"name": "Garry",
"gender": "male"
},
{
"id": 8,
"name": "Holly",
"gender": "female"
},
{
"id": 9,
"name": "Iris",
"gender": "female"
},
{
"id": 10,
"name": "Jane",
"gender": "female"
}
],
"links": [
{
"source": 1,
"target": 2
},
{
"source": 1,
"target": 5
},
{
"source": 1,
"target": 6
},
{
"source": 2,
"target": 3
},
{
"source": 2,
"target": 7
}
,
{
"source": 3,
"target": 4
},
{
"source": 8,
"target": 3
}
,
{
"source": 4,
"target": 5
}
,
{
"source": 4,
"target": 9
},
{
"source": 5,
"target": 10
}
]
}
After this I'm getting result
After this i add worker.js,and while I'm importing any other library inside worker.js I'm getting some error but I fixed that one also and the code is below
deep-thought.js(worker)
import addition from './addition';
import * as d3 from 'd3';
/* eslint-disable no-restricted-globals */
self.onmessage = (question) => {
const reciveData = question.data;
const nodes = question.data.nodes;
const links = question.data.links;
console.log(nodes);
console.log(links);
console.log(reciveData);
const result = addition(42);
self.postMessage({
result: result,
});
};
updated forceGraphGeneratorPixi.js
import * as d3 from 'd3';
import * as PIXI from 'pixi.js';
import { Viewport } from 'pixi-viewport';
import styles from './forceGraph.module.css';
export function runForceGraphPixi(
container,
linksData,
nodesData,
nodeHoverTooltip
) {
const links = linksData.map((d) => Object.assign({}, d));
const nodes = nodesData.map((d) => Object.assign({}, d));
const containerRect = container.getBoundingClientRect();
const height = containerRect.height;
const width = containerRect.width;
let dragged = false;
container.innerHTML = '';
const color = () => {
return '#f0f8ff';
};
// Pass data to web-worker
const worker = new Worker(new URL('../deep-thought.js', import.meta.url));
worker.postMessage({
nodes: nodes,
links: links,
});
worker.onmessage = ({ data: { answer } }) => {
console.log(answer);
};
// Add the tooltip element to the graph
const tooltip = document.querySelector('#graph-tooltip');
if (!tooltip) {
const tooltipDiv = document.createElement('div');
tooltipDiv.classList.add(styles.tooltip);
tooltipDiv.style.opacity = '0';
tooltipDiv.id = 'graph-tooltip';
document.body.appendChild(tooltipDiv);
}
const div = d3.select('#graph-tooltip');
const addTooltip = (hoverTooltip, d, x, y) => {
div.transition().duration(200).style('opacity', 0.9);
div
.html(hoverTooltip(d))
.style('left', `${x}px`)
.style('top', `${y - 28}px`);
};
const removeTooltip = () => {
div.transition().duration(200).style('opacity', 0);
};
const colorScale = (num) => parseInt(color().slice(1), 16);
const app = new PIXI.Application({
width,
height,
antialias: !0,
transparent: !0,
resolution: 1,
});
container.appendChild(app.view);
// create viewport
const viewport = new Viewport({
screenWidth: width,
screenHeight: height,
worldWidth: width * 4,
worldHeight: height * 4,
passiveWheel: false,
interaction: app.renderer.plugins.interaction, // the interaction module is important for wheel to work properly when renderer.view is placed or scaled
});
app.stage.addChild(viewport);
// activate plugins
viewport
.drag()
.pinch()
.wheel()
.decelerate()
.clampZoom({ minWidth: width / 4, minHeight: height / 4 });
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3
.forceLink(links) // This force provides links between nodes
.id((d) => d.id) // This sets the node id accessor to the specified function. If not specified, will default to the index of a node.
.distance(50)
)
.force('charge', d3.forceManyBody().strength(-500)) // This adds repulsion (if it's negative) between nodes.
.force('center', d3.forceCenter(width / 2, height / 2))
.force(
'collision',
d3
.forceCollide()
.radius((d) => d.radius)
.iterations(2)
)
.velocityDecay(0.8);
/*
Implementation
*/
let visualLinks = new PIXI.Graphics();
viewport.addChild(visualLinks);
nodes.forEach((node) => {
const { name, gender } = node;
node.gfx = new PIXI.Graphics();
node.gfx.lineStyle(1, 0xd3d3d3);
node.gfx.beginFill(colorScale(node.id));
node.gfx.drawCircle(0, 0, 24);
node.gfx.endFill();
node.gfx
// events for click
.on('click', (e) => {
if (!dragged) {
e.stopPropagation();
}
dragged = false;
});
viewport.addChild(node.gfx);
node.gfx.interactive = true;
node.gfx.buttonMode = true;
// create hit area, needed for interactivity
node.gfx.hitArea = new PIXI.Circle(0, 0, 24);
// show tooltip when mouse is over node
node.gfx.on('mouseover', (mouseData) => {
addTooltip(
nodeHoverTooltip,
{ name },
mouseData.data.originalEvent.pageX,
mouseData.data.originalEvent.pageY
);
});
// make circle half-transparent when mouse leaves
node.gfx.on('mouseout', () => {
removeTooltip();
});
const text = new PIXI.Text(name, {
fontSize: 12,
fill: '#000',
});
text.anchor.set(0.5);
text.resolution = 2;
node.gfx.addChild(text);
});
const ticked = () => {
nodes.forEach((node) => {
let { x, y, gfx } = node;
gfx.position = new PIXI.Point(x, y);
});
for (let i = visualLinks.children.length - 1; i >= 0; i--) {
visualLinks.children[i].destroy();
}
visualLinks.clear();
visualLinks.removeChildren();
visualLinks.alpha = 1;
links.forEach((link) => {
let { source, target, number } = link;
visualLinks.lineStyle(2, 0xd3d3d3);
visualLinks.moveTo(source.x, source.y);
visualLinks.lineTo(target.x, target.y);
});
visualLinks.endFill();
};
// Listen for tick events to render the nodes as they update in your Canvas or SVG.
simulation.on('tick', ticked);
return {
destroy: () => {
nodes.forEach((node) => {
node.gfx.clear();
});
visualLinks.clear();
},
};
}
addition.js(perform simple addition in web-worker)
const addition = (data) => {
const result = data + 1;
return result;
};
export default addition;
so i perform simple addition using web-worker but now i want to perform simulation and tick function in webWorker and after performing i want to use it in my code to replace complex function because i'm new to web-worker i'm not figure-out how to do that
I just began coding in Phaser 3 after developing some games with p5.js and wanted to make a 2d endless runner game. So here's the code for my game:
var game;
var gameOptions = {
monkeyGravity: 1200,
monkeyPower: 1000
}
window.onload = function() {
let gameConfig = {
type: Phaser.AUTO,
backgroundColor:0x87ceeb,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: 'thegame',
width: 1920,
height: 1080
},
physics: {
default: 'arcade',
arcade: {debug: true}
},
scene: [
startGame,
playGame
]
}
game = new Phaser.Game(gameConfig);
window.focus();
}
class startGame extends Phaser.Scene{
constructor(){
super('StartGame');
}
preload(){
this.load.image('menu-bg', '/jeffrey2nd/menu-bg.png');
this.load.image('play-button', '/jeffrey2nd/play-button.png');
}
create() {
this.menuBg = this.add.sprite(game.config.width / 2, 0, 'menu-bg').setScale(2);
const screenCenterX = this.cameras.main.worldView.x + this.cameras.main.width / 2;
const screenCenterY = this.cameras.main.worldView.y + this.cameras.main.height / 2;
const startButton = this.add.sprite(screenCenterX, screenCenterY, 'play-button');
startButton.setInteractive();
startButton.on('pointerdown', () => this.scene.start('PlayGame'));
}
}
class playGame extends Phaser.Scene{
constructor(){
super('PlayGame');
}
preload(){
this.load.image('background', '/jeffrey2nd/background.png');
this.load.image('backgroundL1', '/jeffrey2nd/backgroundL1.png');
this.load.image('backgroundL2', '/jeffrey2nd/backgroundL2.png');
this.load.image('backgroundL3', '/jeffrey2nd/backgroundL3.png');
this.load.image('backgroundL4', '/jeffrey2nd/backgroundL4.png');
this.load.image('ground', '/jeffrey2nd/ground.png');
//ANIMATIONS
this.load.image('run0', '/jeffrey2nd/animations/monkey/Running_000.png');
this.load.image('run1', '/jeffrey2nd/animations/monkey/Running_001.png');
this.load.image('run2', '/jeffrey2nd/animations/monkey/Running_002.png');
this.load.image('run3', '/jeffrey2nd/animations/monkey/Running_003.png');
this.load.image('run4', '/jeffrey2nd/animations/monkey/Running_004.png');
this.load.image('run5', '/jeffrey2nd/animations/monkey/Running_005.png');
this.load.image('run6', '/jeffrey2nd/animations/monkey/Running_006.png');
this.load.image('run7', '/jeffrey2nd/animations/monkey/Running_007.png');
this.load.image('run8', '/jeffrey2nd/animations/monkey/Running_008.png');
this.load.image('run9', '/jeffrey2nd/animations/monkey/Running_009.png');
this.load.image('run10', '/jeffrey2nd/animations/monkey/Running_010.png');
this.load.image('run11', '/jeffrey2nd/animations/monkey/Running_011.png');
this.load.image('run12', '/jeffrey2nd/animations/monkey/Running_012.png');
this.load.image('run13', '/jeffrey2nd/animations/monkey/Running_013.png');
this.load.image('jump0', '/jeffrey2nd/animations/monkey/Jumping_000.png');
this.load.image('jump1', '/jeffrey2nd/animations/monkey/Jumping_001.png');
this.load.image('jump2', '/jeffrey2nd/animations/monkey/Jumping_002.png');
this.load.image('jump3', '/jeffrey2nd/animations/monkey/Jumping_003.png');
this.load.image('jump4', '/jeffrey2nd/animations/monkey/Jumping_004.png');
}
create(){
//BACKGROUND AND LAYERS
this.bgLs = this.add.group();
this.background = this.bgLs.create(0, game.config.height / 2, 'background');
this.backgroundL1 = this.bgLs.create(0, game.config.height / 2, 'backgroundL1');
this.backgroundL12 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL1');
this.backgroundL2 = this.bgLs.create(0, game.config.height / 2, 'backgroundL2');
this.backgroundL22 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL2');
this.backgroundL3 = this.bgLs.create(0, game.config.height / 2, 'backgroundL3');
this.backgroundL32 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL3');
this.backgroundL4 = this.bgLs.create(0, game.config.height / 2, 'backgroundL4');
this.backgroundL42 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL4');
for (let b of this.bgLs.children.entries) {
b.setOrigin(0, 0.5);
}
//GROUND PLATFORMS
this.groundGroup = this.physics.add.group();
this.ground1 = this.groundGroup.create(0, game.config.height - 50, 'ground');
this.ground2 = this.groundGroup.create(game.config.width, game.config.height - 50, 'ground');
this.ground3 = this.groundGroup.create(game.config.width + game.config.width / 2, game.config.height - 275, 'ground');
this.ground4 = this.groundGroup.create(game.config.width + game.config.width / 1.5, game.config.height - 500, 'ground');
this.ground4.setScale(0.5, 1);
for (let g of this.groundGroup.children.entries) {
g.setOrigin(0, 0.5);
g.setImmovable(true);
g.setScale(1,0.3);
g.body.checkCollision.down = false;
}
//MONKEY
this.monkey = this.physics.add.sprite(game.config.width / 10 * 2, 500, 'run0');
this.monkey.setScale(0.3);
this.anims.create({
key: "player-run",
frames: [
{ key: 'run0' },
{ key: 'run1' },
{ key: 'run2' },
{ key: 'run3' },
{ key: 'run4' },
{ key: 'run5' },
{ key: 'run6' },
{ key: 'run7' },
{ key: 'run8' },
{ key: 'run9' },
{ key: 'run10' },
{ key: 'run11' },
{ key: 'run12' },
{ key: 'run13' }
],
frameRate: 20,
repeat: -1
})
this.anims.create({
key: "player-jump",
frames: [
{ key: 'jump0' },
{ key: 'jump1' },
{ key: 'jump2' },
{ key: 'jump3' },
{ key: 'jump4' }
],
frameRate: 20,
repeat: -1
})
this.monkey.body.setSize(this.monkey.width/2, this.monkey.height/2);
this.input.on('pointerdown', this.jump, this);
this.input.on('pointerup', this.fall, this);
}
update(){
this.backgroundL1.x -= 0.2;
this.backgroundL12.x -= 0.2;
this.backgroundL2.x -= 0.4;
this.backgroundL22.x -= 0.4;
this.backgroundL3.x -= 0.6;
this.backgroundL32.x -= 0.6;
this.backgroundL4.x -= 0.8;
this.backgroundL42.x -= 0.8;
for (let b of this.bgLs.children.entries) {
if (b.x <= -game.config.width) b.setX(game.config.width);
}
var speed = 5;
for (let g of this.groundGroup.children.entries) {
g.setX(g.x-speed);
//if (g.x <= -game.config.width) g.setX(game.config.width);
}
if (this.ground1.x <= -game.config.width) this.ground1.setX(game.config.width);
if (this.ground2.x <= -game.config.width) this.ground2.setX(game.config.width);
if (this.ground3.x <= -game.config.width) {
this.rnd1 = (Phaser.Math.Between(0, 500))/100;
this.ground3.setX(game.config.width + game.config.width / this.rnd1);
}
if (this.ground4.x <= -game.config.width) {
this.rnd2 = (Phaser.Math.Between(0, 500))/100;
this.ground4.setX(game.config.width + game.config.width / this.rnd2);
}
this.physics.world.collide(this.groundGroup, this.monkey, ()=> {console.log('touche' + game.loop.time )}, null, this);
this.monkey.body.gravity.y = gameOptions.monkeyGravity;
if(this.monkey.body.touching.down) this.monkey.anims.play("player-run", true);
else this.monkey.anims.play("player-jump", true);
}
jump(){
if(this.monkey.body.touching.down) {
this.monkey.body.setVelocity(0, -gameOptions.monkeyPower);
this.monkey.anims.stop();
this.monkey.anims.play("player-jump");
}
}
fall(){
if (this.monkey.body.velocity.y < 0) this.monkey.body.setVelocity(0, -100);
}
}
Game start scene has the Start Button, the game begins, the monkey runs on the platforms and you can jump on the upper platforms.
All seems to work fine, but sometimes randomly the monkey falls down off the screen.
You can see a playable version of the bug at https://420videogames.com/jeffrey2nd
Here I added a console log in the 'monkey vs ground goup collide' callback function, logging the game.loop.time to try to understand. My idea was that maybe some frames were missed during Update and the objects did not collide perfectly, but when the monkey falls off, the callback function runs 2 times and then the monkey keeps falling and the game breaks up.
Another strange thing about this issue is that on my mobile phone REDMI8 the game works with no problems, as for the iPhone8 of my GF. On Firefox mobile of another friend, by the way, the game has the same PC issue.
Thank you in advance for your attention, hope someone can help me fix this problem,
Ab
The issue was resolved moving the colliders from Update function to Create function.
I would like to ask whether does easeljs has performance issue for many sprite class objects? It seems that from my codepen demo, its terribly lagging...below's code as follows:
var $window = $(window),
wh = $window.innerHeight(),
ww = $window.innerWidth();
var stage = new createjs.Stage("sceneStage");
var w, h, drone;
var runnerSprite2, runnerContainer, drone2, droneContainer, robot;
var robot__movement_speed = 1;
var building_right, building_left;
var queue = new createjs.LoadQueue(),
$state = $('#state'),
$progress = $('#progress'),
$progressbar = $('#progressbar .bar');
queue.on('complete', onComplete);
queue.on('error', onError);
queue.on('fileload', onFileLoad);
queue.on('fileprogress', onFileProgress);
queue.on('progress', onProgress);
queue.loadManifest([
{
id: '2',
src: 'images/sprite_robot_test_plus_toss.png'
},
{
id: '3',
src: 'images/Drones-Hovering-Loop-12fps.png'
},
{
id: '4',
src: 'images/sprite_robot_plus_toss.png'
},
{
id: '5',
src: 'images/sprite_protestor.png'
}
]);
function onComplete(event) {
console.log('Complete', event);
$state.text( $state.text() + '[All loaded]' );
$progressbar.addClass('complete');
$('#mainContainer').addClass('hide');
$('#drone').removeClass('hidden');
loadScenes();
}
function onError(event) {
console.log('Error', event);
$state.text( $state.text() + '[' + event + ' errored] ');
}
function onFileLoad(event) {
console.log('File loaded', event);
$state.text( $state.text() + '[' + event.item.id + ' loaded] ');
}
function onFileProgress(event) {
console.log('File progress', event);
}
function onProgress(event) {
var progress = Math.round(event.loaded * 100);
console.log('General progress', Math.round(event.loaded) * 100, event);
$progress.text(progress + '%');
$progressbar.css({
'width': progress + '%'
});
}
function loadScenes() {
// grab canvas width and height for later calculations:
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
w = stage.canvas.width;
h = stage.canvas.height;
//----- Drones --------//
var data = new createjs.SpriteSheet({
"images": ["images/Drones-Hovering-Loop-12fps.png"],
"frames": {"regX": 0, "height": 262, "count": 25, "regY": 0, "width": 250},
"animations": {
"idle": [0, 24],
"stun": [0, 0]
},
framerate: 24
});
drone = new createjs.Sprite(data, "idle");
drone.setBounds(null, null, 250, 262);
drone.y = h - drone.getBounds().height;
drone.x = w - drone.getBounds().width;
building_right = drone;
var drone_left = new createjs.Sprite(data, "stun");
drone_left.setBounds(null, null, 250, 262);
drone_left.regX = 250;
drone_left.y = h - drone_left.getBounds().height;
drone_left.x = drone_left.regX;
building_left = drone_left;
droneContainer = new createjs.Container();
droneContainer.addChild(drone, drone_left);
stage.addChild(droneContainer, runnerContainer);
var robot_walk_left_arry = [],
robot_walk_right_arry = [];
for(var i = 14; i< 50; i++) {
robot_walk_left_arry.push(i);
}
for(var i = 49; i > 13; i--) {
robot_walk_right_arry.push(i);
}
console.log(robot_walk_right_arry);
var robot_data = new createjs.SpriteSheet({
"images": ["images/sprite_robot_test_plus_toss.png"],
"frames": {"regX": 0, "height": 540, "count": 83, "regY": 0, "width": 810},
"animations": {
idle: {
frames: [0,1,2,3,4,5,6,7,8,9,10,11,12,11,10,9,8,7,6,5,4,3,2,1]
},
walk_left: {
frames: robot_walk_left_arry,
speed: 1 * robot__movement_speed
},
walk_right: {
frames: robot_walk_right_arry,
speed: 1 * robot__movement_speed
},
toss_left: [50, 82, "idle", 0.8 * robot__movement_speed]
},
framerate: 24
});
robot = new createjs.Sprite(robot_data, "idle");
robot.setBounds(null, null, 810, 540);
robot.regX = 405;
robot.x = (w - robot.getBounds().width);
robot.y = h - robot.getBounds().height;
robot._body_dimen = 162;
stage.addChild(robot);
var protestor_data = new createjs.SpriteSheet({
"images": ["images/sprite_protestor.png"],
"frames": {"regX": 0, "height": 216, "count": 39, "regY": 0, "width": 384},
"animations": {
idle: {
frames: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1]
},
recovery: [33, 38, "idle", 1],
nudge: [15,33, "recovery", 1]
},
framerate: 24
});
var protestor = new createjs.Sprite(protestor_data, "idle");
protestor.setBounds(null, null, 384, 216);
protestor.x = 200;
protestor.y = h - protestor.getBounds().height;
stage.addChild(protestor);
drone_left.on("click", function() {
tweenthis(robot, robot.x, "left");
});
drone.on("click", function() {
tweenthis(robot, robot.x, "right");
});
createjs.Ticker.framerate = 30;
createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.addEventListener("tick", tick);
// createjs.Ticker.on("tick", stage);
}
function handleClick(evt, data) {
console.log('test');
}
function tick(event) {
stage.update(event);
}
Generally I just create 4 sprite classes with 3 different sprite images. But didn't expect it to be running so lagging.
The protestors image seems to be 8k x 8k pixel in size (with only the top part filled apparently)... That's about 192 MB unpacked... That will bring down any engine... Make sure your animation images are more efficiently packed and of a more reasonable size...