Working Example
Angle
Decay
Spread
Element Count
Start Velocity
Page Script
// For full API documentation, including code examples, visit http://wix.to/94BuAAs
let confettiSettings;
let readyTimer = null;
let timeoutCounter = 0;
let ready = false;
let htmlDebugging = false;
$w.onReady(function () {
initConfettiSettings();
clearMessage();
$w('#confettiComponent').onMessage((event) => {
if (event.data && event.data.to === 'Page') {
// Message received
processMessage(event.data.message);
} else {
showMessage("Unknown event "+JSON.stringify(event));
}
});
// Delay ready test
setTimeout(() => {
startReadyTimer();
}, 1000);
});
function startReadyTimer() {
if (timeoutCounter === 0) {
showMessage("Starting Up...");
} else {
showMessage("Timer restart number: "+timeoutCounter);
}
sendConfettiMessage({'action':'ready'});
readyTimer = setTimeout(() => {
timeoutCounter++;
startReadyTimer();
}, 1000);
}
function showMessage(message) {
$w('#messages').text = message;
}
function clearMessage() {
showMessage("");
}
function processMessage(message) {
switch (message.action) {
case 'ready':
clearTimeout(readyTimer);
ready = true;
showMessage("Ready!");
// Disable debugButton_click
sendConfettiMessage({'action':'debugOff'});
//load component settings_click
sendConfettiMessage({'action':'getSettings'});
break;
case 'settings':
{
// We should have a pay load
if (message.payload) {
let settings = message.payload;
// Merge the settings received with the
// local confetti settings
Object.assign(getConfettiSettings(), settings);
updateSettingsSliders();
}
}
break;
default:
showMessage("Unknown Event: "+message.action);
break;
}
}
function sendConfettiMessage(message, to) {
let messageObject = {
'to' : (to?to:'Confetti'),
'from': 'Page',
'message':message
};
$w('#confettiComponent').postMessage(messageObject);
}
function initConfettiSettings() {
confettiSettings = {};
}
function getConfettiSettings() {
if (!confettiSettings) {
initConfettiSettings();
}
return confettiSettings;
}
function updateSettingsSliders() {
let settings = getConfettiSettings();
$w('#angle').value = settings.angle;
$w('#decay').value = settings.decay;
$w('#spread').value = settings.spread;
$w('#elementCount').value = settings.elementCount;
$w('#startVelocity').value = settings.startVelocity;
}
export function settings_click(event) {
if ($w('#settingsBox').isVisible) {
$w('#settingsBox').hide();
$w('#settings').label = "Show Settings";
// Send changed settings
sendConfettiMessage({'action':'setSettings', 'payload':getConfettiSettings()});
} else {
$w('#settingsBox').show();
$w('#settings').label = "Hide Settings";
}
}
export function confetti_click(event) {
sendConfettiMessage({'action':'confetti'});
}
export function angle_change(event) {
getConfettiSettings().angle = $w('#angle').value;
}
export function decay_change(event) {
getConfettiSettings().decay = $w('#decay').value;
}
export function spread_change(event) {
getConfettiSettings().spread = $w('#spread').value;
}
export function elementCount_change(event) {
getConfettiSettings().elementCount = $w('#elementCount').value;
}
export function startVelocity_change(event) {
getConfettiSettings().startVelocity = $w('#startVelocity').value;
}
export function debugButton_click(event) {
if (htmlDebugging) {
sendConfettiMessage({'action':'debugOff'});
$w('#debugButton').label = "Show Debug";
} else {
sendConfettiMessage({'action':'debugOn'});
$w('#debugButton').label = "Hide Debug";
}
htmlDebugging = !htmlDebugging;
}
export function resetSettings_click(event) {
sendConfettiMessage({'action':'resetSettings'});
}
This example shows how to use third party javascript on a Wix page.
The javascript is called confetti and was used as is from its author's, Daniel Lundin, github page here
https://github.com/daniel-lundin/dom-confetti/blob/master/src/main.js
This page has somewhat replicated the example page for this code available here:
https://daniel-lundin.github.io/react-dom-confetti/
The page is structured into three sections:
-
Section 1: This section is the working example of the code used on a Wix page. The code runs in a Wix HTML
component block which is colored grey below this introduction. The buttons perform as follows:
Confetti: Sends a message to the html component which activates the confetti function and will display confetti in the grey box.
Show(Hide) Debug: Sends a message to the html component telling it to show or not show log data. The log data shows how messages received from the page are processed.
Show(Hide) Settings: Reveals a set of sliders that allow confetti configuration to be changed. This is similar to the example page referenced above. When the settings are hidden a message is sent to the html component to update the settings that confetti uses.
Reset Settings: Sends a message to the html component telling it to update to the default start up settings used by the confetti function.
-
Section 2: This section shows the javascript used on the Wix Code Page that drives the interaction with onscreen
controls and communication with the html component. Each function is linked to an on screen menu ( will not be shown on mobile device).
-
Section 3: This section shows the html code used by the Wix html component that drives the interaction with
page code to respond to messages from the wix Page code. It also has the full javascript module (without nodeJs packaging) for confetti described above. Each function is linked to an on screen menu ( will not be shown on mobile device).
HTML Component Code
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: transparent;
}
#log {
background-color: white;
}
</style>
<script>
let pageURL = window.location.href;
let startTimer = null;
let timeoutCounter = 0;
let ready = false;
let initConfettiSettings = {​
angle : 90,
decay : 0.9,
spread : 45,
startVelocity : 45,
elementCount : 50,
};
​
let confettiSettings = Object.assign({}, initConfettiSettings);
window.onmessage = (event) => {
if (event.data &&
event.data.to &&
event.data.from &&
event.data.message) {
log(`HTML Component received a message: ${JSON.stringify(event.data)}`);
// relay message to event lister
if (event.data.to === 'Confetti') {
processMessage(event.data.message);
} else {
log("Message not for me!: " +event.data.message+" to: "+event.data.to+" from: "+event.data.from);
}
} else {
log("Badly formed Message! "+JSON.stringify(event.data));
}
}
function processMessage(message) {
log('processMessage('+JSON.stringify(message)+')');
​
switch (message.action) {
case 'ready':
{
if (!ready) {
// Disable timeout
clearTimeout(startTimer);
ready = true;
log('ready!');
}
// If we receive a ready we will send an ack to close the loop
sendPageMessage({'action':'ready'});
}
break;
case 'setSettings':
updateSettings(message.payload);
break;
case 'getSettings':
getSettings();
break;
case 'resetSettings':
confettiSettings = Object.assign({}, initConfettiSettings);
getSettings();
break;
case 'confetti':
let root = document.getElementById('confettiLauch');
activateConfetti(root);
break;
case 'debugOn':
enableLog();
break;
​
case 'debugOff':
disableLog();
clearLog();
break;
​
default:
log('Unknown Action ['+JSON.stringify(message)+']');
break;
}
}
// send message to the page code
function sendPageMessage(msg, to) {
let messageObject = {
'to' : (to?to:'Page'),
'from': 'Confetti',
'message':msg
};
log("sending message ["+JSON.stringify(messageObject)+"]");
window.parent.postMessage(messageObject, "*");
}
function startup() {
log("Page URL: "+pageURL);
if (timeoutCounter === 0) {
log("Starting Up...");
} else {
log("Timer restart number: "+timeoutCounter);
}
sendPageMessage({'action':'ready'});
startTimer = setTimeout(() => {
timeoutCounter++;
startup();
}, 1000);
}
function log(params) {
document.getElementById('logMessages').innerHTML += '<BR>'+'<B>'+params+'</B>';
}
function enableLog() {
document.getElementById('log').style.visibility = 'visible';
}
function disableLog() {
document.getElementById('log').style.visibility = 'hidden';
}
function clearLog() {
document.getElementById('logMessages').innerHTML = '<H1>Debug Output</H1>';
}
function updateSettings(settings) {
log('updateSettings('+JSON.stringify(settings)+')');
if (settings.hasOwnProperty('angle')) {
setAngle(settings.angle);
}
if (settings.hasOwnProperty('decay')) {
setDecay(settings.decay);
}
if (settings.hasOwnProperty('spread')) {
setSpread(settings.spread);
}
if (settings.hasOwnProperty('startVelocity')) {
setStartVelocity(settings.startVelocity);
}
if (settings.hasOwnProperty('elementCount')) {
setElementCount(settings.elementCount);
}
}
function getSettings() {
log('getSettings()');
log('returning settings<br><p>'+JSON.stringify(confettiSettings)+"</p>");
sendPageMessage({'action':'settings', 'payload':confettiSettings});
}
function setAngle(angle) {
log("setAngle("+angle.toString()+")");
if (angle < 0) {
angle = 0
} else if (angle > 360) {
angle = 360;
}
confettiSettings.angle = angle;
}
function setDecay(decay) {
log("setDecay("+decay.toString()+")");
if (decay < 0.1) {
decay = 0.1
} else if (decay > 1.0) {
decay = 1.0;
}
confettiSettings.decay = decay;
}
function setSpread(spread) {
log("setSpread("+spread.toString()+")");
if (spread < 0) {
spread = 0
} else if (spread > 360) {
spread = 360;
}
confettiSettings.spread = spread;
}
function setStartVelocity(startVelocity) {
log("setStartVelocity("+startVelocity.toString()+")");
if (startVelocity < 1) {
startVelocity = 1
} else if (startVelocity > 100) {
startVelocity = 100;
}
confettiSettings.startVelocity = startVelocity;
}
function setElementCount(elementCount) {
log("setElementCount("+elementCount.toString()+")");
if (elementCount < 1) {
elementCount = 1
} else if (elementCount > 200) {
elementCount = 200;
}
confettiSettings.elementCount = elementCount;
}
function activateConfetti() {
log("activateConfetti...");
log("confettiSettings:<br><p>"+JSON.stringify(confettiSettings)+"</p>");
let confettiLaunchRoot = document.getElementById('confettiLaunch');
confetti(confettiLaunchRoot, confettiSettings);
}
</script>
</head>
<body>
​
<div id="confettiLaunch"></div>
​
<div id="log">
<div id="logMessages"></div>
</div>
​
<script language="javascript">
window.onload = function(e){
startup();
}
</script>
<script id="confettiScript">
const defaultColors = [
'#a864fd',
'#29cdff',
'#78ff44',
'#ff718d',
'#fdff6a'
];
function createElements(root, elementCount, colors) {
return Array
.from({ length: elementCount })
.map((_, index) => {
const element = document.createElement('div');
const color = colors[index % colors.length];
element.style['background-color']= color; // eslint-disable-line space-infix-ops
element.style.width = '10px';
element.style.height = '10px';
element.style.position = 'absolute';
root.appendChild(element);
return element;
});
}
function randomPhysics(angle, spread, startVelocity, random) {
const radAngle = angle * (Math.PI / 180);
const radSpread = spread * (Math.PI / 180);
return {
x: 0,
y: 0,
wobble: random() * 10,
velocity: (startVelocity * 0.5) + (random() * startVelocity),
angle2D: -radAngle + ((0.5 * radSpread) - (random() * radSpread)),
angle3D: -(Math.PI / 4) + (random() * (Math.PI / 2)),
tiltAngle: random() * Math.PI
};
}
function updateFetti(fetti, progress, decay) {
/* eslint-disable no-param-reassign */
fetti.physics.x += Math.cos(fetti.physics.angle2D) * fetti.physics.velocity;
fetti.physics.y += Math.sin(fetti.physics.angle2D) * fetti.physics.velocity;
fetti.physics.z += Math.sin(fetti.physics.angle3D) * fetti.physics.velocity;
fetti.physics.wobble += 0.1;
fetti.physics.velocity *= decay;
fetti.physics.y += 3;
fetti.physics.tiltAngle += 0.1;
const { x, y, tiltAngle, wobble } = fetti.physics;
const wobbleX = x + (10 * Math.cos(wobble));
const wobbleY = y + (10 * Math.sin(wobble));
const transform = `translate3d(${wobbleX}px, ${wobbleY}px, 0) rotate3d(1, 1, 1, ${tiltAngle}rad)`;
fetti.element.style.transform = transform;
fetti.element.style.opacity = 1 - progress;
/* eslint-enable */
}
function animate(root, fettis, decay) {
const totalTicks = 200;
let tick = 0;
function update() {
fettis.forEach((fetti) => updateFetti(fetti, tick / totalTicks, decay));
tick += 1;
if (tick < totalTicks) {
requestAnimationFrame(update);
} else {
fettis.forEach((fetti) => {
if (fetti.element.parentNode === root) {
return root.removeChild(fetti.element);
}
});
}
}
requestAnimationFrame(update);
}
function confetti(root, {
angle = 90,
decay = 0.9,
spread = 45,
startVelocity = 45,
elementCount = 50,
colors = defaultColors,
random = Math.random,
} = {}) {
const elements = createElements(root, elementCount, colors);
const fettis = elements.map((element) => ({
element,
physics: randomPhysics(angle, spread, startVelocity, random)
}));
animate(root, fettis, decay);
}
</script>
</body>
</html>