Explanation
I have 2 apps/webpages which use different entry points, lets call them app1 and app2, which are using entry1.js and entry2.js respectively. In both apps, I use modules which are very commun between then, they are stored in a shared folder.
I am using OpenLayers in my project and the concept is that I have a "page 1" and a "page 2" which have lot of things in commun (the map, same feature styles, some layers, same data store logic) but also a lot of things which are different (some layers, the content of the store, the way I use the store to do things).
I currently use a file structure that looks like this:
entry1.js
entry2.js
app1/
map.js
[...]
app2/
map.js
[...]
shared/
pointsLayer.js
store.js
styles.js
[...]
In this example, pointsLayer uses the exact same logic between apps, the exception is the way I get the style for the Points is different.
entry1.js
import './app1/map';
import { togglePoint } from './shared/pointsLayer';
// pointsLayer is used here to bind the togglePoint function to the DOM event
$('.point-checkbox').change(function() {
let $this = $(this);
let eid = $this.data('eid');
togglePoint(eid, $this.is(':checked'));
});
entry2.js
import './app2/map';
import { togglePoint } from './shared/pointsLayer';
// pointsLayer is used here to bind the togglePoint function to the DOM event
$('.another-point-checkbox').change(function() {
// Bind the function to another DOM element than app1
// [...]
togglePoint(eid, $this.is(':checked'));
});
app1/map.js and app2/map.js
// The files looks the same because I only extracted what's relevant for you
import { Map, View } from 'ol';
import pointLayer, { updatePoint } from '../shared/pointsLayer';
const map = new Map({
layers: [pointLayer],
target: 'map',
view: new View([/*...*/])
});
map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)
shared/store.js
// Here I initialise some data that come from the Global Scope
// This module allows me to share data between ES modules
export default {
a: window.a,
b: window.b
};
// In app1, a will be set, b will be undefined
// In app2, a will be undefined, b will be set
// a and b contain information used to set the color of a Feature Style
// That's part of the problem I'm trying to resolve
shared/styles.js
import { Circle, Fill, Stroke, Style, Text } from 'ol/style';
import Store from './store';
function getElementColor(eid) {
// Here
// I need to access Store.a[eid].color when it's app1
// Or access Store.b[eid].color when it's app2
}
function getPointStyle(eid) {
return new Style({
image: new Circle({
fill: new Fill({
color: getElementColor(eid)
}),
radius: 6,
stroke: new Stroke({
color: '#000',
width: 2
})
})
});
}
export { getPointStyle };
shared/pointsLayer.js
import { Feature } from 'ol';
import { Point } from 'ol/geom';
import { Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';
import Styles from './styles';
const points = {};
const source = new VectorSource();
const layer = new VectorLayer({
source: source,
style: new Style(null)
});
export function updatePoint(eid, position) {
// Do stuff to update a point using the provided eid and position
// I call the getPointStyle function from 'shared/styles.js' here
// [...]
points[eid].setStyle(Styles.getPointStyle(eid));
// [...]
}
export function togglePoint(eid, visible) {
// Do stuff to toggle a point visible or not
// Also uses Styles.getPointStyle(eid) to set the corresponding style
}
export default layer;
Problem
My problem is that everything in the shared/pointsLayer file can be used in both apps, but this module depends of another module which do things differently in app1 and app2 to get the color of a Style applied to a Point (see the getElementColor function in shared/styles.js).
I guess I could just make the getElementColor function do something like if (Store.a === undefined) { // I am in app2 } [...] but I'm pretty sure that's not a good way to handle this.
I thought about 2 others ideas, but I am not happy with them either.
Idea 1
- Set Store.app = "app1" in
app1/map.js - Set Store.app = "app2" in
app2/map.js - Check the value of Store.app in the
getElementColorfunction
map.js
import { Map, View } from 'ol';
import pointLayer, { updatePoint } from '../shared/pointsLayer';
// HERE
import Store from '../shared/store';
Store.app = "app1"; // Or "app2"
const map = new Map({
layers: [pointLayer],
target: 'map',
view: new View([/*...*/])
});
map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)
shared/styles.js
// [...]
function getElementColor(eid) {
if (Store.app == 'app1') {
// Access Store.a[eid].color
} else {
// Access Store.b[eid].color
}
}
// [...]
Idea 2
- Add a function to set the "style function" inside
pointsLayermodule - Do not rely anymore on
shared/styles.jsinsidepointsLayermodule - Use the function in
map.js
shared/pointsLayer.js
import { Feature } from 'ol';
import { Point } from 'ol/geom';
import { Vector as VectorSource } from 'ol/source';
import { Vector as VectorLayer } from 'ol/layer';
const points = {};
const source = new VectorSource();
const layer = new VectorLayer({
source: source,
style: new Style(null)
});
// HERE
let getPointColor = () => {};
export function setGetPointColor(fct) {
getPointColor = fct;
}
function getPointStyle(eid) {
return new Style({
image: new Circle({
fill: new Fill({
color: getPointColor(eid)
}),
radius: 6,
stroke: new Stroke({
color: '#000',
width: 2
})
})
});
}
//
export function updatePoint(eid, position) {
// [...]
points[eid].setStyle(getPointStyle(eid));
// [...]
}
export function togglePoint(eid, visible) {
// Also uses getPointStyle(eid) to set the corresponding style
}
export default layer;
app1/map.js and app2/map.js
import { Map, View } from 'ol';
import pointLayer, { updatePoint, setGetPointColor } from '../shared/pointsLayer';
// HERE
setGetPointColor(function(eid) {
let element = Store.a[eid]; // Or Store.b[eid]
if (!element) {
// Log, error, whatever...
return '#000';
}
return element.color;
});
const map = new Map({
layers: [pointLayer],
target: 'map',
view: new View([/*...*/])
});
map.addEventListener /* ... */
// Here, on a specific map event, I call updatePoint(eid, position)
None of these solutions/ideas feel right to me, I'm new in using ES6 and I think maybe I'm missing some important ES module concept?
Your help would be greatly appreciated.