diff --git a/main.ts b/main.ts index b4c7961..8cc379c 100644 --- a/main.ts +++ b/main.ts @@ -351,9 +351,9 @@ class ScGraphItemView extends ItemView { if (Object.keys(this.smartNotes).length === 0) { return; } + this.setupSettingsMenu(); this.setupSVG(); this.addEventListeners(); - this.setupSettingsMenu(); this.watchForNoteChanges(); // Load latest active file if opening view for first time @@ -410,10 +410,10 @@ class ScGraphItemView extends ItemView { const svgGroup = svg.append('g'); - svgGroup.append('g').attr('class', 'links'); - svgGroup.append('g').attr('class', 'node-labels'); - svgGroup.append('g').attr('class', 'link-labels'); - svgGroup.append('g').attr('class', 'nodes'); + svgGroup.append('g').attr('class', 'smart-connections-visualizer-links'); + svgGroup.append('g').attr('class', 'smart-connections-visualizer-node-labels'); + svgGroup.append('g').attr('class', 'smart-connections-visualizer-link-labels'); + svgGroup.append('g').attr('class', 'smart-connections-visualizer-nodes'); this.svgGroup = svgGroup; this.svg = svg; @@ -490,25 +490,25 @@ class ScGraphItemView extends ItemView { } // Use contentEl to create a table container - const tableContainer = this.contentEl.createEl('div', { cls: 'legend-container' }); + const tableContainer = this.contentEl.createEl('div', { cls: 'smart-connections-visualizer-legend-container' }); // Create table header - const header = tableContainer.createEl('div', { cls: 'legend-header' }); + const header = tableContainer.createEl('div', { cls: 'smart-connections-visualizer-legend-header' }); ['Connection Type', 'Count', 'Color'].forEach(headerTitle => { // Assign appropiate class based on column switch(headerTitle) { case "Connection Type": - header.createEl('div', { text: headerTitle, cls: 'variable-col' }); + header.createEl('div', { text: headerTitle, cls: 'smart-connections-visualizer-variable-col' }); break; case "Count": - header.createEl('div', { text: headerTitle, cls: 'count-col' }); + header.createEl('div', { text: headerTitle, cls: 'smart-connections-visualizer-count-col' }); break; case "Color": - header.createEl('div', { text: headerTitle, cls: 'color-col' }); + header.createEl('div', { text: headerTitle, cls: 'smart-connections-visualizer-color-col' }); break; default: - header.createEl('div', { text: headerTitle, cls: 'variable-col' }); + header.createEl('div', { text: headerTitle, cls: 'smart-connections-visualizer-variable-col' }); break } @@ -517,13 +517,13 @@ class ScGraphItemView extends ItemView { // Create rows for each type types.forEach((type, index) => { if (counts[index] > 0) { // Check if the count is greater than zero - const row = tableContainer.createEl('div', { cls: 'legend-row' }); + const row = tableContainer.createEl('div', { cls: 'smart-connections-visualizer-legend-row' }); - row.createEl('div', { text: this.capitalizeFirstLetter(type), cls: 'variable-col' }); - row.createEl('div', { text: `${counts[index]}`, cls: 'count-col' }); + row.createEl('div', { text: this.capitalizeFirstLetter(type), cls: 'smart-connections-visualizer-variable-col' }); + row.createEl('div', { text: `${counts[index]}`, cls: 'smart-connections-visualizer-count-col' }); - const colorCell = row.createEl('div', { cls: 'color-col' }); - const colorPicker = colorCell.createEl('input', { type: 'color', value: colors[type as keyof typeof colors], cls: 'legend-color-picker' }); + const colorCell = row.createEl('div', { cls: 'smart-connections-visualizer-color-col' }); + const colorPicker = colorCell.createEl('input', { type: 'color', value: colors[type as keyof typeof colors], cls: 'smart-connections-visualizer-legend-color-picker' }); colorPicker.addEventListener('change', (e) => this.updateNodeColors(type, (e.target as HTMLInputElement).value)); } @@ -634,30 +634,41 @@ class ScGraphItemView extends ItemView { document.addEventListener('keyup', this.onKeyUp.bind(this)); } + // TODO:: Add back when ready for multiselect onKeyDown(event: any) { - if (event.key === 'Alt' || event.key === 'AltGraph') this.isAltPressed = true; - if (event.key === 'Control') { - this.isCtrlPressed = true; - d3.select('svg').style('cursor', 'crosshair'); - } + // if (event.key === 'Alt' || event.key === 'AltGraph') this.isAltPressed = true; + // if (event.key === 'Control') { + // this.isCtrlPressed = true; + // d3.select('svg').style('cursor', 'crosshair'); + // } } onKeyUp(event: any) { - if (event.key === 'Alt' || event.key === 'AltGraph') this.isAltPressed = false; - if (event.key === 'Control') { - this.isCtrlPressed = false; - d3.select('svg').style('cursor', 'default'); - } + // if (event.key === 'Alt' || event.key === 'AltGraph') this.isAltPressed = false; + // if (event.key === 'Control') { + // this.isCtrlPressed = false; + // d3.select('svg').style('cursor', 'default'); + // } } setupSettingsMenu() { - if (!document.querySelector('.smart-connections-visualizer-settings-icon')) { - this.createSettingsIcon(); - this.createDropdownMenu(); - this.setupAccordionHeaders(); - this.setupSettingsEventListeners(); - } - } + // Remove any existing settings icon and dropdown menu + const existingIcon = this.contentEl.querySelector('.smart-connections-visualizer-settings-icon'); + if (existingIcon) { + existingIcon.remove(); + } + + const existingDropdownMenu = this.contentEl.querySelector('.sc-visualizer-dropdown-menu'); + if (existingDropdownMenu) { + existingDropdownMenu.remove(); + } + + // Create new settings icon and dropdown menu + this.createSettingsIcon(); + this.createDropdownMenu(); + this.setupAccordionHeaders(); + this.setupSettingsEventListeners(); + } createDropdownMenu() { const dropdownMenu = this.contentEl.createEl('div', { cls: 'sc-visualizer-dropdown-menu' }); @@ -665,18 +676,18 @@ class ScGraphItemView extends ItemView { } buildDropdownMenuContent(dropdownMenu: HTMLElement) { - const menuHeader = dropdownMenu.createEl('div', { cls: 'menu-header' }); + const menuHeader = dropdownMenu.createEl('div', { cls: 'smart-connections-visualizer-menu-header' }); // Append the refresh icon created by createRefreshIcon const refreshIcon = this.createRefreshIcon(); - refreshIcon.classList.add('icon'); // Ensure it has the 'icon' class for styling - refreshIcon.setAttribute('id', 'refresh-icon'); // Set the ID for specific styling or selection + refreshIcon.classList.add('smart-connections-visualizer-icon'); // Ensure it has the 'icon' class for styling + refreshIcon.setAttribute('id', 'smart-connections-visualizer-refresh-icon'); // Set the ID for specific styling or selection menuHeader.appendChild(refreshIcon); // Append the new X icon created by createNewXIcon const xIcon = this.createNewXIcon(); - xIcon.classList.add('icon'); // Ensure it has the 'icon' class for styling - xIcon.setAttribute('id', 'close-icon'); // Set the ID for specific styling or selection + xIcon.classList.add('smart-connections-visualizer-icon'); // Ensure it has the 'icon' class for styling + xIcon.setAttribute('id', 'smart-connections-visualizer-close-icon'); // Set the ID for specific styling or selection menuHeader.appendChild(xIcon); this.addAccordionItem(dropdownMenu, 'Filters', this.getFiltersContent.bind(this)); @@ -686,30 +697,30 @@ class ScGraphItemView extends ItemView { addAccordionItem(parent: HTMLElement, title: string, buildContent: (parent: HTMLElement) => void) { - const accordionItem = parent.createEl('div', { cls: 'accordion-item' }); - const header = accordionItem.createEl('div', { cls: 'accordion-header' }); + const accordionItem = parent.createEl('div', { cls: 'smart-connections-visualizer-accordion-item' }); + const header = accordionItem.createEl('div', { cls: 'smart-connections-visualizer-accordion-header' }); - const arrowIcon = header.createEl('span', { cls: 'arrow-icon' }); + const arrowIcon = header.createEl('span', { cls: 'smart-connections-visualizer-arrow-icon' }); arrowIcon.appendChild(this.createRightArrow()); header.createEl('span', { text: title }); - const accordionContent = accordionItem.createEl('div', { cls: 'accordion-content' }); + const accordionContent = accordionItem.createEl('div', { cls: 'smart-connections-visualizer-accordion-content' }); buildContent(accordionContent); } getFiltersContent(parent: HTMLElement) { - const sliderContainer1 = parent.createEl('div', { cls: 'slider-container' }); + const sliderContainer1 = parent.createEl('div', { cls: 'smart-connections-visualizer-slider-container' }); sliderContainer1.createEl('label', { text: `Min relevance: ${(this.relevanceScoreThreshold * 100).toFixed(0)}%`, - attr: { id: 'scoreThresholdLabel', for: 'scoreThreshold' } + attr: { id: 'smart-connections-visualizer-scoreThresholdLabel', for: 'smart-connections-visualizer-scoreThreshold' } }); const relevanceSlider = sliderContainer1.createEl('input', { attr: { type: 'range', - id: 'scoreThreshold', - class: 'slider', + id: 'smart-connections-visualizer-scoreThreshold', + class: 'smart-connections-visualizer-slider', name: 'scoreThreshold', min: '0', max: '0.99', @@ -720,9 +731,9 @@ class ScGraphItemView extends ItemView { // Ensure the slider's value is set after it is appended to the DOM relevanceSlider.value = this.relevanceScoreThreshold.toString(); - parent.createEl('label', { text: 'Connection type:', cls: 'settings-item-content-label' }); + parent.createEl('label', { text: 'Connection type:', cls: 'smart-connections-visualizer-settings-item-content-label' }); - const radioContainer = parent.createEl('div', { cls: 'radio-container' }); + const radioContainer = parent.createEl('div', { cls: 'smart-connections-visualizer-radio-container' }); const radioBlockLabel = radioContainer.createEl('label'); const blockRadio = radioBlockLabel.createEl('input', { @@ -761,34 +772,34 @@ class ScGraphItemView extends ItemView { getDisplayContent(parent: HTMLElement) { const displaySettings = [ - { id: 'nodeSize', label: 'Node size', value: this.nodeSize, min: 1, max: 15, step: 0.01 }, - { id: 'maxLabelCharacters', label: 'Max label characters', value: this.maxLabelCharacters, min: 1, max: 50, step: 1 }, - { id: 'linkLabelSize', label: 'Link label size', value: this.linkLabelSize, min: 1, max: 15, step: 0.01 }, - { id: 'nodeLabelSize', label: 'Node label size', value: this.nodeLabelSize, min: 1, max: 26, step: 1 }, - { id: 'minLinkThickness', label: 'Min link thickness', value: this.minLinkThickness, min: 0.1, max: 10, step: 0.01 }, - { id: 'maxLinkThickness', label: 'Max link thickness', value: this.maxLinkThickness, min: 0.1, max: 10, step: 0.01 }, - { id: 'fadeThreshold', label: 'Text fade threshold', value: this.textFadeThreshold, min: 0.1, max: 10, step: 0.01 } + { id: 'smart-connections-visualizer-nodeSize', label: 'Node size', value: this.nodeSize, min: 1, max: 15, step: 0.01 }, + { id: 'smart-connections-visualizer-maxLabelCharacters', label: 'Max label characters', value: this.maxLabelCharacters, min: 1, max: 50, step: 1 }, + { id: 'smart-connections-visualizer-linkLabelSize', label: 'Link label size', value: this.linkLabelSize, min: 1, max: 15, step: 0.01 }, + { id: 'smart-connections-visualizer-nodeLabelSize', label: 'Node label size', value: this.nodeLabelSize, min: 1, max: 26, step: 1 }, + { id: 'smart-connections-visualizer-minLinkThickness', label: 'Min link thickness', value: this.minLinkThickness, min: 0.1, max: 10, step: 0.01 }, + { id: 'smart-connections-visualizer-maxLinkThickness', label: 'Max link thickness', value: this.maxLinkThickness, min: 0.1, max: 10, step: 0.01 }, + { id: 'smart-connections-visualizer-fadeThreshold', label: 'Text fade threshold', value: this.textFadeThreshold, min: 0.1, max: 10, step: 0.01 } ]; displaySettings.forEach(setting => { - const sliderContainer = parent.createEl('div', { cls: 'slider-container' }); + const sliderContainer = parent.createEl('div', { cls: 'smart-connections-visualizer-slider-container' }); sliderContainer.createEl('label', { text: `${setting.label}: ${setting.value}`, attr: { id: `${setting.id}Label`, for: setting.id } }); - sliderContainer.createEl('input', { attr: { type: 'range', id: setting.id, class: 'slider', name: setting.id, min: `${setting.min}`, max: `${setting.max}`, value: `${setting.value}`, step: `${setting.step}` } }); + sliderContainer.createEl('input', { attr: { type: 'range', id: setting.id, class: 'smart-connections-visualizer-slider', name: setting.id, min: `${setting.min}`, max: `${setting.max}`, value: `${setting.value}`, step: `${setting.step}` } }); }); } getForcesContent(parent: HTMLElement) { const forcesSettings = [ - { id: 'repelForce', label: 'Repel force', value: this.repelForce, min: 0, max: 1500, step: 1 }, - { id: 'linkForce', label: 'Link force', value: this.linkForce, min: 0, max: 1, step: 0.01 }, - { id: 'linkDistance', label: 'Link distance', value: this.linkDistance, min: 10, max: 200, step: 1 } + { id: 'smart-connections-visualizer-repelForce', label: 'Repel force', value: this.repelForce, min: 0, max: 1500, step: 1 }, + { id: 'smart-connections-visualizer-linkForce', label: 'Link force', value: this.linkForce, min: 0, max: 1, step: 0.01 }, + { id: 'smart-connections-visualizer-linkDistance', label: 'Link distance', value: this.linkDistance, min: 10, max: 200, step: 1 } ]; forcesSettings.forEach(setting => { - const sliderContainer = parent.createEl('div', { cls: 'slider-container' }); + const sliderContainer = parent.createEl('div', { cls: 'smart-connections-visualizer-slider-container' }); sliderContainer.createEl('label', { text: `${setting.label}: ${setting.value}`, attr: { id: `${setting.id}Label`, for: setting.id } }); - sliderContainer.createEl('input', { attr: { type: 'range', id: setting.id, class: 'slider', name: setting.id, min: `${setting.min}`, max: `${setting.max}`, value: `${setting.value}`, step: `${setting.step}` } }); + sliderContainer.createEl('input', { attr: { type: 'range', id: setting.id, class: 'smart-connections-visualizer-slider', name: setting.id, min: `${setting.min}`, max: `${setting.max}`, value: `${setting.value}`, step: `${setting.step}` } }); }); } @@ -806,13 +817,13 @@ class ScGraphItemView extends ItemView { setupAccordionHeaders() { - const accordionHeaders = document.querySelectorAll('.accordion-header'); + const accordionHeaders = document.querySelectorAll('.smart-connections-visualizer-accordion-header'); accordionHeaders.forEach(header => header.addEventListener('click', this.toggleAccordionContent.bind(this))); } toggleAccordionContent(event: any) { const content = event.currentTarget.nextElementSibling; - const arrowIcon = event.currentTarget.querySelector('.arrow-icon'); + const arrowIcon = event.currentTarget.querySelector('.smart-connections-visualizer-arrow-icon'); if (content && arrowIcon) { content.classList.toggle('show'); arrowIcon.innerHTML = ''; // Clear current content @@ -822,7 +833,7 @@ class ScGraphItemView extends ItemView { createDropdownArrow() { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - svg.setAttribute("class", "dropdown-indicator"); + svg.setAttribute("class", "smart-connections-visualizer-dropdown-indicator"); svg.setAttribute("viewBox", "0 0 16 16"); svg.setAttribute("fill", "currentColor"); @@ -836,7 +847,7 @@ class ScGraphItemView extends ItemView { createRightArrow() { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - svg.setAttribute("class", "dropdown-indicator"); + svg.setAttribute("class", "smart-connections-visualizer-dropdown-indicator"); svg.setAttribute("viewBox", "0 0 16 16"); svg.setAttribute("fill", "currentColor"); @@ -865,7 +876,7 @@ class ScGraphItemView extends ItemView { svg.setAttribute("stroke-width", "2"); svg.setAttribute("stroke-linecap", "round"); svg.setAttribute("stroke-linejoin", "round"); - svg.setAttribute("class", "svg-icon lucide-settings"); + svg.setAttribute("class", "smart-connections-visualizer-svg-icon smart-connections-visualizer-lucide-settings"); // Create path element for settings icon const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); @@ -886,7 +897,7 @@ class ScGraphItemView extends ItemView { } createRefreshIcon() { - const refreshIcon = this.contentEl.createEl('div', { cls: 'refresh-icon' }); + const refreshIcon = this.contentEl.createEl('div', { cls: 'smart-connections-visualizer-refresh-icon' }); const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "24"); @@ -897,7 +908,7 @@ class ScGraphItemView extends ItemView { svg.setAttribute("stroke-width", "2"); svg.setAttribute("stroke-linecap", "round"); svg.setAttribute("stroke-linejoin", "round"); - svg.setAttribute("class", "svg-icon lucide-rotate-ccw"); + svg.setAttribute("class", "smart-connections-visualizer-svg-icon smart-connections-visualizer-lucide-rotate-ccw"); const path1 = document.createElementNS("http://www.w3.org/2000/svg", "path"); path1.setAttribute("d", "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"); @@ -913,7 +924,7 @@ class ScGraphItemView extends ItemView { } createNewXIcon() { - const xIcon = this.contentEl.createEl('div', { cls: 'x-icon' }); + const xIcon = this.contentEl.createEl('div', { cls: 'smart-connections-visualizer-x-icon' }); const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "24"); @@ -924,7 +935,7 @@ class ScGraphItemView extends ItemView { svg.setAttribute("stroke-width", "2"); svg.setAttribute("stroke-linecap", "round"); svg.setAttribute("stroke-linejoin", "round"); - svg.setAttribute("class", "svg-icon lucide-x"); + svg.setAttribute("class", "smart-connections-visualizer-svg-icon smart-connections-visualizer-lucide-x"); const path1 = document.createElementNS("http://www.w3.org/2000/svg", "path"); path1.setAttribute("d", "M18 6 6 18"); @@ -959,7 +970,7 @@ class ScGraphItemView extends ItemView { } setupScoreThresholdSlider() { - const scoreThresholdSlider = document.getElementById('scoreThreshold') as HTMLInputElement; + const scoreThresholdSlider = document.getElementById('smart-connections-visualizer-scoreThreshold') as HTMLInputElement; if (scoreThresholdSlider) { scoreThresholdSlider.addEventListener('input', (event) => this.updateScoreThreshold(event)); const debouncedUpdate = debounce((event: Event) => { @@ -971,14 +982,14 @@ class ScGraphItemView extends ItemView { updateScoreThreshold(event: any) { const newScoreThreshold = parseFloat(event.target.value); - const label = document.getElementById('scoreThresholdLabel'); + const label = document.getElementById('smart-connections-visualizer-scoreThresholdLabel'); this.plugin.settings.relevanceScoreThreshold = newScoreThreshold; // Update the settings this.plugin.saveSettings(); // Save the settings if (label) label.textContent = `Min relevance: ${(newScoreThreshold * 100).toFixed(0)}%`; } setupNodeSizeSlider() { - const nodeSizeSlider = document.getElementById('nodeSize') as HTMLInputElement; + const nodeSizeSlider = document.getElementById('smart-connections-visualizer-nodeSize') as HTMLInputElement; if (nodeSizeSlider) { nodeSizeSlider.addEventListener('input', (event) => this.updateNodeSize(event)); } @@ -986,7 +997,7 @@ class ScGraphItemView extends ItemView { updateNodeSize(event: any) { const newNodeSize = parseFloat(event.target.value); - const label = document.getElementById('nodeSizeLabel'); + const label = document.getElementById('smart-connections-visualizer-nodeSizeLabel'); if (label) label.textContent = `Node size: ${newNodeSize}`; this.plugin.settings.nodeSize = newNodeSize; // Update the settings this.plugin.saveSettings(); // Save the settings @@ -995,7 +1006,7 @@ class ScGraphItemView extends ItemView { } setupLineThicknessSlider() { - const lineThicknessSlider = document.getElementById('lineThickness') as HTMLInputElement; + const lineThicknessSlider = document.getElementById('smart-connections-visualizer-lineThickness') as HTMLInputElement; if (lineThicknessSlider) { lineThicknessSlider.addEventListener('input', (event) => this.updateLineThickness(event)); } @@ -1012,7 +1023,7 @@ class ScGraphItemView extends ItemView { } setupCenterForceSlider() { - const centerForceSlider = document.getElementById('centerForce') as HTMLInputElement; + const centerForceSlider = document.getElementById('smart-connections-visualizer-centerForce') as HTMLInputElement; if (centerForceSlider) { centerForceSlider.addEventListener('input', (event) => this.updateCenterForce(event)); } @@ -1029,7 +1040,7 @@ class ScGraphItemView extends ItemView { } setupRepelForceSlider() { - const repelForceSlider = document.getElementById('repelForce') as HTMLInputElement; + const repelForceSlider = document.getElementById('smart-connections-visualizer-repelForce') as HTMLInputElement; if (repelForceSlider) { repelForceSlider.addEventListener('input', (event) => this.updateRepelForce(event)); } @@ -1037,7 +1048,7 @@ class ScGraphItemView extends ItemView { updateRepelForce(event: any) { const newRepelForce = parseFloat(event.target.value); - const label = document.getElementById('repelForceLabel'); + const label = document.getElementById('smart-connections-visualizer-repelForceLabel'); if (label) label.textContent = `Repel force: ${newRepelForce}`; this.repelForce = newRepelForce; this.plugin.settings.repelForce = newRepelForce; // Update the settings @@ -1046,7 +1057,7 @@ class ScGraphItemView extends ItemView { } setupLinkForceSlider() { - const linkForceSlider = document.getElementById('linkForce') as HTMLInputElement; + const linkForceSlider = document.getElementById('smart-connections-visualizer-linkForce') as HTMLInputElement; if (linkForceSlider) { linkForceSlider.addEventListener('input', (event) => this.updateLinkForce(event)); } @@ -1054,7 +1065,7 @@ class ScGraphItemView extends ItemView { updateLinkForce(event: any) { const newLinkForce = parseFloat(event.target.value); - const label = document.getElementById('linkForceLabel'); + const label = document.getElementById('smart-connections-visualizer-linkForceLabel'); if (label) label.textContent = `Link force: ${newLinkForce}`; this.linkForce = newLinkForce; this.plugin.settings.linkForce = newLinkForce; // Update the settings @@ -1063,7 +1074,7 @@ class ScGraphItemView extends ItemView { } setupLinkDistanceSlider() { - const linkDistanceSlider = document.getElementById('linkDistance') as HTMLInputElement; + const linkDistanceSlider = document.getElementById('smart-connections-visualizer-linkDistance') as HTMLInputElement; if (linkDistanceSlider) { linkDistanceSlider.addEventListener('input', (event) => this.updateLinkDistance(event)); } @@ -1071,7 +1082,7 @@ class ScGraphItemView extends ItemView { updateLinkDistance(event: any) { const newLinkDistance = parseFloat(event.target.value); - const label = document.getElementById('linkDistanceLabel'); + const label = document.getElementById('smart-connections-visualizer-linkDistanceLabel'); if (label) label.textContent = `Link distance: ${newLinkDistance}`; this.linkDistance = newLinkDistance; this.plugin.settings.linkDistance = newLinkDistance; // Update the settings @@ -1080,7 +1091,7 @@ class ScGraphItemView extends ItemView { } setupFadeThresholdSlider() { - const fadeThresholdSlider = document.getElementById('fadeThreshold') as HTMLInputElement; + const fadeThresholdSlider = document.getElementById('smart-connections-visualizer-fadeThreshold') as HTMLInputElement; if (fadeThresholdSlider) { fadeThresholdSlider.addEventListener('input', (event) => { this.updateFadeThreshold(event); @@ -1091,7 +1102,7 @@ class ScGraphItemView extends ItemView { updateFadeThreshold(event: any) { const newFadeThreshold = parseFloat(event.target.value); - const label = document.getElementById('fadeThresholdLabel'); + const label = document.getElementById('smart-connections-visualizer-fadeThresholdLabel'); if (label) label.textContent = `Text fade threshold: ${newFadeThreshold}`; this.textFadeThreshold = newFadeThreshold; this.plugin.settings.textFadeThreshold = newFadeThreshold; // Update the settings @@ -1099,7 +1110,7 @@ class ScGraphItemView extends ItemView { } setupMinLinkThicknessSlider() { - const minLinkThicknessSlider = document.getElementById('minLinkThickness') as HTMLInputElement; + const minLinkThicknessSlider = document.getElementById('smart-connections-visualizer-minLinkThickness') as HTMLInputElement; if (minLinkThicknessSlider) { minLinkThicknessSlider.addEventListener('input', (event) => this.updateMinLinkThickness(event)); } @@ -1107,7 +1118,7 @@ class ScGraphItemView extends ItemView { updateMinLinkThickness(event: any) { const newMinLinkThickness = parseFloat(event.target.value); - const label = document.getElementById('minLinkThicknessLabel'); + const label = document.getElementById('smart-connections-visualizer-minLinkThicknessLabel'); if (label) label.textContent = `Min link thickness: ${newMinLinkThickness}`; this.minLinkThickness = newMinLinkThickness; this.plugin.settings.minLinkThickness = newMinLinkThickness; // Update the settings @@ -1116,7 +1127,7 @@ class ScGraphItemView extends ItemView { } setupMaxLinkThicknessSlider() { - const maxLinkThicknessSlider = document.getElementById('maxLinkThickness') as HTMLInputElement; + const maxLinkThicknessSlider = document.getElementById('smart-connections-visualizer-maxLinkThickness') as HTMLInputElement; if (maxLinkThicknessSlider) { maxLinkThicknessSlider.addEventListener('input', (event) => this.updateMaxLinkThickness(event)); } @@ -1124,7 +1135,7 @@ class ScGraphItemView extends ItemView { updateMaxLinkThickness(event: any) { const newMaxLinkThickness = parseFloat(event.target.value); - const label = document.getElementById('maxLinkThicknessLabel'); + const label = document.getElementById('smart-connections-visualizer-maxLinkThicknessLabel'); if (label) label.textContent = `Max link thickness: ${newMaxLinkThickness}`; this.maxLinkThickness = newMaxLinkThickness; this.plugin.settings.maxLinkThickness = newMaxLinkThickness; // Update the settings @@ -1146,7 +1157,7 @@ class ScGraphItemView extends ItemView { } setupMaxLabelCharactersSlider() { - const maxLabelCharactersSlider = document.getElementById('maxLabelCharacters') as HTMLInputElement; + const maxLabelCharactersSlider = document.getElementById('smart-connections-visualizer-maxLabelCharacters') as HTMLInputElement; if (maxLabelCharactersSlider) { maxLabelCharactersSlider.addEventListener('input', (event) => this.updateMaxLabelCharacters(event)); } @@ -1154,14 +1165,14 @@ class ScGraphItemView extends ItemView { updateMaxLabelCharacters(event: any) { const newMaxLabelCharacters = parseInt(event.target.value, 10); - const label = document.getElementById('maxLabelCharactersLabel'); + const label = document.getElementById('smart-connections-visualizer-maxLabelCharactersLabel'); if (label) label.textContent = `Max Label Characters: ${newMaxLabelCharacters}`; this.maxLabelCharacters = newMaxLabelCharacters; this.updateNodeLabels(); } setupLinkLabelSizeSlider() { - const linkLabelSizeSlider = document.getElementById('linkLabelSize') as HTMLInputElement; + const linkLabelSizeSlider = document.getElementById('smart-connections-visualizer-linkLabelSize') as HTMLInputElement; if (linkLabelSizeSlider) { linkLabelSizeSlider.addEventListener('input', (event) => this.updateLinkLabelSize(event)); } @@ -1169,22 +1180,23 @@ class ScGraphItemView extends ItemView { updateLinkLabelSize(event: any) { const newLinkLabelSize = parseFloat(event.target.value); - const label = document.getElementById('linkLabelSizeLabel'); + const label = document.getElementById('smart-connections-visualizer-linkLabelSizeLabel'); if (label) label.textContent = `Link Label Size: ${newLinkLabelSize}`; this.linkLabelSize = newLinkLabelSize; this.updateLinkLabelSizes(); } setupNodeLabelSizeSlider() { - const nodeLabelSizeSlider = document.getElementById('nodeLabelSize') as HTMLInputElement; + const nodeLabelSizeSlider = document.getElementById('smart-connections-visualizer-nodeLabelSize') as HTMLInputElement; if (nodeLabelSizeSlider) { nodeLabelSizeSlider.addEventListener('input', (event) => this.updateNodeLabelSize(event)); } } updateNodeLabelSize(event: any) { + console.log('flounddd'); const newNodeLabelSize = parseFloat(event.target.value); - const label = document.getElementById('nodeLabelSizeLabel'); + const label = document.getElementById('smart-connections-visualizer-nodeLabelSizeLabel'); if (label) label.textContent = `Node Label Size: ${newNodeLabelSize}`; this.nodeLabelSize = newNodeLabelSize; this.updateNodeLabelSizes(); @@ -1192,7 +1204,7 @@ class ScGraphItemView extends ItemView { // Updated setupCloseIcon method setupCloseIcon() { - const closeIcon = document.getElementById('close-icon'); + const closeIcon = document.getElementById('smart-connections-visualizer-close-icon'); if (closeIcon) closeIcon.addEventListener('click', () => this.toggleDropdownMenu()); } @@ -1202,7 +1214,7 @@ class ScGraphItemView extends ItemView { } setupRefreshIcon() { - const refreshIcon = document.getElementById('refresh-icon'); + const refreshIcon = document.getElementById('smart-connections-visualizer-refresh-icon'); if (refreshIcon) refreshIcon.addEventListener('click', () => this.resetToDefault()); } @@ -1252,22 +1264,22 @@ class ScGraphItemView extends ItemView { this.updateLinkThickness(); this.updateSimulationForces(); this.updateVisualization(this.relevanceScoreThreshold); - + } updateLabelsToDefaults() { const labels = { - 'scoreThresholdLabel': `Min relevance: ${(this.relevanceScoreThreshold * 100).toFixed(0)}%`, - 'nodeSizeLabel': `Node size: ${this.nodeSize}`, - 'maxLabelCharactersLabel': `Max label characters: ${this.maxLabelCharacters}`, - 'linkLabelSizeLabel': `Link label size: ${this.linkLabelSize}`, - 'nodeLabelSizeLabel': `Node label size: ${this.nodeLabelSize}`, - 'minLinkThicknessLabel': `Min link thickness: ${this.minLinkThickness}`, - 'maxLinkThicknessLabel': `Max link thickness: ${this.maxLinkThickness}`, - 'fadeThresholdLabel': `Text fade threshold: ${this.textFadeThreshold}`, - 'repelForceLabel': `Repel force: ${this.repelForce}`, - 'linkForceLabel': `Link force: ${this.linkForce}`, - 'linkDistanceLabel': `Link distance: ${this.linkDistance}` + 'smart-connections-visualizer-scoreThresholdLabel': `Min relevance: ${(this.relevanceScoreThreshold * 100).toFixed(0)}%`, + 'smart-connections-visualizer-nodeSizeLabel': `Node size: ${this.nodeSize}`, + 'smart-connections-visualizer-maxLabelCharactersLabel': `Max label characters: ${this.maxLabelCharacters}`, + 'smart-connections-visualizer-linkLabelSizeLabel': `Link label size: ${this.linkLabelSize}`, + 'smart-connections-visualizer-smart-connections-visualizer-nodeLabelSizeLabel': `Node label size: ${this.nodeLabelSize}`, + 'smart-connections-visualizer-minLinkThicknessLabel': `Min link thickness: ${this.minLinkThickness}`, + 'smart-connections-visualizer-maxLinkThicknessLabel': `Max link thickness: ${this.maxLinkThickness}`, + 'smart-connections-visualizer-fadeThresholdLabel': `Text fade threshold: ${this.textFadeThreshold}`, + 'smart-connections-visualizer-repelForceLabel': `Repel force: ${this.repelForce}`, + 'smart-connections-visualizer-linkForceLabel': `Link force: ${this.linkForce}`, + 'smart-connections-visualizer-linkDistanceLabel': `Link distance: ${this.linkDistance}` }; for (const [id, text] of Object.entries(labels)) { @@ -1279,19 +1291,19 @@ class ScGraphItemView extends ItemView { } updateSliders() { - const scoreThresholdSlider = document.getElementById('scoreThreshold') as HTMLInputElement; - const nodeSizeSlider = document.getElementById('nodeSize') as HTMLInputElement; + const scoreThresholdSlider = document.getElementById('smart-connections-visualizer-scoreThreshold') as HTMLInputElement; + const nodeSizeSlider = document.getElementById('smart-connections-visualizer-nodeSize') as HTMLInputElement; // const lineThicknessSlider = document.getElementById('lineThickness') as HTMLInputElement; // const centerForceSlider = document.getElementById('centerForce') as HTMLInputElement; - const repelForceSlider = document.getElementById('repelForce') as HTMLInputElement; - const linkForceSlider = document.getElementById('linkForce') as HTMLInputElement; - const linkDistanceSlider = document.getElementById('linkDistance') as HTMLInputElement; - const fadeThresholdSlider = document.getElementById('fadeThreshold') as HTMLInputElement; - const minLinkThicknessSlider = document.getElementById('minLinkThickness') as HTMLInputElement; - const maxLinkThicknessSlider = document.getElementById('maxLinkThickness') as HTMLInputElement; - const maxLabelCharactersSlider = document.getElementById('maxLabelCharacters') as HTMLInputElement; - const linkLabelSizeSlider = document.getElementById('linkLabelSize') as HTMLInputElement; - const nodeLabelSizeSlider = document.getElementById('nodeLabelSize') as HTMLInputElement; + const repelForceSlider = document.getElementById('smart-connections-visualizer-repelForce') as HTMLInputElement; + const linkForceSlider = document.getElementById('smart-connections-visualizer-linkForce') as HTMLInputElement; + const linkDistanceSlider = document.getElementById('smart-connections-visualizer-linkDistance') as HTMLInputElement; + const fadeThresholdSlider = document.getElementById('smart-connections-visualizer-fadeThreshold') as HTMLInputElement; + const minLinkThicknessSlider = document.getElementById('smart-connections-visualizer-minLinkThickness') as HTMLInputElement; + const maxLinkThicknessSlider = document.getElementById('smart-connections-visualizer-maxLinkThickness') as HTMLInputElement; + const maxLabelCharactersSlider = document.getElementById('smart-connections-visualizer-maxLabelCharacters') as HTMLInputElement; + const linkLabelSizeSlider = document.getElementById('smart-connections-visualizer-linkLabelSize') as HTMLInputElement; + const nodeLabelSizeSlider = document.getElementById('smart-connections-visualizer-nodeLabelSize') as HTMLInputElement; scoreThresholdSlider.value = `${this.relevanceScoreThreshold}`; nodeSizeSlider.value = `${this.nodeSize}`; @@ -1383,10 +1395,10 @@ class ScGraphItemView extends ItemView { new Notice('No nodes or links to display after filtering. Adjust filter settings'); // Clear the existing nodes and links from the visualization - this.nodeSelection = this.svgGroup.select('g.nodes').selectAll('circle').data([]).exit().remove(); - this.linkSelection = this.svgGroup.select('g.links').selectAll('line').data([]).exit().remove(); - this.linkLabelSelection = this.svgGroup.select('g.link-labels').selectAll('text').data([]).exit().remove(); - this.labelSelection = this.svgGroup.select('g.node-labels').selectAll('text').data([]).exit().remove(); + this.nodeSelection = this.svgGroup.select('g.smart-connections-visualizer-nodes').selectAll('circle').data([]).exit().remove(); + this.linkSelection = this.svgGroup.select('g.smart-connections-visualizer-links').selectAll('line').data([]).exit().remove(); + this.linkLabelSelection = this.svgGroup.select('g.smart-connections-visualizer-link-labels').selectAll('text').data([]).exit().remove(); + this.labelSelection = this.svgGroup.select('g.smart-connections-visualizer-node-labels').selectAll('text').data([]).exit().remove(); return; } @@ -1405,6 +1417,11 @@ class ScGraphItemView extends ItemView { .distance((d: any) => this.linkDistanceScale(d.score)); // Ensure the link distance is applied this.simulation.alpha(1).restart(); + + // Stop the simulation after a short delay + setTimeout(() => { + this.simulation.alphaTarget(0); + }, 1000); // Adjust the delay as needed this.updatingVisualization = false; @@ -1581,7 +1598,7 @@ class ScGraphItemView extends ItemView { const svgGroup = this.svgGroup; // Update links first - this.linkSelection = svgGroup.select('g.links').selectAll('line') + this.linkSelection = svgGroup.select('g.smart-connections-visualizer-links').selectAll('line') .data(this.validatedLinks, (d: any) => `${d.source}-${d.target}`) .join( enter => this.enterLink(enter), @@ -1590,7 +1607,7 @@ class ScGraphItemView extends ItemView { ); - this.linkLabelSelection = svgGroup.select('g.link-labels').selectAll('text') + this.linkLabelSelection = svgGroup.select('g.smart-connections-visualizer-link-labels').selectAll('text') .data(this.validatedLinks, (d: any) => `${d.source.id}-${d.target.id}`) .join( enter => this.enterLinkLabel(enter), @@ -1598,7 +1615,7 @@ class ScGraphItemView extends ItemView { exit => exit.remove() ); - this.labelSelection = svgGroup.select('g.node-labels').selectAll('text') + this.labelSelection = svgGroup.select('g.smart-connections-visualizer-node-labels').selectAll('text') .data(nodesData, (d: any) => d.id) .join( enter => this.enterLabel(enter), @@ -1609,7 +1626,7 @@ class ScGraphItemView extends ItemView { .attr('y', (d: any) => d.y); // Update nodes after links - this.nodeSelection = svgGroup.select('g.nodes').selectAll('circle') + this.nodeSelection = svgGroup.select('g.smart-connections-visualizer-nodes').selectAll('circle') .data(nodesData, (d: any) => { return d.id; }) @@ -1625,7 +1642,7 @@ class ScGraphItemView extends ItemView { enterNode(enter: any) { const that = this; // Reference to 'this' context for inner functions return enter.append('circle') - .attr('class', 'node') + .attr('class', 'smart-connections-visualizer-node') .attr('r', (d: any) => d.id === this.centralNode.id ? this.nodeSize + 2 : this.nodeSize) .attr('fill', (d: any) => d.fill) .attr('stroke', (d: any) => d.selected ? 'blanchedalmond' : 'transparent') @@ -1769,7 +1786,7 @@ class ScGraphItemView extends ItemView { enterLink(enter: any) { return enter.append('line') - .attr('class', 'link') + .attr('class', 'smart-connections-visualizer-link') .attr('stroke', '#4c7787') .attr('stroke-width', (d: any) => this.getLinkStrokeWidth(d)) .attr('stroke-opacity', 1) @@ -1789,7 +1806,7 @@ class ScGraphItemView extends ItemView { updateLinkLabelSelection(svgGroup: any) { return svgGroup.append('g') - .attr('class', 'link-labels') + .attr('class', 'smart-connections-visualizer-link-labels') .selectAll('text') .data(this.validatedLinks, (d: any) => `${d.source.id}-${d.target.id}`) .join( @@ -1801,7 +1818,7 @@ class ScGraphItemView extends ItemView { enterLinkLabel(enter: any) { return enter.append('text') - .attr('class', 'link-label') + .attr('class', 'smart-connections-visualizer-link-label') .attr('font-size', this.linkLabelSize) .attr('fill', '#bbb') .attr('opacity', 0) @@ -1821,7 +1838,7 @@ class ScGraphItemView extends ItemView { enterLabel(enter: any) { return enter.append('text') - .attr('class', 'label') + .attr('class', 'smart-connections-visualizer-label') .attr('dx', 0) .attr('font-size', this.nodeLabelSize) .attr('dy', 12) @@ -1847,26 +1864,6 @@ class ScGraphItemView extends ItemView { .attr('opacity', 1); } - - updateSimulation(nodesData: any) { - if (!nodesData || !this.validatedLinks) { - console.error('Nodes data or validated links are undefined'); - return; - } - - const simulation = d3.forceSimulation(nodesData) - .force('link', d3.forceLink(this.validatedLinks) - .id((d: any) => d.id) - .distance((d: any) => this.linkDistanceScale(d.score)) - .strength(this.linkForce)) - .force('charge', d3.forceManyBody().strength(-this.repelForce)) - .force('collide', d3.forceCollide().radius(this.nodeSize + 3).strength(0.7)) - .on('tick', this.simulationTickHandler.bind(this)); - - this.simulation = simulation; - this.simulation.alpha(0.3).alphaTarget(0.05).restart(); - } - updateNodeSizes() { this.nodeSelection.attr('r', (d: any) => d.id === this.centralNode.id ? this.nodeSize + 3 : this.nodeSize); @@ -1893,7 +1890,12 @@ class ScGraphItemView extends ItemView { .strength(this.linkForce)) // .force('collide', d3.forceCollide().radius(this.nodeSize + 3).strength(0.7)); - this.simulation.alphaTarget(0.3).restart(); + this.simulation.alphaTarget(0.3).restart(); + + // Stop the simulation after a short delay + setTimeout(() => { + this.simulation.alphaTarget(0); + }, 1000); // Adjust the delay as needed } normalizeScore(score: number) : number{ @@ -1964,7 +1966,7 @@ class ScGraphItemView extends ItemView { this.isDragging = true; const [x, y] = d3.pointer(event); this.selectionBox = d3.select('svg').append('rect') - .attr('class', 'selection-box') + .attr('class', 'smart-connections-visualizer-selection-box') .attr('x', x) .attr('y', y) .attr('width', 0) @@ -2075,6 +2077,8 @@ export default class ScGraphView extends Plugin { await this.saveData(this.settings); } - onunload() {} + onunload() { + + } } diff --git a/styles.css b/styles.css index 8635b22..d40d4ca 100644 --- a/styles.css +++ b/styles.css @@ -1,42 +1,30 @@ -/* - -This CSS file will be included with your plugin, and -available in the app when your plugin is enabled. - -If your plugin does not need CSS, delete this file. - -*/ - -.link { +.smart-connections-visualizer-link { stroke: #4c7787; stroke-opacity: 1; cursor: pointer; } -.label { +.smart-connections-visualizer-label { pointer-events: none; fill: #bbb; text-shadow: 0px 0px 2px black; font-family: 'Cascadia'; } -.link-label { +.smart-connections-visualizer-link-label { font-family: 'Cascadia'; } -.node:hover { +.smart-connections-visualizer-node:hover { stroke: #fff; cursor: pointer; stroke-width: 0.4px; } -svg { - pointer-events: all; -} -svg .nodes circle { +svg .smart-connections-visualizer-nodes circle { cursor: pointer; } -.node { +.smart-connections-visualizer-node { cursor: pointer; } @@ -72,45 +60,48 @@ svg .nodes circle { .sc-visualizer-dropdown-menu.open { display: block !important; } -.menu-header { +.smart-connections-visualizer-menu-header { display: flex; justify-content: flex-end; margin-bottom: 5px; font-family: sans-serif; } -.menu-header .icon { +.smart-connections-visualizer-menu-header .smart-connections-visualizer-icon { cursor: pointer; font-size: 19px; color: #bbb; margin-left: 10px; margin-top: -2px; } -.menu-header .icon:hover { +.smart-connections-visualizer-menu-header .smart-connections-visualizer-icon:hover { color: #fff; } -.accordion-item { +.smart-connections-visualizer-accordion-item { margin-bottom: 10px; color: #a3aecb; } -.slider { +.smart-connections-visualizer-slider { width: 100% !important; } -.slider-container { +.smart-connections-visualizer-slider-container { margin-bottom: 8px; } -#score-threshold-label { +.smart-connections-visualizer-score-threshold-label { text-wrap: nowrap; } -#refresh-icon { +#smart-connections-visualizer-refresh-icon { font-size: 28px; - margin-top: -9px; + margin-top: -2px; + width: 20px; + height: 20px; + display: flex; } -.lucide-x { +.smart-connections-visualizer-lucide-x { height: 24px !important; width: 24px !important; } @@ -134,7 +125,7 @@ svg .nodes circle { right: 14px; } -.accordion-header { +.smart-connections-visualizer-accordion-header { cursor: pointer; background-color: #444; color: #fff; @@ -143,46 +134,46 @@ svg .nodes circle { display: block; align-items: center; } -.accordion-header:hover { +.smart-connections-visualizer-accordion-header:hover { background-color: #555; } -.accordion-content { +.smart-connections-visualizer-accordion-content { display: none; padding: 10px; background-color: #333; border-radius: 5px; } -.accordion-content.show { +.smart-connections-visualizer-accordion-content.show { display: block; } -.dropdown-indicator { +.smart-connections-visualizer-dropdown-indicator { width: 16px; height: 16px; margin-right: 8px; vertical-align: middle; } -.radio-container { +.smart-connections-visualizer-radio-container { margin-top: 10px; } -.radio-container label { +.smart-connections-visualizer-radio-container label { margin-right: 10px; color: #a3aecb; } -.settings-item-content-label { +.smart-connections-visualizer-settings-item-content-label { margin-right: 20px; } -.selection-box { +.smart-connections-visualizer-selection-box { stroke: #00f; stroke-width: 1; fill: rgba(0, 0, 255, 0.3); } /* Styles for the legend container */ -.legend-container { +.smart-connections-visualizer-legend-container { width: 295px; border-collapse: collapse; background-color: #2d3039; /* Dark background color similar to settings menu */ @@ -193,7 +184,7 @@ svg .nodes circle { } /* Styles for the legend header */ -.legend-header { +.smart-connections-visualizer-legend-header { display: flex; background-color: #303030; /* Darker background color for header */ text-align: left; @@ -201,49 +192,49 @@ svg .nodes circle { } /* Styles for each header cell in the legend */ -.legend-header div { +.smart-connections-visualizer-legend-header div { padding: 8px; } /* Styles for each row in the legend */ -.legend-row { +.smart-connections-visualizer-legend-row { display: flex; align-items: center; /* border-bottom: 1px solid #ddd; */ } /* Alternate row coloring for better readability */ -.legend-row:nth-child(even) { +.smart-connections-visualizer-legend-row:nth-child(even) { background-color: #3d4149; /* Slightly lighter row color for contrast */ } -.legend-row:nth-child(odd) { +.smart-connections-visualizer-legend-row:nth-child(odd) { background-color: #2d3039; /* Same as container background color */ } /* Styles for each cell in the row */ -.legend-row div { +.smart-connections-visualizer-legend-row div { padding: 8px; } /* Styles for the color picker input */ -.legend-color-picker { +.smart-connections-visualizer-legend-color-picker { width: 30px; height: 30px; border: none; cursor: pointer; } -.variable-col { +.smart-connections-visualizer-variable-col { flex: 2; } -.count-col { +.smart-connections-visualizer-count-col { flex: 1; text-align: center; } -.color-col { +.smart-connections-visualizer-color-col { flex: 1; text-align: center; } \ No newline at end of file