@matdata/yasgui-graph-plugin 1.0.8 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,11 +24,11 @@ A YASGUI plugin for visualizing SPARQL CONSTRUCT and DESCRIBE query results as i
24
24
  ### NPM
25
25
 
26
26
  ```bash
27
- npm install @matdata/yasgui-graph-plugin @zazuko/yasgui vis-network
27
+ npm install @matdata/yasgui-graph-plugin @matdata/yasgui vis-network
28
28
  ```
29
29
 
30
30
  ```javascript
31
- import Yasgui from '@zazuko/yasgui';
31
+ import Yasgui from '@matdata/yasgui';
32
32
  import GraphPlugin from '@matdata/yasgui-graph-plugin';
33
33
 
34
34
  Yasgui.Yasr.registerPlugin('Graph', GraphPlugin);
@@ -40,8 +40,8 @@ const yasgui = new Yasgui(document.getElementById('yasgui'));
40
40
 
41
41
  ```html
42
42
  <!-- YASGUI -->
43
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazuko/yasgui@4/build/yasgui.min.css">
44
- <script src="https://cdn.jsdelivr.net/npm/@zazuko/yasgui@4/build/yasgui.min.js"></script>
43
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@matdata/yasgui@5.0.0/build/yasgui.min.css">
44
+ <script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui@5.0.0/build/yasgui.min.js"></script>
45
45
 
46
46
  <!-- Graph Plugin -->
47
47
  <script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui-graph-plugin/dist/yasgui-graph-plugin.min.js"></script>
@@ -197,8 +197,8 @@ Contributions welcome! Please follow the project constitution (`.specify/memory/
197
197
  ## 🙏 Acknowledgments
198
198
 
199
199
  - Built with [vis-network](https://visjs.github.io/vis-network/) for graph rendering
200
- - Integrates with [YASGUI](https://github.com/zazuko/yasgui) SPARQL editor
201
- - Follows the [yasgui-geo](https://github.com/zazuko/yasgui-geo) plugin pattern
200
+ - Integrates with [YASGUI](https://github.com/matdata/yasgui) SPARQL editor
201
+ - Follows the [yasgui-geo](https://github.com/matdata/yasgui-geo) plugin pattern
202
202
 
203
203
  ## 📊 Project Status
204
204
 
@@ -69,7 +69,7 @@ function truncateLabel(text, maxLength = 50) {
69
69
  }
70
70
 
71
71
  // src/networkConfig.js
72
- function getDefaultNetworkOptions() {
72
+ function getDefaultNetworkOptions(themeColors) {
73
73
  return {
74
74
  autoResize: true,
75
75
  width: "100%",
@@ -100,27 +100,20 @@ function getDefaultNetworkOptions() {
100
100
  },
101
101
  nodes: {
102
102
  shape: "dot",
103
- size: 20,
103
+ size: 10,
104
104
  font: {
105
- size: 14,
106
- color: "#000000",
107
- align: "center",
108
- vadjust: 0,
109
- multi: false
105
+ size: 12,
106
+ color: themeColors.text
110
107
  },
111
- borderWidth: 2,
112
- borderWidthSelected: 3,
113
- labelHighlightBold: true,
114
- fixed: {
115
- x: false,
116
- y: false
117
- }
108
+ borderWidth: 1,
109
+ borderWidthSelected: 2,
110
+ labelHighlightBold: true
118
111
  },
119
112
  edges: {
120
113
  arrows: {
121
114
  to: {
122
115
  enabled: true,
123
- scaleFactor: 0.5
116
+ scaleFactor: 0.6
124
117
  }
125
118
  },
126
119
  smooth: {
@@ -129,7 +122,14 @@ function getDefaultNetworkOptions() {
129
122
  },
130
123
  font: {
131
124
  size: 12,
132
- align: "middle"
125
+ align: "middle",
126
+ color: themeColors.edgeLabel,
127
+ background: themeColors.edgeLabelBackground,
128
+ strokeWidth: 0
129
+ // Remove white outline/halo
130
+ },
131
+ color: {
132
+ color: themeColors.edge
133
133
  }
134
134
  }
135
135
  };
@@ -162,24 +162,24 @@ function parseConstructResults(yasrResults) {
162
162
  }
163
163
 
164
164
  // src/colorUtils.js
165
- function getNodeColor(node, triples) {
165
+ function getNodeColor(node, triples, themeColors) {
166
166
  if (node.uri && node.uri.startsWith("_:")) {
167
- return "#c5c5c5ff";
167
+ return themeColors.blankNode;
168
168
  }
169
169
  if (node.type === "literal") {
170
- return "#a6c8a6ff";
170
+ return themeColors.literal;
171
171
  }
172
172
  const isTypeObject = triples.some(
173
173
  (triple) => triple.predicate === "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" && triple.object.value === node.uri
174
174
  );
175
175
  if (isTypeObject) {
176
- return "#e15b13ff";
176
+ return themeColors.typeObject;
177
177
  }
178
- return "#97C2FC";
178
+ return themeColors.uri;
179
179
  }
180
180
 
181
181
  // src/transformers.js
182
- function createNodeMap(triples, prefixMap) {
182
+ function createNodeMap(triples, prefixMap, themeColors) {
183
183
  const nodeMap = /* @__PURE__ */ new Map();
184
184
  let nodeId = 1;
185
185
  triples.forEach((triple) => {
@@ -190,15 +190,10 @@ function createNodeMap(triples, prefixMap) {
190
190
  id: nodeId++,
191
191
  uri: triple.subject,
192
192
  label,
193
- color: getNodeColor({ uri: triple.subject, type: "uri" }, triples),
193
+ color: getNodeColor({ uri: triple.subject, type: "uri" }, triples, themeColors),
194
194
  type: "uri",
195
195
  fullValue: triple.subject,
196
- title: isBlankNode ? triple.subject : applyPrefix(triple.subject, prefixMap),
197
- font: {
198
- vadjust: -30,
199
- // Position label above the node
200
- align: "center"
201
- }
196
+ title: isBlankNode ? triple.subject : applyPrefix(triple.subject, prefixMap)
202
197
  });
203
198
  }
204
199
  const objValue = triple.object.value;
@@ -225,16 +220,12 @@ function createNodeMap(triples, prefixMap) {
225
220
  label,
226
221
  color: getNodeColor(
227
222
  { uri: objValue, type: isLiteral ? "literal" : "uri" },
228
- triples
223
+ triples,
224
+ themeColors
229
225
  ),
230
226
  type: isLiteral ? "literal" : "uri",
231
227
  fullValue,
232
- title,
233
- font: {
234
- vadjust: -30,
235
- // Position label above the node
236
- align: "center"
237
- }
228
+ title
238
229
  });
239
230
  }
240
231
  });
@@ -264,8 +255,8 @@ function createEdgesArray(triples, nodeMap, prefixMap) {
264
255
  });
265
256
  return edges;
266
257
  }
267
- function triplesToGraph(triples, prefixMap) {
268
- const nodeMap = createNodeMap(triples, prefixMap);
258
+ function triplesToGraph(triples, prefixMap, themeColors) {
259
+ const nodeMap = createNodeMap(triples, prefixMap, themeColors);
269
260
  const edges = createEdgesArray(triples, nodeMap, prefixMap);
270
261
  const nodes = Array.from(nodeMap.values());
271
262
  return { nodes, edges };
@@ -29972,6 +29963,66 @@ Network.prototype.getOptionsFromConfigurator = function() {
29972
29963
  return options;
29973
29964
  };
29974
29965
 
29966
+ // src/themeUtils.js
29967
+ function getCurrentTheme() {
29968
+ return document.documentElement.getAttribute("data-theme") || "light";
29969
+ }
29970
+ function getThemeNodeColors(theme) {
29971
+ if (theme === "dark") {
29972
+ return {
29973
+ uri: "#97C2FC",
29974
+ // Light blue for URIs
29975
+ literal: "#a6c8a6ff",
29976
+ // Light green for literals
29977
+ blankNode: "#888888",
29978
+ // Medium grey for blank nodes (darker than light mode)
29979
+ typeObject: "#e15b13ff",
29980
+ // Orange for rdf:type objects
29981
+ text: "#e0e0e0",
29982
+ // Light text for dark backgrounds
29983
+ edge: "#666666",
29984
+ // Darker edges
29985
+ edgeLabel: "#cccccc",
29986
+ // Lighter edge labels
29987
+ edgeLabelBackground: "rgba(30, 30, 30, 0.8)"
29988
+ // Dark semi-transparent background
29989
+ };
29990
+ }
29991
+ return {
29992
+ uri: "#97C2FC",
29993
+ // Light blue for URIs
29994
+ literal: "#a6c8a6ff",
29995
+ // Light green for literals
29996
+ blankNode: "#c5c5c5ff",
29997
+ // Light grey for blank nodes
29998
+ typeObject: "#e15b13ff",
29999
+ // Orange for rdf:type objects
30000
+ text: "#000000",
30001
+ // Black text
30002
+ edge: "#cccccc",
30003
+ // Light grey edges
30004
+ edgeLabel: "#666666",
30005
+ // Dark grey edge labels
30006
+ edgeLabelBackground: "rgba(255, 255, 255, 0.8)"
30007
+ // Light semi-transparent background
30008
+ };
30009
+ }
30010
+ function watchThemeChanges(callback) {
30011
+ const observer = new MutationObserver((mutations) => {
30012
+ mutations.forEach((mutation) => {
30013
+ if (mutation.attributeName === "data-theme") {
30014
+ const theme = getCurrentTheme();
30015
+ callback(theme);
30016
+ }
30017
+ });
30018
+ });
30019
+ observer.observe(document.documentElement, {
30020
+ attributes: true,
30021
+ attributeFilter: ["data-theme"]
30022
+ });
30023
+ return observer;
30024
+ }
30025
+
29975
30026
  // src/GraphPlugin.js
29976
30027
  function getVisNetwork() {
29977
30028
  return { Network, DataSet };
@@ -29980,6 +30031,8 @@ var GraphPlugin = class {
29980
30031
  constructor(yasr) {
29981
30032
  this.yasr = yasr;
29982
30033
  this.network = null;
30034
+ this.currentTheme = getCurrentTheme();
30035
+ this.themeObserver = null;
29983
30036
  }
29984
30037
  /**
29985
30038
  * Plugin priority (higher = shown first in tabs)
@@ -30022,7 +30075,9 @@ var GraphPlugin = class {
30022
30075
  return;
30023
30076
  }
30024
30077
  const prefixMap = extractPrefixes(this.yasr);
30025
- const { nodes, edges } = triplesToGraph(triples, prefixMap);
30078
+ this.currentTheme = getCurrentTheme();
30079
+ const themeColors = getThemeNodeColors(this.currentTheme);
30080
+ const { nodes, edges } = triplesToGraph(triples, prefixMap, themeColors);
30026
30081
  const container = document.createElement("div");
30027
30082
  container.style.width = "100%";
30028
30083
  container.style.height = "600px";
@@ -30032,7 +30087,11 @@ var GraphPlugin = class {
30032
30087
  const { Network: Network2, DataSet: DataSet2 } = getVisNetwork();
30033
30088
  const nodesDataSet = new DataSet2(nodes);
30034
30089
  const edgesDataSet = new DataSet2(edges);
30035
- const options = getDefaultNetworkOptions();
30090
+ const options = getDefaultNetworkOptions(themeColors);
30091
+ this.nodesDataSet = nodesDataSet;
30092
+ this.edgesDataSet = edgesDataSet;
30093
+ this.triples = triples;
30094
+ this.prefixMap = prefixMap;
30036
30095
  this.network = new Network2(
30037
30096
  container,
30038
30097
  { nodes: nodesDataSet, edges: edgesDataSet },
@@ -30043,6 +30102,11 @@ var GraphPlugin = class {
30043
30102
  this.network.setOptions({ physics: { enabled: true } });
30044
30103
  this.networkReady = true;
30045
30104
  });
30105
+ if (!this.themeObserver) {
30106
+ this.themeObserver = watchThemeChanges((newTheme) => {
30107
+ this.applyTheme(newTheme);
30108
+ });
30109
+ }
30046
30110
  const controls = document.createElement("div");
30047
30111
  controls.style.position = "absolute";
30048
30112
  controls.style.top = "10px";
@@ -30078,16 +30142,57 @@ var GraphPlugin = class {
30078
30142
  this.yasr.resultsEl.innerHTML = '<div style="padding: 20px; color: red;">Error rendering graph. See console for details.</div>';
30079
30143
  }
30080
30144
  }
30145
+ /**
30146
+ * Apply theme to existing network
30147
+ * @param {string} newTheme - 'light' or 'dark'
30148
+ */
30149
+ applyTheme(newTheme) {
30150
+ if (!this.network || !this.nodesDataSet || !this.triples || !this.prefixMap) {
30151
+ return;
30152
+ }
30153
+ this.currentTheme = newTheme;
30154
+ const themeColors = getThemeNodeColors(newTheme);
30155
+ const { nodes, edges } = triplesToGraph(this.triples, this.prefixMap, themeColors);
30156
+ this.nodesDataSet.clear();
30157
+ this.nodesDataSet.add(nodes);
30158
+ this.edgesDataSet.clear();
30159
+ this.edgesDataSet.add(edges);
30160
+ const options = getDefaultNetworkOptions(themeColors);
30161
+ this.network.setOptions(options);
30162
+ }
30081
30163
  /**
30082
30164
  * Get icon for plugin tab
30083
30165
  * @returns {Element} Icon element
30084
30166
  */
30085
30167
  getIcon() {
30086
- const icon = document.createElement("span");
30087
- icon.className = "fas fa-project-diagram";
30168
+ const icon = document.createElement("div");
30088
30169
  icon.setAttribute("aria-label", "Graph visualization");
30170
+ icon.style.display = "inline-flex";
30171
+ icon.style.alignItems = "center";
30172
+ icon.style.justifyContent = "center";
30173
+ icon.innerHTML = `<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
30174
+ <circle cx="3" cy="3" r="2" />
30175
+ <circle cx="13" cy="3" r="2" />
30176
+ <circle cx="8" cy="13" r="2" />
30177
+ <line x1="4.5" y1="4" x2="7" y2="11.5" stroke="currentColor" stroke-width="1.5" />
30178
+ <line x1="11.5" y1="4" x2="9" y2="11.5" stroke="currentColor" stroke-width="1.5" />
30179
+ <line x1="5" y1="3" x2="11" y2="3" stroke="currentColor" stroke-width="1.5" />
30180
+ </svg>`;
30089
30181
  return icon;
30090
30182
  }
30183
+ /**
30184
+ * Cleanup when plugin is destroyed
30185
+ */
30186
+ destroy() {
30187
+ if (this.themeObserver) {
30188
+ this.themeObserver.disconnect();
30189
+ this.themeObserver = null;
30190
+ }
30191
+ if (this.network) {
30192
+ this.network.destroy();
30193
+ this.network = null;
30194
+ }
30195
+ }
30091
30196
  };
30092
30197
  var GraphPlugin_default = GraphPlugin;
30093
30198