Related
Is there a way to achieve the effect of mouse hover like on the website below:
https://studiomaertens.com/about
if you hover on the Work or About link, there is a magnetic effect on it as well as the cursor automatically scales and positions itself in the center with the link,
So far I've managed to combine two different examples together, the magnetic effect works but the cursor doesn't align properly with the icons
https://codepen.io/pen/?template=mdPmPbK
<main>
<div>
<button class="cerchio" >
<ion-icon name="logo-facebook"></ion-icon>
</button>
</div>
<button>
<ion-icon name="logo-twitter"></ion-icon>
</button>
</main>
<div class="cursor cursor--large"></div>
<div class="cursor cursor--small"></div>
var cerchio = document.querySelectorAll('.cerchio');
cerchio.forEach(function(elem){
$(document).on('mousemove touch', function(e){
magnetize(elem, e);
});
})
function magnetize(el, e){
var mX = e.pageX,
mY = e.pageY;
const item = $(el);
const customDist = item.data('dist') * 20 || 120;
const centerX = item.offset().left + (item.width()/2);
const centerY = item.offset().top + (item.height()/2);
var deltaX = Math.floor((centerX - mX)) * -0.45;
var deltaY = Math.floor((centerY - mY)) * -0.45;
var distance = calculateDistance(item, mX, mY);
if(distance < customDist){
TweenMax.to(item, 0.5, {y: deltaY, x: deltaX, scale:1.1});
item.addClass('magnet');
}
else {
TweenMax.to(item, 0.6, {y: 0, x: 0, scale:1});
item.removeClass('magnet');
}
}
function calculateDistance(elem, mouseX, mouseY) {
return Math.floor(Math.sqrt(Math.pow(mouseX - (elem.offset().left+(elem.width()/2)), 2) + Math.pow(mouseY - (elem.offset().top+(elem.height()/2)), 2)));
}
/*- MOUSE STICKY -*/
function lerp(a, b, n) {
return (1 - n) * a + n * b
}
// Inizio Cursor
class Cursor {
constructor() {
this.bind()
//seleziono la classe del cursore
this.cursor = document.querySelector('.js-cursor')
this.mouseCurrent = {
x: 0,
y: 0
}
this.mouseLast = {
x: this.mouseCurrent.x,
y: this.mouseCurrent.y
}
this.rAF = undefined
}
bind() {
['getMousePosition', 'run'].forEach((fn) => this[fn] = this[fn].bind(this))
}
getMousePosition(e) {
this.mouseCurrent = {
x: e.clientX,
y: e.clientY
}
}
run() {
this.mouseLast.x = lerp(this.mouseLast.x, this.mouseCurrent.x, 0.2)
this.mouseLast.y = lerp(this.mouseLast.y, this.mouseCurrent.y, 0.2)
this.mouseLast.x = Math.floor(this.mouseLast.x * 100) / 100
this.mouseLast.y = Math.floor(this.mouseLast.y * 100) / 100
this.cursor.style.transform = `translate3d(${this.mouseLast.x}px, ${this.mouseLast.y}px, 0)`
this.rAF = requestAnimationFrame(this.run)
}
requestAnimationFrame() {
this.rAF = requestAnimationFrame(this.run)
}
addEvents() {
window.addEventListener('mousemove', this.getMousePosition, false)
}
on() {
this.addEvents()
this.requestAnimationFrame()
}
init() {
this.on()
}
}
const cursor = new Cursor()
cursor.init();
Might there be a way to make a similar effect on the Studiomaertens website above?
Kindly let me know
Thank you
To align the cursor in center use
.cursor{
transform: translate(-50%,-50%);
}
With konvajs I'm having problems to render many objects, more than 1000. I already tried all performance tips they mentioned but stills seems to be a bit slow. Then I made this basic comparison and I have these numbers. Should I migrate my code to fabricjs?. Improvements and suggestions are please welcome!!
I took that code and customized a little: https://github.com/jonobr1/two.js/issues/237
(function() {
fabric.Object.prototype.transparentCorners = false;
// this.__canvases = [];
//
// General parameters\
//
const objectsNumber = 1000;
const objectsRadius = 15;
const canvasWidth = 390;
const canvasHeight = 390;
var i, dot, circle,
t1, t2,
// only to have
startTimer = function() {
t1 = new Date().getTime();
return t1;
},
stopTimer = function() {
t2 = new Date().getTime();
return t2 - t1;
},
// getRandomInt = fabric.util.getRandomInt,
rainbow = ["#ffcc66", "#ccff66", "#66ccff", "#ff6fcf", "#ff6666"],
rainbowEnd = rainbow.length - 1;
//
// Rendering canvas #1 twojs
//
var elem = document.getElementById('c1');
var two = new Two({
width: 390,
height: 390
}).appendTo(elem);
results1 = document.getElementById('results-c1');
startTimer();
for (i = 1000; i >= 0; i--) {
circle = two.makeCircle(Math.floor(Math.random() * 400) + 0, Math.floor(Math.random() * 350) + 0, objectsRadius);
circle.fill = rainbow[Math.floor(Math.random() * rainbowEnd) + 0];
circle.noStroke();
circle.opacity = 0.75;
}
two.update();
results1.innerHTML = 'Twojs rendering of 1000 elements in ' + stopTimer() + 'ms';
//
// Rendering canvas #2
//
var canvas2 = new fabric.Canvas('c2', {
backgroundColor: "white",
renderOnAddRemove: false
});
canvas2.setHeight(390);
canvas2.setWidth(390);
var results2 = document.getElementById('results-c2');
startTimer();
for (i = 1000; i >= 0; i--) {
dot = new fabric.Circle({
left: Math.floor(Math.random() * 400) + 0,
top: Math.floor(Math.random() * 350) + 0,
radius: objectsRadius,
fill: rainbow[Math.floor(Math.random() * rainbowEnd) + 0],
objectCaching: false,
opacity: 0.75
});
canvas2.add(dot);
}
canvas2.renderAll(); // Note, calling renderAll() is important in this case
results2.innerHTML = 'Fabricjs rendering 1000 elements using canvas.renderOnAddRemove = false and objectCaching = false in ' + stopTimer() + 'ms';
// this.__canvases.push(canvas2);
//
// Rendering canvas #3 konvajs
//
var stage = new Konva.Stage({
container: 'c3',
width: 390,
height: 390
});
var layer = new Konva.Layer();
results3 = document.getElementById('results-c3');
startTimer();
for (i = 1000; i >= 0; i--) {
var kcircle = new Konva.Circle({
x: Math.floor(Math.random() * 400) + 0,
y: Math.floor(Math.random() * 350) + 0,
radius: objectsRadius,
fill: rainbow[Math.floor(Math.random() * rainbowEnd) + 0],
draggable: true,
opacity: 0.75
});
layer.add(kcircle);
}
stage.add(layer);
results3.innerHTML = 'Konvajs rendering of 1000 elements in ' + stopTimer() + 'ms';
})();
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.6.0/two.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/3.2.3/konva.min.js"></script>
<div class="row">
<div id="results-c1" class=" col-lg-4"></div>
<div id="results-c2" class=" col-lg-4"></div>
<div id="results-c3" class=" col-lg-4"></div>
</div>
<div class="row">
<div id="c1" class=" col-lg-4"></div>
<canvas id="c2" class=" col-lg-4" width="390" height="390"></canvas>
<div id="c3" class=" col-lg-4"></div>
</div>
I've been trying to make a raphael animation, it's working fine and animating on load as it should but..
I want it to animate AGAIN when clicking a text or button (a div outsite raphael paper).
Raphael Code is here:
window.onload = function () {
var paper = new Raphael(document.getElementById('frivardihouse'), 250, 250);
function round(value, precision) {
var multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
let ltv = 0.6;
let h = 144*ltv;
let y = 86+((1-ltv)*144);
let ltvtxt = round(ltv * 100);
var fillhouse = paper.rect(40.5,230,172.3,0).attr({fill: "#ff6600", stroke: "none"});
var sAnimation = Raphael.animation({ 'width': 172.3, 'height': h, 'x': 40.5, 'y': y, fill: "#ff0066"}, 2000, "backOut")
fillhouse.animate(sAnimation);
var thehouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z").attr({fill: "#ccc", stroke: "none"});
};
I made a fiddle.
I tried normal click functions, but just can't seem to get it to work :( Nothing is happening. Really frustrating!
See fiddle here
Just add the click event to .clickme class with jquery.
$('.clickme').click(function(){
document.getElementById('frivardihouse').innerHTML = '';
onload();
});
Below is the full code
onload = function () {
var paper = new Raphael(document.getElementById('frivardihouse'), 250, 250);
function round(value, precision) {
var multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
let ltv = 0.6;
let h = 144*ltv;
let y = 86+((1-ltv)*144);
let ltvtxt = round(ltv * 100);
var fillhouse = paper.rect(40.5,230,172.3,0).attr({fill: "#ff6600", stroke: "none"});
var sAnimation = Raphael.animation({ 'width': 172.3, 'height': h, 'x': 40.5, 'y': y, fill: "#ff0066"}, 2000, "backOut")
fillhouse.animate(sAnimation);
var thehouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z").attr({fill: "#ccc", stroke: "none"});
};
$('.clickme').click(function(){
document.getElementById('frivardihouse').innerHTML = '';
onload();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="frivardihouse"></div>
<div class="clickme">
CLICK ME AND REPEAT ANIMATION
</div>
Without JQuery yes its possible!
Use dispatchEvent(new Event('load')); to trigger onload event from JS..
var clickEle = document.getElementsByClassName("clickme")[0];
clickEle.addEventListener("click", function() {
document.getElementById("frivardihouse").innerHTML = "";
dispatchEvent(new Event('load'));
});
onload = function() {
var paper = new Raphael(document.getElementById('frivardihouse'), 250, 250);
function round(value, precision) {
var multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
let ltv = 0.6;
let h = 144 * ltv;
let y = 86 + ((1 - ltv) * 144);
let ltvtxt = round(ltv * 100);
var fillhouse = paper.rect(40.5, 230, 172.3, 0).attr({
fill: "#ff6600",
stroke: "none"
});
var sAnimation = Raphael.animation({
'width': 172.3,
'height': h,
'x': 40.5,
'y': y,
fill: "#ff0066"
}, 2000, "backOut")
fillhouse.animate(sAnimation);
var thehouse = paper.path("M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z").attr({
fill: "#ccc",
stroke: "none"
});
};
//Trigger onload event while clicking the element
var clickEle = document.getElementsByClassName("clickme")[0];
clickEle.addEventListener("click", function() {
document.getElementById("frivardihouse").innerHTML = "";
dispatchEvent(new Event('load'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<div id="frivardihouse"></div>
<div class="clickme">
CLICK ME AND REPEAT ANIMATION
</div>
The simplest way to do this is as follows
Call reFill function on the click event
function reFill() {
document.getElementById('frivardihouse').innerHTML = '';
onload();
}
That's it!.
if you are still looking for answer. I would solve a little bit different from the existing ones. Basically I would
not override onload by declaring onload function as global. it is a little bit difficult to follow
separate a method to draw and a method to animate.
in onload I will call draw and get an object back. this object will perform animation.
onClick will call animation method again
animation method will check if the house is already filled. if it is filled then remove the filled element only. Then it will performing to add new fill element with animation. fiddle link to check https://jsfiddle.net/hye0os7f/9/
function round(value, precision) {
const multiplier = Math.pow(10, precision || 0);
return Math.round(value * multiplier) / multiplier;
}
function draw() {
const paper = new Raphael(document.getElementById('frivardihouse'), 250, 250);
const ltv = 0.6;
const h = 144 * ltv;
const y = 86 + (1 - ltv) * 144;
const ltvtxt = round(ltv * 100);
const sAnimation = Raphael.animation(
{
width: 172.3,
height: h,
x: 40.5,
y,
fill: '#ff0066',
},
2000,
'backOut',
);
paper
.path(
'M236.5,80.4L128.9,2.1c-1.6-1.1-3.7-1.1-5.3,0L16.1,80.4c-3.5,2.6-1.7,8.1,2.6,8.1l13,0c-1,2.5-1.5,5.3-1.5,8.2l0,122.7c0,12,9.2,21.7,20.6,21.7l150.9,0c11.4,0,20.6-9.7,20.6-21.7l0-122.7c0-2.9-0.5-5.7-1.5-8.2h13C238.2,88.6,240,83,236.5,80.4z M206.7,104.9l0,106.5c0,9-6.9,16.3-15.5,16.3l-129.9,0c-8.5,0-15.5-7.3-15.5-16.3l0-106.5c0-9,6.9-16.3,15.5-16.3l129.9,0C199.8,88.6,206.7,95.9,206.7,104.9z',
)
.attr({ fill: '#ccc', stroke: 'none' });
let fillhouse = null;
return {
paper,
animateInHouse: () => {
if (fillhouse) {
fillhouse.remove();
}
fillhouse = paper.rect(40.5, 230, 172.3, 0).attr({ fill: '#ff6600', stroke: 'none' });
fillhouse.animate(sAnimation);
},
};
}
let thePaper = null;
const pageOnLoad = function () {
thePaper = draw();
thePaper.animateInHouse();
};
function onRedraw() {
thePaper.animateInHouse();
}
window.onload = pageOnLoad;
In function setupGameData() I have parametars for 2 cars. In first car speed is 3.00 and second car speed is 3.50. If you click on button "Watch race" you can see first car 3.00 is faster than second car 3.50. How to repair code to see 3.50 is faster than 3.00.
/*jslint plusplus: true, sloppy: true, indent: 4 */
(function () {
"use strict";
// this function is strict...
}());
// RequestAnimFrame: a browser API for getting smooth animations
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
// Globals
var canvas = null,
ctx = null,
background = null,
car_sprite = null,
game_data = null,
CAR_WIDTH = 170,
CAR_HEIGHT = 37,
STEP_COUNT_MILLISECONDS = 1000 / 30,
RACE_LENGTH = 20,
RACE_FINISH_LINE_X = 770,
iTime = 0,
iFinishPlace = 1,
random_graph;
function clearCanvas() {
// clear canvas
ctx.clearRect(0, 0, canvas.height, canvas.width);
}
function drawBackground() {
clearCanvas();
ctx.drawImage(background, 0, -400);
loadCarSprite();
}
function loadBackground() {
// Load the timer
background = new Image();
background.src = 'http://www.upslike.net/imgdb/race-scence-f7bf19.png';
background.onload = drawBackground;
}
function setupGameData() {
var json =
{
cars:
[
{
"colour": 'blue',
"x": 0,
"y": 50,
"spritex": 0,
"spritey": 0,
"graph": null,
"step": 77,
"position": null,
"speed": 3.00,
"speed_late": 0.28 },
{
"colour": 'red',
"x": 0,
"y": 110,
"spritex": 0,
"spritey": 37,
"graph": null,
"step": 39,
"position": null,
"speed": 3.50,
"speed_late": 0.48 }
],
graphs:
[
[0,5,10,20,40,60,70],
[0,10,20,30,40,50,60],
[0,20,39,40,50,55,58],
[0,10,20,30,40,50,55],
[0,25,45,47,49,50,52],
[0,10,20,29,38,45,50],
[0,15,20,25,30,40,45],
[0,2,4,8,20,30,40],
[0,5,10,15,20,25,30],
[0,1,3,14,15,22,30],
[0,5,11,14,17,22,25],
[0,20,30,44,67,72,90],
[0,2,7,24,47,52,65],
[0,2,9,20,40,52,70]
]
};
random_graph = Math.floor( Math.random() * json.graphs.length );
return json;
}
function drawCar(car) {
// Draw the car onto the canvas
ctx.drawImage(car_sprite,
car.spritex, car.spritey,
CAR_WIDTH, CAR_HEIGHT,
car.x-70 + car.step, car.y,
CAR_WIDTH, CAR_HEIGHT);
drawText(car);
}
function drawCars() {
var iCarCounter;
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
drawCar(game_data.cars[iCarCounter]);
}
}
function initCar(current_car) {
current_car.graph = random_graph;
}
function initGameState() {
var iCarCounter;
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
initCar(game_data.cars[iCarCounter]);
}
}
function getPositionAtTime(graph_index, percentageElapsed, current_car) {
var graph = game_data.graphs[graph_index],
iNumberOfGraphPoints = graph.length,
iGraphPosition = null,
iFloor = null,
iCeil = null,
p = null;
position = null;
graph = graph.map( function( val, i ) {
if ( i === 0 ) {
return val;
}
var car_speed = undefined === current_car.speed ? 1 : current_car.speed,
car_speed_late = undefined === current_car.speed_late ? car_speed : current_car.speed_late;
return ( i < Math.floor( graph.length / 2 ) ) ? car_speed : car_speed_late;
});
iGraphPosition = (iNumberOfGraphPoints / 100) * percentageElapsed;
iFloor = Math.floor(iGraphPosition);
iCeil = Math.ceil(iGraphPosition);
if(iGraphPosition === iFloor) {
position = graph[iFloor];
} else if(iGraphPosition === iCeil) {
position = graph[iCeil];
} else {
p = (graph[iCeil] - graph[iFloor]) / 100;
position = ((iGraphPosition - iFloor) * 100) * p + graph[iFloor];
}
return position;
}
function redrawRoadSection() {
ctx.drawImage(background, 0, 400, 1000, 200, 0, 0, 1000, 200);
}
function graphPosToScreenPos() {
return (900 / 100) * (position / 60 * 100);
}
function updateDebugWindow() {
// Debug window
var time = document.getElementById('time');
if(time !== null) {
time.value = iTime / 1000;
}
}
function drawText(current_car) {
if(current_car.position !== null) {
ctx.strokeStyle = "black";
ctx.font = "normal 12px Facebook Letter Faces";
ctx.strokeText(current_car.position, RACE_FINISH_LINE_X + current_car.step + 110, current_car.y + 25);
}
}
function moveCar(iCarCounter) {
var current_car = game_data.cars[iCarCounter],
seconds = iTime / 1000,
percentageElapsed = (seconds / RACE_LENGTH) * 100,
a = 20,
velocity = 2,
position = getPositionAtTime(current_car.graph, percentageElapsed,current_car);
if(current_car.x < RACE_FINISH_LINE_X) {
current_car.x = graphPosToScreenPos(position) + (velocity * seconds) + (1/2 * a * Math.pow(seconds, 2));
}
else {
current_car.x = RACE_FINISH_LINE_X;
if(current_car.position === null) {
current_car.position = iFinishPlace++;
}
}
drawCar(current_car);
}
function initCars() {
game_data = setupGameData();
initGameState();
drawCars();
}
function stopLoop() {
iTime = 0;
iFinishPlace = 1;
}
function startRace() {
var iCarCounter;
redrawRoadSection();
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
moveCar(iCarCounter);
}
updateDebugWindow();
if(iFinishPlace > 4) {
stopLoop();
} else {
iTime += STEP_COUNT_MILLISECONDS;
requestAnimFrame(startRace);
}
}
function startLoop() {
stopLoop();
requestAnimFrame(startRace);
}
function loadCarSprite() {
// Load the timer
car_sprite = new Image();
car_sprite.src = 'http://www.upslike.net/imgdb/car-scene-53401b.png';
car_sprite.onload = initCars;
}
function draw() {
// Main entry point got the motion canvas example
canvas = document.getElementById('motion');
// Canvas supported?
if (canvas.getContext) {
ctx = canvas.getContext('2d');
loadBackground();
} else {
alert("Canvas not supported!");
}
}
<script>
window.onload = function() {
draw();
}
</script>
<center><canvas id="motion" width="1000px" height="200px"></canvas></center>
<div style="position: absolute; top: 0px; left:65px;">
<div id="alerter" class="hid">
<input id="loop" onclick="javascript:initCars(); startLoop();" type="button" class="prikaz" value="Watch race">
</div>
</div>
</br>
CodePen
First thing I would do is use console.log in your car movement function to see what speed is, to me it looks like your car speed is being converted to an int instead of a double so your speed 3.50 is 3.00.
Also in your moveCar function you are setting the velocity to 2 and using that in your function, shouldn't you be using your speed variable?
It is also depend on speed late(Json). If you increase blue car 'speed late' then blue car speed is fast. And increase red car 'speed late' then red car speed is fast.
/*jslint plusplus: true, sloppy: true, indent: 4 */
(function () {
"use strict";
// this function is strict...
}());
// RequestAnimFrame: a browser API for getting smooth animations
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
// Globals
var canvas = null,
ctx = null,
background = null,
car_sprite = null,
game_data = null,
CAR_WIDTH = 170,
CAR_HEIGHT = 37,
STEP_COUNT_MILLISECONDS = 1000 / 30,
RACE_LENGTH = 20,
RACE_FINISH_LINE_X = 770,
iTime = 0,
iFinishPlace = 1,
random_graph;
function clearCanvas() {
// clear canvas
ctx.clearRect(0, 0, canvas.height, canvas.width);
}
function drawBackground() {
clearCanvas();
ctx.drawImage(background, 0, -400);
loadCarSprite();
}
function loadBackground() {
// Load the timer
background = new Image();
background.src = 'http://www.upslike.net/imgdb/race-scence-f7bf19.png';
background.onload = drawBackground;
}
function setupGameData() {
var json =
{
cars:
[
{
"colour": 'blue',
"x": 0,
"y": 50,
"spritex": 0,
"spritey": 0,
"graph": null,
"step": 77,
"position": null,
"speed": 3.55,
"speed_late": 1 },
{
"colour": 'red',
"x": 0,
"y": 110,
"spritex": 0,
"spritey": 37,
"graph": null,
"step": 39,
"position": null,
"speed": 3.55,
"speed_late": 19 }
],
graphs:
[
[0,5,10,20,40,60,70],
[0,10,20,30,40,50,60],
[0,20,39,40,50,55,58],
[0,10,20,30,40,50,55],
[0,25,45,47,49,50,52],
[0,10,20,29,38,45,50],
[0,15,20,25,30,40,45],
[0,2,4,8,20,30,40],
[0,5,10,15,20,25,30],
[0,1,3,14,15,22,30],
[0,5,11,14,17,22,25],
[0,20,30,44,67,72,90],
[0,2,7,24,47,52,65],
[0,2,9,20,40,52,70]
]
};
random_graph = Math.floor( Math.random() * json.graphs.length );
return json;
}
function drawCar(car) {
// Draw the car onto the canvas
ctx.drawImage(car_sprite,
car.spritex, car.spritey,
CAR_WIDTH, CAR_HEIGHT,
car.x-70 + car.step, car.y,
CAR_WIDTH, CAR_HEIGHT);
drawText(car);
}
function drawCars() {
var iCarCounter;
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
drawCar(game_data.cars[iCarCounter]);
}
}
function initCar(current_car) {
current_car.graph = random_graph;
}
function initGameState() {
var iCarCounter;
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
initCar(game_data.cars[iCarCounter]);
}
}
function getPositionAtTime(graph_index, percentageElapsed, current_car) {
var graph = game_data.graphs[graph_index],
iNumberOfGraphPoints = graph.length,
iGraphPosition = null,
iFloor = null,
iCeil = null,
p = null;
position = null;
graph = graph.map( function( val, i ) {
if ( i === 0 ) {
return val;
}
var car_speed = undefined === current_car.speed ? 1 : current_car.speed,
car_speed_late = undefined === current_car.speed_late ? car_speed : current_car.speed_late;
return ( i < Math.floor( graph.length / 2 ) ) ? car_speed : car_speed_late;
});
iGraphPosition = (iNumberOfGraphPoints / 100) * percentageElapsed;
iFloor = Math.floor(iGraphPosition);
iCeil = Math.ceil(iGraphPosition);
if(iGraphPosition === iFloor) {
position = graph[iFloor];
} else if(iGraphPosition === iCeil) {
position = graph[iCeil];
} else {
p = (graph[iCeil] - graph[iFloor]) / 100;
position = ((iGraphPosition - iFloor) * 100) * p + graph[iFloor];
}
return position;
}
function redrawRoadSection() {
ctx.drawImage(background, 0, 400, 1000, 200, 0, 0, 1000, 200);
}
function graphPosToScreenPos() {
return (900 / 100) * (position / 60 * 100);
}
function updateDebugWindow() {
// Debug window
var time = document.getElementById('time');
if(time !== null) {
time.value = iTime / 1000;
}
}
function drawText(current_car) {
if(current_car.position !== null) {
ctx.strokeStyle = "black";
ctx.font = "normal 12px Facebook Letter Faces";
ctx.strokeText(current_car.position, RACE_FINISH_LINE_X + current_car.step + 110, current_car.y + 25);
}
}
function moveCar(iCarCounter) {
var current_car = game_data.cars[iCarCounter],
seconds = iTime / 1000,
percentageElapsed = (seconds / RACE_LENGTH) * 100,
a = 20,
velocity = 2,
position = getPositionAtTime(current_car.graph, percentageElapsed,current_car);
if(current_car.x < RACE_FINISH_LINE_X) {
current_car.x = graphPosToScreenPos(position) + (velocity * seconds) + (1/2 * a * Math.pow(seconds, 2));
}
else {
current_car.x = RACE_FINISH_LINE_X;
if(current_car.position === null) {
current_car.position = iFinishPlace++;
}
}
drawCar(current_car);
}
function initCars() {
game_data = setupGameData();
initGameState();
drawCars();
}
function stopLoop() {
iTime = 0;
iFinishPlace = 1;
}
function startRace() {
var iCarCounter;
redrawRoadSection();
for(iCarCounter = 0; iCarCounter < game_data.cars.length; iCarCounter++) {
moveCar(iCarCounter);
}
updateDebugWindow();
if(iFinishPlace > 4) {
stopLoop();
} else {
iTime += STEP_COUNT_MILLISECONDS;
requestAnimFrame(startRace);
}
}
function startLoop() {
stopLoop();
requestAnimFrame(startRace);
}
function loadCarSprite() {
// Load the timer
car_sprite = new Image();
car_sprite.src = 'http://www.upslike.net/imgdb/car-scene-53401b.png';
car_sprite.onload = initCars;
}
function draw() {
// Main entry point got the motion canvas example
canvas = document.getElementById('motion');
// Canvas supported?
if (canvas.getContext) {
ctx = canvas.getContext('2d');
loadBackground();
} else {
alert("Canvas not supported!");
}
}
<script>
window.onload = function() {
draw();
}
</script>
<center><canvas id="motion" width="1000px" height="200px"></canvas></center>
<div style="position: absolute; top: 0px; left:65px;">
<div id="alerter" class="hid">
<input id="loop" onclick="javascript:initCars(); startLoop();" type="button" class="prikaz" value="Watch race">
</div>
</div>
</br>
'speed late':1
'speed_late':19
good luck:
I have a problem with segment spin, in this spin wheel from https://www.sitepoint.com/jquery-wheel-fortune-demo/ demo: http://jsfiddle.net/sNYYD/237/
window.WHEELOFFORTUNE = {
cache: {},
init: function () {
console.log('controller init...');
var _this = this;
this.cache.wheel = $('.wheel');
this.cache.wheelMarker = $('.marker');
this.cache.wheelSpinBtn = $('.wheel'); //im using the wheel as the spin button but simply change this to a button if you want.
//mapping is backwards as wheel spins clockwise //1=win
this.cache.wheelMapping = [400, 120, 80, 750, 150, 300, 60, 175, 500, 125, 75, 1000, 120, 200, 90, 600, 100, 250].reverse();
this.cache.wheelSpinBtn.on('click', function (e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) _this.spin();
});
//reset wheel
this.resetSpin();
//setup prize events
this.prizeEvents();
},
spin: function () {
console.log('spinning wheel');
var _this = this;
// reset wheel
this.resetSpin();
//disable spin button while in progress
this.cache.wheelSpinBtn.addClass('disabled');
/*
Wheel has 10 sections.
Each section is 360/10 = 36deg.
*/
var deg = 1500 + Math.round(Math.random() * 1500),
duration = 6000; //optimal 6 secs
_this.cache.wheelPos = deg;
//transition queuing
//ff bug with easeOutBack
this.cache.wheel.transition({
rotate: '0deg'
}, 0)
.transition({
rotate: deg + 'deg'
}, duration, 'easeOutCubic');
//move marker
_this.cache.wheelMarker.transition({
rotate: '-20deg'
}, 0, 'snap');
//just before wheel finish
setTimeout(function () {
//reset marker
_this.cache.wheelMarker.transition({
rotate: '0deg'
}, 300, 'easeOutQuad');
}, duration - 500);
//wheel finish
setTimeout(function () {
// did it win??!?!?!
var spin = _this.cache.wheelPos,
degrees = spin % 360,
percent = (degrees / 360) * 100,
segment = Math.ceil((percent / 6)), //divided by number of segments
win = _this.cache.wheelMapping[segment - 1]; //zero based array
console.log('spin = ' + spin);
console.log('degrees = ' + degrees);
console.log('percent = ' + percent);
console.log('segment = ' + segment);
console.log('win = ' + win);
//display dialog with slight delay to realise win or not.
setTimeout(function () {
alert('you won '+win+'!');
}, 700);
//re-enable wheel spin
_this.cache.wheelSpinBtn.removeClass('disabled');
}, duration);
},
resetSpin: function () {
this.cache.wheel.transition({
rotate: '0deg'
}, 0);
this.cache.wheelPos = 0;
}
}
window.WHEELOFFORTUNE.init();
I have 18 segments and always the win number is wrong, Is the problem Math.ceil((percent / 6)) or this.cache.wheelPos = 0; ?
Thank you
I've been tempted to vote this question as duplicated...(see link)
I think your code lacks consistency: in one line there is a comment about having 10 segments, in other one you say 6, but it seems you have 18 different segments in your wheel. Fix that part (use constants!) and I think most of your issues will be solved.
UPDATED: The way you calculate the segment is incorrect, changing it with this solves the issue.
//the segment is 18 multiplied by the proportion
segment = Math.ceil((percent *18/100))-1;