Dataview plugin snippet showcase

Messing around with chatGPT’s code generation and had it generate a tag-cloud code using only dataviewjs and standard javascript. Took a bit of fiddling and about 4 hours of work but that is much quicker then I could have done this by hand…

Lists all files and tags, except those in the excluded paths. Determines size and color based on filename, number of tags, and word count (ignoring metadata, code blocks, and latex blocks. It also randomizes the order for good effect. Clicking on a file will open the file, clicking on tags does nothing but could be fixed if you feel like it.

const FromStr = `-"00 meta" AND -"50 logs"`;
const filesQuery = dv.pages(FromStr);

async function backlinksQuery(query) {
  const file = query.split('/').pop().split(".").slice(0, -1).join(".");
  return dv.query(
    `
    LIST
    FROM [[${file}]] AND ${FromStr}
    `
  );
}

/* Dataview query to retrieve all tags and their associated .md files */
async function tagsQuery(query) {
  return dv.query(
    `
    LIST
    FROM "${query}"
    where tags != ""
    `);
}

async function tagFilesQuery(query) { 
  return dv.query(
    `
    LIST
    FROM ${FromStr}
    where tags = "${query}"
    `);
}

/* Dataview query to retrieve the number of words in each .md file */
async function wordCountQuery(query) {
  const fs = require('fs');
  const path = require('path');
  const text = fs.readFileSync(path.join(app.vault.adapter.basePath, query), 'utf-8');
    // remove blocks
  const pattern = /---[\s\S]*?---|```[\s\S]*?```|\$[\s\S]*?\$|\$\$[\s\S]*?\$\$/g;
  const cleanedText = text.replace(pattern, '');
  // count words
  return cleanedText.match(/\S+/g).length;
}

/* Function to calculate the font size for each tag based on the number of backlinks and number of words */
function calculateFontSize(backlinks, wordCount) {
  const backlinksWeight = 0.2;
  const wordCountWeight = 0.8;
  const maxFontSize = 24;
  const minFontSize = 8;
  const fontSize = Math.sqrt((backlinks * backlinksWeight) + (wordCount * wordCountWeight)) * 4;
  return Math.round((fontSize / 100) * (maxFontSize - minFontSize) + minFontSize);
}

/* Function to calculate the color for each tag based on its name */
function calculateColor(tagName) {
  if (tagName == null) {return "#FFFFFF";}
  const colors = {
    "red": "#ff6464",
    "orange": "#ffb364",
    "yellow": "#ffd664",
    "green": "#64ff64",
    "blue": "#64bfff",
    "purple": "#b864ff",
    "ruby-red": "#D62E4D",
    "sunny-yellow": "#F6C026",
    "vivid-orange": "#FF6E1F",
    "bright-pink": "#F1478A",
    "electric-blue": "#0F7DC2",
    "deep-purple": "#5B0F91",
    "teal-green": "#007F86",
    "golden-brown": "#AA8F6A",
    "moss-green": "#8BC34A",
    "navy-blue": "#3F51B5",
    "pale-pink": "#F7B1B1",
    "soft-lilac": "#C9A1E9",
    "pastel-green": "#B3E6C3",
    "sky-blue": "#87CEEB",
    "light-gray": "#D3D3D3",
    "chocolate-brown": "#5F4B32",
    "cream-yellow": "#FFFDD0",
    "peach-orange": "#FFCC99",
    "dusty-rose": "#C4A4A4",
    "seafoam-green": "#71BC9C"
  };
  const tagWords = tagName.split(/\W+/g);
  const colorIndex = tagWords.reduce((total, word) => total + word.charCodeAt(0), 0) % Object.keys(colors).length;
  return colors[Object.keys(colors)[colorIndex]];
}

function shuffleArray(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

// tagData.push(fileData)
/* Create the HTML for the tag cloud */
const tagCloudHtml = async () => {
const tags = new Map();
const files = new Map();

/* Add all .md files to the tags map with their backlinks and word count */
Promise.all(filesQuery.map(async (f) => {
  const file = f.file
  const blq = backlinksQuery(file.path)
  const wcq = wordCountQuery(file.path)

  if (file.tags) {
    await Promise.all(file.tags.map(async (tag) => {
      if (!tags.has(tag)) {
        tags.set(tag, { backlinks: 0, wordCount: 0 });
      }
      const tagInfo = tags.get(tag);
      const res = await blq;
      tagInfo.backlinks += res.value.values.length;
      const wc = await wcq;
      tagInfo.wordCount += wc;
    }));
  }

  const fileInfo = { backlinks: 0, wordCount: 0 };
  const res = await blq;
  fileInfo.backlinks = res.value.values.length;
  const wc = await wcq;
  fileInfo.wordCount = wc;
  files.set(file, fileInfo);
}))
.then(() => {
  const data = []
  /* Calculate the font size, color, and shape for each tag */
  tags.forEach((tagInfo, tagName) => {
    const fontSize = calculateFontSize(tagInfo.backlinks, tagInfo.wordCount);
    const color = calculateColor(tagName);
    data.push({ name: `\\${tagName}`, fontSize, color });
  });

  /* Calculate the font size, color, and shape for each file */
  files.forEach((fileInfo, fileName) => {
    if (fileName == null) {return;}
    const fontSize = calculateFontSize(fileInfo.backlinks, fileInfo.wordCount);
    const color = calculateColor(fileName.name);
    data.push({ name: fileName.name, fontSize, color});
  });
 return shuffleArray(data).map((tag) => {
    return `<a class="tag-cloud-anchor" href="obsidian://open?vault=OBSIDIAN-VAULT&file=${encodeURIComponent(tag.name)}" style="font-size:${tag.fontSize}px; background-color: #4444444f; color: ${tag.color};">${tag.name}</a>`;
  }).join("");
}).then(res => dv.paragraph(res))
.catch(error => {
  console.error(error);
});
}
tagCloudHtml()
8 Likes