"Communication with web pages" not working

Hey guys,

I’m struggling with sending data from a dropdown menu on my “index.html” page to the corresponding playcanvas method.
Hope someone can help me, i’ve been trying for hours now, but im at the end of my rope here…

I followed this tutorial, but i just can’t get it to work:
https://developer.playcanvas.com/en/user-manual/publishing/web/communicating-webpage/

Any help would be highly appreciated, thanks Chris :slight_smile:

What I did:

The index.html file:

<body>
    <script src="__start__.js"></script>
    <script src="__loading__.js"></script>
    <script>	
	 var switchIT = function (ID) 
	 {
		window.switchTo(ID);
	 }
    </script>
	
        <div class="dropdown">
		<button class="dropbtn">Washbasin</button>
		<div class="dropdown-content">
			<a href="#" onMouseDown="return switchIT(1001)">Model Arosa</a>
			<a href="#" onMouseDown="return switchIT(1002)">Model Venice</a>
		</div>
	</div>

In PlayCanvas:

  1. I made an entity “Model Switcher”
  2. added a Script “modelSwitcher” with the following content:
window.switchTo = function(modelID)
{
    var app = pc.Application.getApplication();
	var entity = app.root.findByName("Model Switcher");
		
	entity.script.modelSwitcher.switchTo(modelID);
    	
};



var ModelSwitcher = pc.createScript("modelSwitcher");


// initialize code called once per entity
ModelSwitcher.prototype.initialize = function(entity) {
    
/*        this.app.on("modelID:set", function (modelID) {
        this.switchTo(modelID);
    }, this);*/
    
    console.error("ModelSwitcher initialized!");
};

// update code called every frame
ModelSwitcher.prototype.update = function(dt) {
    
};


ModelSwitcher.prototype.switchTo = function(modelID) {

>>>>  Here comes the switching stuff, but it never gets to this point  <<<<<

};

hi XNA2010, tried too & got

Refused to display ‘https://launch.playcanvas.com/641048?debug=true’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.

in console with iframe & free account, perhaps its the same issue

Hey borbor,

thanks for the info, i will do a test with the iframe setup too. I keep you posted when something new turns up.

cheers, chris

Refer to this page for the iframe setup: Communicating with web page

Hey yaustar,

I just tried it and finally got the iframe version working. I will now try to implement the demo setup in my actual project. Thanks for sharing the demo project!

I’ve just tried this with a self hosted project as well and managed to get the following working:

<!doctype html>
<html>
<head>
    <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no' />
    <meta charset='utf-8'>
    <link rel="stylesheet" type="text/css" href="styles.css">
    <link rel="manifest" href="manifest.json">
    <style></style>
    <title>Communicate when self hosted</title>
    <script src="playcanvas-stable.min.js"></script>
    <script>
        ASSET_PREFIX = "";
        SCRIPT_PREFIX = "";
        SCENE_PATH = "642290.json";
        CONTEXT_OPTIONS = {
            'antialias': true,
            'alpha': false,
            'preserveDrawingBuffer': false,
            'preferWebGl2': true
        };
        SCRIPTS = [ 14301551, 14301544, 14301541, 14301549, 14301554 ];
        CONFIG_FILENAME = "config.json";
        pc.script.legacy = false;
    </script>
</head>
<body>
	<button type="button" onclick="window.someFunction();">Click Me!</button>
    <script src="__start__.js"></script>
    <script src="__loading__.js"></script>
</body>
</html>
window.someFunction = function() {
    var app = pc.Application.getApplication();
    var e = app.root.findByName("CubeModel");
    e.enabled = !e.enabled;
};

Project: https://playcanvas.com/project/575391/overview

Sep-07-2018%2010-37-20

Hi Steven,

thanks for the selfhosted version! The iFrame Version works flawlessly now. But I’ll give this version a try too, just to be sure. :slight_smile:

Nice solution/example @yaustar. Now building upon that notion of communicating between applet and webpage I want to push it further. I want to communicate between the upper and lower JS layers - and also look upon multiple interactive steps.

I have been able to implement a top layer (graphically above the PC applet layer, instead of besides on an htmlpage, as the ‘click me’ above). Here I have made a load CSV-file function by button click … I can maybe show this/my own twist later.

But after my example answers with the parsed and outputtet table CSV-lines, I want to read those lines/table-td’s by a new button-click, that then transfers (or at least reads) the values into the PC applet-layer. I need/want to use a combination of the following methods:

window.handleTable = function() {
   /* var app = pc.Application.getApplication();
    var e = app.root.findByName("CubeModel");
    e.enabled = !e.enabled;*/
    
      var table = document.getElementById('table');
    var items = table.getElementsById('td');
    var val = table.getElementById('point');
    var sum = 0;
    for(var i=0; i<items.length; i++)
        sum += parseInt(val[i].value);
    //var outP = document.getElementById('sum');
    //outP.innerHTML = sum;
};

-> Taken/inspired from http://jsfiddle.net/V6HaA/

And also (combine this with) the bindevents method from https://developer.playcanvas.com/en/tutorials/htmlcss---live-updates/:

// this script can reference html asset as an attribute
// and will live update dom and reattach events to it on html changes
// so that launcher don't need to be refreshed during development
var HtmlHandler = pc.createScript('htmlHandler');

HtmlHandler.attributes.add('html', {type: 'asset', assetType:'html', title: 'HTML Asset'});

HtmlHandler.prototype.initialize = function() {
    // create DIV element
    this.element = document.createElement('div');
    this.element.classList.add('container');

    // append to body
    // can be appended somewhere else
    // it is recommended to have some container element
    // to prevent iOS problems of overfloating elements off the screen
    document.body.appendChild(this.element);

    // asset
    this.asset = null;
    this.assetId = 0;

    this.counter = 0;
};


HtmlHandler.prototype.attachAsset = function(assetId, fn) {
    // remember current assetId
    this.assetId = assetId;

    // might be no asset provided
    if (! this.assetId)
        return fn.call(this);

    // get asset from registry
    var asset = this.app.assets.get(this.assetId);

    // store callback of an asset load event
    var self = this;
    asset._onLoad = function(asset) {
        fn.call(self, asset, asset.resource);
    };

    // subscribe to changes on resource
    asset.on('load', asset._onLoad);
    // callback
    fn.call(this, asset, asset.resource);
    // load asset if not loaded
    this.app.assets.load(asset);
};


HtmlHandler.prototype.template = function(asset, html) {
    // unsubscribe from old asset load event if required
    if (this.asset && this.asset !== asset)
        this.asset.off('load', this.asset._onLoad);

    // remember current asset
    this.asset = asset;

    // template element
    // you can use templating languages with renderers here
    // such as hogan, mustache, handlebars or any other
    this.element.innerHTML = html || '';

    // bind some events to dom of an element
    // it has to be done on each retemplate
    if (html)
        this.bindEvents();
};


HtmlHandler.prototype.bindEvents = function() {
    var self = this;
    // example
    //
    // get button element by class
    var button = this.element.querySelector('.button');
    var counter = this.element.querySelector('.counter');
    // if found
    if (button) {
        // add event listener on `click`
        button.addEventListener('click', function() {
            ++self.counter;
            if (counter)
                counter.textContent = self.counter;
            
            console.log('button clicked');

            // try to find object and change its material diffuse color
            // just for fun purposes
            var obj = pc.app.root.findByName('chamferbox');
            if (obj && obj.model && obj.model.model) {
                var material = obj.model.model.meshInstances[0].material;
                if (material) {
                    material.diffuse.set(Math.random(), Math.random(), Math.random());
                    material.update();
                }
            }
        }, false);
    }

    if (counter)
        counter.textContent = self.counter;
};

HtmlHandler.prototype.update = function (dt) {
    // check for swapped asset
    // if so, then start asset loading and templating
    if (this.assetId !== this.html.id)
        this.attachAsset(this.html.id, this.template);
};

So how to read: the already table-outputtet CSV-values into the PC applet-layer?

I might have found the solution myself … but will, in such case, write some small guidelines/remarks on how in here later.

1 Like