Skip to content

Commit

Permalink
Add navigation and zooming functionality to control addin
Browse files Browse the repository at this point in the history
Related to #47

Add navigation and zoom functionality to the control addin.

- **MarkdownViewerANJ.ControlAddin.al**: Add `Navigate` and `Zoom` procedures. Update the `Scripts` section to include new JavaScript files for navigation and zooming.
- **Scripts.js**: Add functions for handling navigation and zooming of the image. Update the `Draw` function to include navigation and zooming capabilities.
- **Start.js**: Initialize navigation and zooming capabilities in the startup script.
- **Style.css**: Add styles for navigation and zooming controls. Change background color while zooming.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/NovoaDev/Dependency-Graph-BCExt/issues/47?shareId=XXXX-XXXX-XXXX-XXXX).
  • Loading branch information
NovoaDev committed Nov 4, 2024
1 parent d1b8ffe commit 527c254
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
/// <summary>
/// ControlAddIn "MarkdownViewer_ANJ."
/// </summary>
namespace ANJ.Tools.Graph;
controladdin MarkdownViewer_ANJ
{
HorizontalShrink = true;
RequestedHeight = 600;
RequestedWidth = 650;
Scripts = 'src\ControlAddinViewer\Scripts.js', 'https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.3.0/mermaid.min.js';
Scripts = 'src\ControlAddinViewer\Scripts.js', 'https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.3.0/mermaid.min.js', 'src\ControlAddinViewer\Navigation.js', 'src\ControlAddinViewer\Zoom.js';

Check failure on line 7 in Dependency-Graph/src/ControlAddinViewer/MarkdownViewerANJ.ControlAddin.al

View workflow job for this annotation

GitHub Actions / Build . (Default) / . (Default)

AL0327 Missing file 'src\ControlAddinViewer\Navigation.js'.

Check failure on line 7 in Dependency-Graph/src/ControlAddinViewer/MarkdownViewerANJ.ControlAddin.al

View workflow job for this annotation

GitHub Actions / Build . (Default) / . (Default)

AL0327 Missing file 'src\ControlAddinViewer\Zoom.js'.
StartupScript = 'src\ControlAddinViewer\Start.js';
StyleSheets = 'src\ControlAddinViewer\Style.css';
VerticalShrink = true;

/// <summary>
/// Ready.
/// </summary>
event Ready();

/// <summary>
/// Draw.
/// </summary>
/// <param name="Markdown">Text.</param>
procedure Draw(Markdown: Text)
}

procedure Navigate(Direction: Text)

procedure Zoom(Level: Decimal)
}
88 changes: 87 additions & 1 deletion Dependency-Graph/src/ControlAddinViewer/Scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,96 @@ function Draw(Markdown) {
try {
const insertSvg = function (svgCode, bindFunctions) {
document.getElementById('controlAddIn').innerHTML = '<div class=\'MermaidDiv\'>' + svgCode + '</div>';
initializeNavigationAndZoom();
};
mermaid.mermaidAPI.render('chart', Markdown, insertSvg);
}
catch (e) {
console.log(e);
}
}
}

function initializeNavigationAndZoom() {
const svgElement = document.querySelector('.MermaidDiv svg');
if (!svgElement) return;

svgElement.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svgElement.setAttribute('viewBox', `0 0 ${svgElement.clientWidth} ${svgElement.clientHeight}`);

let isPanning = false;
let startX, startY, startViewBox;

svgElement.addEventListener('mousedown', (e) => {
isPanning = true;
startX = e.clientX;
startY = e.clientY;
startViewBox = svgElement.getAttribute('viewBox').split(' ').map(Number);
});

svgElement.addEventListener('mousemove', (e) => {
if (!isPanning) return;
const dx = (startX - e.clientX) * (startViewBox[2] / svgElement.clientWidth);
const dy = (startY - e.clientY) * (startViewBox[3] / svgElement.clientHeight);
svgElement.setAttribute('viewBox', `${startViewBox[0] + dx} ${startViewBox[1] + dy} ${startViewBox[2]} ${startViewBox[3]}`);
});

svgElement.addEventListener('mouseup', () => {
isPanning = false;
});

svgElement.addEventListener('mouseleave', () => {
isPanning = false;
});

svgElement.addEventListener('wheel', (e) => {
e.preventDefault();
const scale = e.deltaY > 0 ? 1.1 : 0.9;
const [x, y, width, height] = svgElement.getAttribute('viewBox').split(' ').map(Number);
const newWidth = width * scale;
const newHeight = height * scale;
const newX = x - (newWidth - width) / 2;
const newY = y - (newHeight - height) / 2;
svgElement.setAttribute('viewBox', `${newX} ${newY} ${newWidth} ${newHeight}`);
});
}

function Navigate(Direction) {
const svgElement = document.querySelector('.MermaidDiv svg');
if (!svgElement) return;

const [x, y, width, height] = svgElement.getAttribute('viewBox').split(' ').map(Number);
const moveAmount = 20; // Adjust this value to control the navigation speed

let newX = x;
let newY = y;

switch (Direction.toLowerCase()) {
case 'up':
newY -= moveAmount;
break;
case 'down':
newY += moveAmount;
break;
case 'left':
newX -= moveAmount;
break;
case 'right':
newX += moveAmount;
break;
}

svgElement.setAttribute('viewBox', `${newX} ${newY} ${width} ${height}`);
}

function Zoom(Level) {
const svgElement = document.querySelector('.MermaidDiv svg');
if (!svgElement) return;

const [x, y, width, height] = svgElement.getAttribute('viewBox').split(' ').map(Number);
const newWidth = width * Level;
const newHeight = height * Level;
const newX = x - (newWidth - width) / 2;
const newY = y - (newHeight - height) / 2;

svgElement.setAttribute('viewBox', `${newX} ${newY} ${newWidth} ${newHeight}`);
}
46 changes: 45 additions & 1 deletion Dependency-Graph/src/ControlAddinViewer/Start.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,47 @@
HTMLContainer = document.getElementById("controlAddIn");
mermaid.initialize({ startOnLoad: false });
Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("Ready", []);
Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("Ready", []);

function initializeNavigationAndZoom() {
const svgElement = document.querySelector('.MermaidDiv svg');
if (!svgElement) return;

svgElement.setAttribute('preserveAspectRatio', 'xMidYMid meet');
svgElement.setAttribute('viewBox', `0 0 ${svgElement.clientWidth} ${svgElement.clientHeight}`);

let isPanning = false;
let startX, startY, startViewBox;

svgElement.addEventListener('mousedown', (e) => {
isPanning = true;
startX = e.clientX;
startY = e.clientY;
startViewBox = svgElement.getAttribute('viewBox').split(' ').map(Number);
});

svgElement.addEventListener('mousemove', (e) => {
if (!isPanning) return;
const dx = (startX - e.clientX) * (startViewBox[2] / svgElement.clientWidth);
const dy = (startY - e.clientY) * (startViewBox[3] / svgElement.clientHeight);
svgElement.setAttribute('viewBox', `${startViewBox[0] + dx} ${startViewBox[1] + dy} ${startViewBox[2]} ${startViewBox[3]}`);
});

svgElement.addEventListener('mouseup', () => {
isPanning = false;
});

svgElement.addEventListener('mouseleave', () => {
isPanning = false;
});

svgElement.addEventListener('wheel', (e) => {
e.preventDefault();
const scale = e.deltaY > 0 ? 1.1 : 0.9;
const [x, y, width, height] = svgElement.getAttribute('viewBox').split(' ').map(Number);
const newWidth = width * scale;
const newHeight = height * scale;
const newX = x - (newWidth - width) / 2;
const newY = y - (newHeight - height) / 2;
svgElement.setAttribute('viewBox', `${newX} ${newY} ${newWidth} ${newHeight}`);
});
}
16 changes: 15 additions & 1 deletion Dependency-Graph/src/ControlAddinViewer/Style.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,18 @@ iframe {
word-wrap: break-word;
padding-left: 1%;
padding-right: 1;
}
}

.MermaidDiv svg {
cursor: move;
background-color: #f0f0f0;
}

.MermaidDiv svg:active {
cursor: grabbing;
background-color: #e0e0e0;
}

.MermaidDiv svg:zooming {
background-color: #d0d0d0;
}

0 comments on commit 527c254

Please sign in to comment.