Got bored waiting for FaceBook to add an easy “Panorama Picture Viewer” to their Application.
So to see the pictures myself, I made a small tool for it using MaxCanvas. F12 and dig around to see the code if you need it.
- Click “Next” and “Prev” to scroll through the images
- Hover Over the “Pan” buttons to …. well … “pan” 😎
- Hover Over the image for a zoom box
N.B. as I do not want to re-distribute the images, this is not in the MC examples package and the below is minimally commented ;p
Code
// MaxCanvas Panorama Viewer // Simple Panorama viewer, since facebook has not provided one // // Required to drag MC.js into Intellisense // thanks to https://visualstudiomagazine.com/blogs/tool-tracker/2018/07/use-javascript-code.aspx (Dec 2018) /// <reference path="MC.js" /> // Gamecode is wrapped in .. window.onload = (function () { -- ALL CODE HERE --}); .. so game will start AFTER everything else is loaded window.onload = (function() { // AQUIRE HTML DOM CANVAS REFERENCE // HTML has to have a HTML5 canvas element tagged as "canvas" var c=document.getElementById("canvas"); ////////////////////////// // INITIALISE MC Engine // ////////////////////////// MC.init(c); /////////////////////////// // END OF Initialisation // /////////////////////////// //----------------------------------------------------------------------------- ////////////////////////// // VARIABLE DECLARATION // ////////////////////////// var PV = { // object to hold everything (and so avoid polluting global namespace) // Variables Pan1 : new MC.Picture(), T : new MC.Point(0, 0), B : new MC.Point(0.5, 1), set : false, mod : 0, maxMod: 0, datum: new MC.Point(MC.canvas.midX - 300, MC.canvas.midY - 300), delta : 0.001, current: 0, path: "../Assets/images/panoramas/", files: [ ["Dio01.JPG", "Greek Style Diorama"], ["Dio02.JPG"," Prada Wallpaper"], ["P1.JPG", "1. Busy Pompeii Street 2019"], ["At1.JPG", "2. View from Athens Apartment"], ["Sa1.JPG", "3. Fira Harbour (Santorini)"], ["Sa2.JPG", "4. Santorini Caldera"], ["K1.JPG", "5. Kotor from half way up the walls"], ["M1.JPG", "6. Messina"], ["M2.JPG", "7. Messina"], ["M3.JPG", "8. Messina"], ["Sal1.JPG", "9. Salerno Harbour"], ["A1.JPG", "10. Appledore & Crow Point from Instow Beach"], ["A2.JPG", "11. Estuary from Crow Point"], ["A3.JPG", "12. Braunton Burrows"], ["A4.JPG", "13. Tapeley House Monument View"], ["A5.JPG", "14. Appledore from Instow"] ], // a "hit sprite" to see if zoom is required - will not be rendered win: new MC.Sprite({ type: "rect", size1: 533, size2: 533 }), // GUI setup GUI : new MC.GUI(), Title : new MC.ConBox({ width: 600, height: 60, text: "Title", pos: new MC.Point(MC.canvas.midX, 50) }), Prev : new MC.ConBox({ width: 160, height: 60, text: "< Prev", pos: new MC.Point(90, 50), onClick: function () { PV.change(-1) } }), Next : new MC.ConBox({ width: 160, height: 60, text: "Next >", pos: new MC.Point(MC.canvas.right - 90, 50), onClick: function () { PV.change(1) } }), Left : new MC.ConBox({ width: 160, height: 60, text: "<< pan LEFT (a)", pos: new MC.Point(MC.canvas.midX - 90,MC.canvas.bottom - 50) }), Right : new MC.ConBox({ width: 160, height: 60, text: "(d) pan RIGHT >>", pos: new MC.Point(MC.canvas.midX + 90, MC.canvas.bottom - 50) }), // Methods setUp : function () { PV.Pan1 = new MC.Picture(PV.path + PV.files[PV.current][0]); PV.Title.text = "Loading"; PV.set = false; PV.mod = 0; }, change : function (direction) { // only use 1 and -1 for these calls if (direction === 1 || direction === -1) { PV.current += direction; if (PV.current >= PV.files.length) { PV.current = 0; } if (PV.current < 0) { PV.current = PV.files.length - 1; } PV.setUp(); } } }; PV.GUI.push(PV.Prev, PV.Next, PV.Left, PV.Right); // Add the ConBoxes to the GUI MC.mouse.onClickL = function () { // configure MC.game so it checks the GUI upon Left click down PV.GUI.click(); }; ////////////////////////// // END OF declarations // ////////////////////////// //----------------------------------------------------------------------------- ////////////////////////// // GAME LOOP // ////////////////////////// // Set up for the first time PV.setUp(); // first call, request subsequently made within gameLoop(); function gameLoop() { // ESSENTIAL MAINTAINANCE requestAnimationFrame(gameLoop); // Required so the PC will automatically call the gameLoop again when (1) the screen is ready and (2) the CPU has finished any previous frame calculations MC.game.update(); // Essential to update MC.game to ensure MC.game.deltaTime is available // PHYSICS UPDATE LOOP // Check if Image freshly loaded if (!PV.set && PV.Pan1.loaded) { PV.B.set(600 / PV.Pan1.width, 1); PV.maxMod = 1 - PV.B.x; PV.Title.text = PV.files[PV.current][1]; PV.set = true; } // Navigate as required if (MC.keys.a.down || MC.keys.leftArrow.down || PV.Left.hover) PV.mod = MC.maths.maxOf(0, PV.mod - PV.delta); else if (MC.keys.d.down || MC.keys.rightArrow.down || PV.Right.hover) PV.mod = MC.maths.minOf(PV.maxMod, PV.mod + PV.delta); // NON-PHYSICS UPDATES PV.GUI.update(); // calls update on all ConBoxes in the GUI. Required so they can change colour if the mouse "hovers" over them // RENDER // Stage 1. Clear the canvas MC.draw.clearCanvas("Black"); // Stage 2. Render PV.Pan1.render(new MC.Point(MC.canvas.midX, MC.canvas.midY), 0, 600, 600, PV.T.clone().add(PV.mod, 0), PV.B.clone().add(PV.mod, 0)); // Stage 3. Render GUI PV.Title.render(); // not updated, so no hoverover colour change PV.GUI.render(); // Render zoom box (if required) if (PV.win.hit(MC.game.mouse)) { var centre = MC.mouse.pos.clone().minus(PV.datum).div(600); // 0-1 ratio of where mouse is in picture screen var picpos = new MC.Point(PV.mod + (centre.x * PV.B.x), centre.y); // 0-1 ratio of where on the ACTUAL picture it is var newmod = new MC.Point(0.05 * PV.B.x, 0.05); var NT = picpos.clone().minus(newmod); var NB = picpos.clone().add(newmod); MC.draw.rect(MC.mouse.pos, 202, 202, 0, "Orange"); PV.Pan1.render(MC.game.mouse, 0, 200, 200, NT, NB); }; } }); // EoF