Skip to content

Commit 8002c40

Browse files
authored
[fix] Fixed config conflicts when multiple instances are in use
Deep clone the config object to avoid conflicts when multiple netjsongraph.js instances are in use.
1 parent 83935af commit 8002c40

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

src/js/netjsongraph.core.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ class NetJSONGraph {
1010
*/
1111
constructor(JSONParam) {
1212
this.utils = new NetJSONGraphUpdate();
13-
this.config = {...NetJSONGraphDefaultConfig};
13+
// This ensures the of the config is deep-copied, so changes in another instance won't affect it.
14+
this.config = this.utils.deepCopy(NetJSONGraphDefaultConfig);
15+
// Preserve the default CRS after merging because it's a Leaflet instance, not a plain object.
16+
// In setConfig, deepMergeObj would override it, causing it to fall back to the default CRS even
17+
// if explicitly set it to somthing like L.CRS.Simple.
18+
this.config.crs = NetJSONGraphDefaultConfig.crs;
1419
this.JSONParam = this.utils.isArray(JSONParam) ? JSONParam : [JSONParam];
1520
}
1621

src/js/netjsongraph.util.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,21 @@ class NetJSONGraphUtil {
260260
return convertGeojson(geojson);
261261
}
262262

263+
deepCopy(obj) {
264+
if (obj === null || typeof obj !== "object") {
265+
return obj;
266+
}
267+
if (Array.isArray(obj)) {
268+
return obj.map((item) => this.deepCopy(item));
269+
}
270+
const result = {};
271+
const keys = Object.keys(obj);
272+
keys.forEach((key) => {
273+
result[key] = this.deepCopy(obj[key]);
274+
});
275+
return result;
276+
}
277+
263278
/**
264279
* merge two object deeply
265280
*

test/netjsongraph.util.test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,54 @@ describe("makeCluster cluster separation logic", () => {
137137
expect(dist).toBeGreaterThan(4); // clusterRadius/2 = 5, allow some tolerance
138138
});
139139
});
140+
141+
describe("Test utils deepCopy function", () => {
142+
test("creates a deep clone that is independent from the original object", () => {
143+
const util = new NetJSONGraphUtil();
144+
145+
const config = {
146+
render: "map",
147+
mapOptions: {
148+
center: [50, 50],
149+
zoom: 5,
150+
nodeConfig: {label: {offset: [0, -10]}},
151+
},
152+
linkCategories: [
153+
{
154+
name: "down",
155+
linkStyle: {color: "#c92517", width: 5},
156+
},
157+
],
158+
};
159+
160+
const original = config;
161+
const clone = util.deepCopy(original);
162+
163+
expect(clone).not.toBe(original);
164+
expect(clone.mapOptions).not.toBe(original.mapOptions);
165+
expect(clone.linkCategories).not.toBe(original.linkCategories);
166+
167+
clone.render = "graph";
168+
clone.mapOptions.center = [0, 0];
169+
clone.mapOptions.zoom = 10;
170+
clone.linkCategories[0].linkStyle.color = "#000000";
171+
clone.linkCategories.push({
172+
name: "up",
173+
linkStyle: {color: "#00ff00", width: 2},
174+
});
175+
176+
expect(original.render).toBe("map");
177+
expect(clone.render).toBe("graph");
178+
expect(original.mapOptions.center).toEqual([50, 50]);
179+
expect(clone.mapOptions.center).toEqual([0, 0]);
180+
expect(original.mapOptions.zoom).toBe(5);
181+
expect(clone.mapOptions.zoom).toBe(10);
182+
expect(original.linkCategories.length).toBe(1);
183+
expect(clone.linkCategories.length).toBe(2);
184+
expect(original.linkCategories[0].linkStyle.color).toBe("#c92517");
185+
expect(clone.linkCategories[0].linkStyle.color).toBe("#000000");
186+
expect(original.linkCategories[0].name).toBe("down");
187+
expect(clone.linkCategories[0].name).toBe("down");
188+
expect(clone.linkCategories[1].name).toBe("up");
189+
});
190+
});

0 commit comments

Comments
 (0)