Skip to content

[BUG] SVG Post-Processing Not Working in Reading Mode #102

@Mahiron47

Description

@Mahiron47

Summary

The postProcessSvg function, which handles color inversion for dark mode, does not execute in preview mode when rendering TikZ code blocks. This results in unprocessed SVG output that lacks color adjustments

Problem Description

The plugin registers a post-processing function that should invert colors for dark mode (if invertColorsInDarkMode setting is enabled)

Steps to Reproduce

  1. Install the obsidian-tikzjax plugin
  2. Create a tikz code block far enough away from the point where you will switch to Reading mode
  3. Switch to Reading mode
  4. Expected: The colors in the SVG image were inverted for reading in dark mode
  5. Actual: The colors of the SVG image remain the same

Solution Implemented

Added a MutationObserver directly in the registerTikzCodeBlock function to watch for SVG insertion in the specific code block container.

Code Changes

File: main.js (line ~18511)

Before:

registerTikzCodeBlock() {
  this.registerMarkdownCodeBlockProcessor("tikz", (source, el2, ctx) => {
    const script = el2.createEl("script");
    script.setAttribute("type", "text/tikz");
    script.setAttribute("data-show-console", "true");
    script.setText(this.tidyTikzSource(source));
  });
}

After:

registerTikzCodeBlock() {
  this.registerMarkdownCodeBlockProcessor("tikz", (source, el2, ctx) => {
    const script = el2.createEl("script");
    script.setAttribute("type", "text/tikz");
    script.setAttribute("data-show-console", "true");
    script.setText(this.tidyTikzSource(source));
    
    // Add observer for SVG post-processing in preview mode
    const processSvg = (svgElement) => {
      try {
        let svg = svgElement.outerHTML;
        if (this.settings.invertColorsInDarkMode) {
          svg = this.colorSVGinDarkMode(svg);
        }
        svg = this.optimizeSVG(svg);
        const temp = document.createElement('div');
        temp.innerHTML = svg;
        const newSvg = temp.firstChild;
        svgElement.replaceWith(newSvg);
      } catch (error) {
        console.error('Error processing SVG:', error);
      }
    };
    
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeName === 'SVG' || node.tagName === 'svg') {
            processSvg(node);
            observer.disconnect();
          } else if (node.nodeType === 1) {
            // Check child elements
            const svg = node.querySelector('svg');
            if (svg) {
              processSvg(svg);
              observer.disconnect();
            }
          }
        });
      });
    });
    
    observer.observe(el2, { childList: true, subtree: true });
    
    // Fallback: check if SVG already exists
    setTimeout(() => {
      const existingSvg = el2.querySelector('svg');
      if (existingSvg) {
        processSvg(existingSvg);
        observer.disconnect();
      }
    }, 100);
  });
}

Key Improvements

  1. MutationObserver: Watches for SVG insertion directly in the code block container (el2)
  2. processSvg Function: Encapsulates the post-processing logic with error handling
  3. Multiple Detection Paths:
    • Direct SVG node detection (nodeName === 'SVG')
    • Case-insensitive tag check (tagName === 'svg')
    • Child element search for nested SVG
  4. Fallback Timer: Handles race conditions where SVG exists before observer starts
  5. Error Handling: try-catch block prevents crashes and logs issues to console
  6. Clean Disconnection: Observer disconnects after first successful processing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions