Skip to content

Commit

Permalink
New web worker sample (#96)
Browse files Browse the repository at this point in the history
* initial draft from Shaofeng

* add copyright headers

* rewrites to readme with images

* renaming job variables for clarity

* added UI animation for reference

* small code and comment cleanups

* added correct button icons

* added correct button icons

* update image

* Fixes and cleanup work to readme

* update manifests

* created cleaner localhost references (#97)

Co-authored-by: David Chesnut <davech@microsoft.com>

Co-authored-by: Maarten van Stam <aafvstam@users.noreply.github.com>
  • Loading branch information
davidchesnut and aafvstam committed Dec 28, 2020
1 parent b627c2a commit bd5be63
Show file tree
Hide file tree
Showing 16 changed files with 1,065 additions and 0 deletions.
93 changes: 93 additions & 0 deletions Excel-custom-functions/web-worker/functions-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

self.addEventListener('message',
function(event) {
var job = event.data;
if (typeof(job) == "string") {
job = JSON.parse(job);
}

var jobId = job.jobId;
try {
var result = invokeFunction(job.name, job.parameters);
// check whether the result is a promise.
if (typeof(result) == "function" || typeof(result) == "object" && typeof(result.then) == "function") {
result.then(function(realResult) {
postMessage(
{
jobId: jobId,
result: realResult
}
);
})
.catch(function(ex) {
postMessage(
{
jobId: jobId,
error: true
}
)
});
}
else {
postMessage({
jobId: jobId,
result: result
});
}
}
catch(ex) {
postMessage({
jobId: jobId,
error: true
});
}
}
);

function invokeFunction(name, parameters) {
if (name == "TEST") {
return test.apply(null, parameters);
}
else if (name == "TEST_PROMISE") {
return test_promise.apply(null, parameters);
}
else if (name == "TEST_ERROR") {
return test_error.apply(null, parameters);
}
else if (name == "TEST_ERROR_PROMISE") {
return test_error_promise.apply(null, parameters);
}
else {
throw new Error("not supported");
}
}

function test(n) {
var ret = 0;
for (var i = 0; i < n; i++) {
ret += Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(50))))))))));
for (var l = 0; l < n; l++) {
ret -= Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(50))))))))));
}
}
return ret;
}


function test_promise(n) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(test(n));
}, 1000);
});
}

function test_error(n) {
throw new Error();
}

function test_error_promise(n) {
return Promise.reject(new Error());
}
103 changes: 103 additions & 0 deletions Excel-custom-functions/web-worker/functions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

var SampleNamespace = {};

(function(SampleNamespace) {
// The max number of web workers to be created
var g_maxWebWorkers = 4;

// The array of web workers
var g_webworkers = [];

// Next job id
var g_nextJobId = 0;

// The promise info for the job. It stores the {resolve: resolve, reject: reject} information for the job.
var g_jobIdToPromiseInfoMap = {};

function getOrCreateWebWorker(jobId) {
var index = jobId % g_maxWebWorkers;
if (g_webworkers[index]) {
return g_webworkers[index];
}

// create a new web worker
var webWorker = new Worker("functions-worker.js");
webWorker.addEventListener('message', function(event) {
var jobResult = event.data;
if (typeof(jobResult) == "string") {
jobResult = JSON.parse(jobResult);
}

if (typeof(jobResult.jobId) == "number") {
var jobId = jobResult.jobId;
// get the promise info associated with the job id
var promiseInfo = g_jobIdToPromiseInfoMap[jobId];
if (promiseInfo) {
if (jobResult.error) {
// The web worker returned an error
promiseInfo.reject(new Error());
}
else {
// The web worker returned a result
promiseInfo.resolve(jobResult.result);
}
delete g_jobIdToPromiseInfoMap[jobId];
}
}
});

g_webworkers[index] = webWorker;
return webWorker;
}

// Post a job to the web worker to do the calculation
function dispatchCalculationJob(functionName, parameters) {
var jobId = g_nextJobId++;
return new Promise(function(resolve, reject) {
// store the promise information.
g_jobIdToPromiseInfoMap[jobId] = {resolve: resolve, reject: reject};
var worker = getOrCreateWebWorker(jobId);
worker.postMessage({
jobId: jobId,
name: functionName,
parameters: parameters
});
});
}

SampleNamespace.dispatchCalculationJob = dispatchCalculationJob;
})(SampleNamespace);


CustomFunctions.associate("TEST", function(n) {
return SampleNamespace.dispatchCalculationJob("TEST", [n]);
});

CustomFunctions.associate("TEST_PROMISE", function(n) {
return SampleNamespace.dispatchCalculationJob("TEST_PROMISE", [n]);
});

CustomFunctions.associate("TEST_ERROR", function(n) {
return SampleNamespace.dispatchCalculationJob("TEST_ERROR", [n]);
});

CustomFunctions.associate("TEST_ERROR_PROMISE", function(n) {
return SampleNamespace.dispatchCalculationJob("TEST_ERROR_PROMISE", [n]);
});


// This function will show what happens when calculations are run on the main UI thread.
// The task pane will be blocked until this method completes.
CustomFunctions.associate("TEST_UI_THREAD", function(n) {
var ret = 0;
for (var i = 0; i < n; i++) {
ret += Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(50))))))))));
for (var l = 0; l < n; l++) {
ret -= Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(Math.tan(Math.atan(50))))))))));
}
}
return ret;
});

44 changes: 44 additions & 0 deletions Excel-custom-functions/web-worker/functions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"functions": [
{
"id": "TEST_UI_THREAD",
"parameters": [
{
"name": "n"
}
]
},
{
"id": "TEST",
"parameters": [
{
"name": "n"
}
]
},
{
"id": "TEST_PROMISE",
"parameters": [
{
"name": "n"
}
]
},
{
"id": "TEST_ERROR",
"parameters": [
{
"name": "n"
}
]
},
{
"id": "TEST_ERROR_PROMISE",
"parameters": [
{
"name": "n"
}
]
}
]
}
106 changes: 106 additions & 0 deletions Excel-custom-functions/web-worker/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->

<html>
<head>
<title>Custom functions using WebWorker</title>
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js" type="text/javascript"></script>
<script src="functions.js" type="text/javascript"></script>
<script type="text/javascript">

var ballX = 100;
var ballY = 10;
var ballDirection = 'downRight';

Office.onReady(function() {
animate();
console.log("Office.onReady");
});

function animate() {

setInterval(drawBall, 10);
}

var drawBall = () => {
var canvas = document.getElementById('mycanvas');

if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
moveBall(ctx.canvas.width,ctx.canvas.height);
var radius=20;

ctx.beginPath();
ctx.arc(ballX,ballY,radius,0,2*Math.PI,false);
ctx.fillStyle = 'green';
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = '#003300';
ctx.stroke();
}
}

var moveBall = (width,height) => {
//check for ball collision with context boundaries

if (ballX <= 0) {
if (ballDirection === 'upLeft') {
ballDirection = 'upRight';
} else {
ballDirection = "downRight";
}
}
if (ballY <=0) {
if (ballDirection === 'upLeft') {
ballDirection = 'downLeft';

} else {
ballDirection = "downRight";
}
}
if (ballX >= width) {
if (ballDirection ==='upRight'){
ballDirection = 'upLeft';

} else {
ballDirection = 'downLeft';
}
}
if (ballY >= height) {
if (ballDirection ==='downRight'){
ballDirection = 'upRight';
} else {
ballDirection = 'upLeft';
}
}
switch (ballDirection) {
case 'upRight': {
ballX++;
ballY--;
break;
}
case 'upLeft': {
ballX--;
ballY--;
break;
}
case 'downRight': {
ballX++;
ballY++;
break;
}
case 'downLeft': {
ballX--;
ballY++;
break;
}
}
}

</script>
</head>
<body>
<canvas id = "mycanvas" width = "200" height = "200"></canvas>
</body>
</html>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit bd5be63

Please sign in to comment.