dash14 / v-network-graph

An interactive network graph visualization component for Vue 3
https://dash14.github.io/v-network-graph/
MIT License
485 stars 44 forks source link

CSS variables in graph SVG after download #58

Closed Mamiglia closed 2 years ago

Mamiglia commented 2 years ago

I use CSS variables in defineConfigs in order to have a graph with adapting colors. Problem is that when someone downloads the graph as SVG such CSS variables aren't carried over, so the graph looks like this: missing CSS variables

Would it be possible to carry such variables also in the CSS? I did some tests and it appears that if we put them in the 'style' attribute of the main svg tag the colors are corrected

dash14 commented 2 years ago

Hi @Mamiglia,

When displaying a downloaded SVG, color and other attributes need to be completed only within that SVG file. As you have already tried, if the <style> is in the <svg> to be downloaded, it will be applied. This can be accomplished by placing <style> inside the <v-network-graph> tag. An example is shown below. (* The css string is the variable, but you can write it directly in the tag.)

<!-- App.vue -->
<script setup lang="ts">
import { defineConfigs, VNetworkGraphInstance } from "v-network-graph";
import { ref, reactive } from "vue";

const nodes = reactive({
  0: { name: "Node 0" },
  1: { name: "Node 1" },
  2: { name: "Node 2" },
  3: { name: "Node 3" },
});

const edges = reactive({
  edge1: { source: "0", target: "1" },
  edge2: { source: "1", target: "2" },
  edge3: { source: "2", target: "3" },
});

const configs = defineConfigs({
  node: {
    normal: {
      color: "var(--accent)",
    },
    hover: {
      color: "var(--accent-2)",
    },
  },
});

const styles = `
:root {
  --accent: #0000aa;
  --accent-2: #ff8800;
}
`;

const graph = ref<VNetworkGraphInstance>();

function downloadAsSvg() {
  if (!graph.value) return;
  const text = graph.value.getAsSvg();
  const url = URL.createObjectURL(new Blob([text], { type: "octet/stream" }));
  const a = document.createElement("a");
  a.href = url;
  a.download = "network-graph.svg"; // filename to download
  a.click();
  window.URL.revokeObjectURL(url);
}
</script>

<template>
  <div class="graph">
    <v-network-graph
      ref="graph"
      :nodes="nodes"
      :edges="edges"
      :configs="configs"
    >
      <!-- To use CSS within SVG, use <defs>. -->
      <defs>
        <!-- Cannot use <style> directly due to restrictions of Vue. -->
        <component :is="'style'">{{ styles }}}</component>
      </defs>
    </v-network-graph>
    <button @click="downloadAsSvg">Download as SVG</button>
  </div>
</template>

<style>
.graph {
  border: 1px solid #888;
  width: 600px;
  height: 400px;
  margin: 0 auto;
}
</style>

Best Regards,

Mamiglia commented 2 years ago

Thanks for your answer!