Renamed all Ids and classes to have Smart Visualizer prefixe + Made viz updates smoother by stopping force simulation after 1s to remove possible endless force loop + cleanup

This commit is contained in:
Mossy426 2024-06-30 00:27:13 -04:00
parent 9b7cb69cfa
commit 332dd323f1
2 changed files with 199 additions and 204 deletions

316
main.ts
View file

@ -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() {
}
}

View file

@ -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;
}