Skip to content

Commit

Permalink
Add basic search functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
sevein committed Oct 5, 2023
1 parent 4ffab4b commit c9abba9
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 9 deletions.
84 changes: 77 additions & 7 deletions web/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ import getLocation from './location.js'
const { scheme, host } = getLocation(window);
const client = createClient(scheme, host);

const parse = function(blob) {
const parse = (blob) => {
const parser = new DOMParser();
const doc = parser.parseFromString(blob, "text/xml");
return doc.documentElement;
}

const loadDocument = function(config) {
const loadDocument = (config) => {
return client.showWorkflow("/workflow/default", config);
}

const loadGraph = function() {
let panzoomInstance;

const loadGraph = () => {
loadDocument().then((resp) => {
try {
const viewport = document.querySelector("#viewport");
viewport.innerHTML = "";
viewport.appendChild(parse(resp.data));
panzoom(viewport, { minZoom: 0.01, zoomSpeed: 0.3, autocenter: true }).zoomAbs(0, 0, 0.1);
panzoomInstance = panzoom(viewport, { minZoom: 0.01, zoomSpeed: 0.3, autocenter: false });
panzoomInstance.zoomAbs(0, 0, 0.1);
} catch (error) {
console.error(error);
alert("An error occurred while loading the graph.");
Expand All @@ -34,7 +37,7 @@ const loadGraph = function() {
})
};

const saveGraph = function() {
const saveGraph = () => {
loadDocument({ responseType: "blob" }).then((resp) => {
saveAs(resp.data, "workflow.svg", {type: "image/svg+xml"});
}).catch((error) => {
Expand All @@ -43,27 +46,94 @@ const saveGraph = function() {
})
}

const search = (text) => {
const svg = document.querySelector('svg');
const textElements = svg.querySelectorAll('*');
const matchingNodesSet = new Set();
const lctext = text.toLowerCase();

for (let element of textElements) {
if (element.textContent.toLowerCase().includes(lctext)) {
let parent = element.parentElement;
while (parent) {
if (parent.classList.contains('node')) {
matchingNodesSet.add(parent);
break;
}
parent = parent.parentElement;
}
}
}

return Array.from(matchingNodesSet);
}

const zoomElement = (element) => {
const svg = document.querySelector('svg');
const rect = element.getBBox();
const point = svg.createSVGPoint();
point.x = rect.x + rect.width / 2;
point.y = rect.y + rect.height / 2;
const globalPoint = point.matrixTransform(element.getScreenCTM());
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
const panX = (viewportWidth / 2 - globalPoint.x);
const panY = (viewportHeight / 2 - globalPoint.y);
panzoomInstance.moveBy(panX, panY, false);
}

// Write the initial layout of the application.
document.querySelector('#app').innerHTML = `
<div class="wrapper">
<div class="box sidebar">
<button class="reload">Reload</button>
<button class="save">Save</button>
<input class="search" type="text" placeholder="Search (shift + /)"/>
</div>
<div class="box content">
<div id="viewport"></div>
</div>
</div>
`

document.querySelector('.reload').addEventListener('click', loadGraph);
// Focus the search box when shift and `/` keys are pressed simultaneously.
window.addEventListener('keydown', (event) => {
if (event.shiftKey && event.key === '/') {
event.preventDefault();
const search = document.querySelector('.search');
if (search) {
search.focus();
}
}
});

document.querySelector('.save').addEventListener('click', saveGraph);
let results;

document.querySelector(".search").addEventListener("keydown", function(event) {
if (event.key == "Escape") {
event.preventDefault();
this.value = "";
} else if (event.key == "Enter") {
event.preventDefault();
if (this.value.trim() != "") {
results = search(this.value);
if (results.length > 0) {
zoomElement(results[0]);
results.forEach((item) => console.log(this.value, item));
}
}
}
})

// Highlight graph nodes when they are clicked by the user.
document.body.addEventListener('click', function(event) {
const el = event.target.closest('.node');
if (el) {
el.classList.toggle('active');
}
});

document.querySelector('.reload').addEventListener('click', loadGraph);
document.querySelector('.save').addEventListener('click', saveGraph);

loadGraph();
19 changes: 17 additions & 2 deletions web/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,30 @@ body {
z-index: 1;
}

.box {}
.box, #viewport {
width: 100%;
display: block;
}

button {
padding: 4px;
font-size: 11px;
font-size: 14px;
border: 1px solid #333;
cursor: pointer;
}

input.search {
all: unset;
width: 40%;
margin-left: 8px;
background-color: white;
font-family: Arial, Helvetica, sans-serif;
padding: 4px;
border: 1px solid black;
font-size: 14px;
}


/* SVG */

svg {
Expand Down

0 comments on commit c9abba9

Please sign in to comment.