ramp4-pcar4 / story-ramp

Storytelling with interactive maps using RAMP
MIT License
4 stars 14 forks source link

emit map-created event on map load #456

Closed RyanCoulsonCA closed 1 month ago

RyanCoulsonCA commented 1 month ago

Related Item(s)

Not related to any issue, required for CWS migration.

Changes

With the way we've implemented Storylines, we don't have any direct way of using custom templates within RAMP. The traditional way of doing this would be to instantiate the map using const rInstance = createInstance(...), and then use rInstance returned from the function to register new Vue templates as such rInstance.$element.component('new-component', ...).

Since Storylines is instantiating the maps for us, we don't have access to the rInstance variable. To solve this, I've added a new map-created event which is emitted from the app upon map instantiation that will allow you to register Vue templates on a product host page.

I've also added a customTemplates property to the map panel config so the host page can easily access the custom template names for registration.

Example map config (map0.json, pretend this is an entire map config and not just a layer). Note the custom details template custom.

{ 
  "name": "Project",
  "fixtures": {
    "details": {
      "template": "custom"
    }
  },
  "id": "PP",
  "url": "https://maps-cartes.dev.ec.gc.ca/arcgis/rest/services/CWS_SCF/PriorityPlaces/MapServer/0",
  "layerType": "esri-feature"
}

Example Storylines map panel config:

"panel": {
  "config": "map0.json",
  "type": "map",
  "title": "",
  "customTemplates": ["custom"]
}

Now, in order to register the custom template, you would put something like this on the host page (index-ca-en.html for example):

 document.addEventListener('map-created', (data) => {
  const details = data.detail;

  if (details.customTemplates && details.customTemplates.length > 0) {
    details.customTemplates.forEach((t) => {
      details.rInstance.$element.component(t, {
        props: ['identifyData', 'fields'],
        template: `<div>I am a custom template. Layer name: {{this.identifyData.data['Name']}}</div>`,
        methods: { // any methods you need in the template go here. }
      });
    });
  }
});

Testing

Steps:

  1. Load the demo page and open the developer console. Paste the following code block in. When you scroll down to a map, you should see the console.log print in the console.
document.addEventListener('map-created', (data) => {
    console.log("Hello world!", data);
});

This change is Reviewable

github-actions[bot] commented 1 month ago

Your demo site is ready! 🚀 Visit it here: https://ramp4-pcar4.github.io/story-ramp/expose-rinstance/#/en/00000000-0000-0000-0000-000000000000

james-rae commented 1 month ago

Cool stuff. 🤡 question, does it need to be done on the host page due to the template having methods, which can't be JSON-ified and thus stored in the config definition?

RyanCoulsonCA commented 1 month ago

It's primarily because we can't execute JavaScript within a JSON file, so we wouldn't be able to access the rInstance.$element.component() function that we need to actually register the component.

james-rae commented 1 month ago

we can't execute JavaScript within a JSON file

was thinking in your setupMap method, could do

props.config.realTemplateGutsArray.forEach(template =>
    rInstance.$element.component(keyFromSomewhere, template));

where the entire template is mashed into the config. but I suspect the methods part won't de-serialize since it's not part of JSON spec.

We might be saying the same thing with different words. ALL GOOD.

RyanCoulsonCA commented 1 month ago

Yup I was about to edit my comment. It would work if we just needed templates, but as soon as we want to add custom methods we'd run into issues unless we use our good friend eval which I don't think the GitHub security bot would love very much 🤖