Adding accessible tooltips to azdataGraph (#144)

* Adding click to tooltip

* Vbumping

* Adding announcement to tooltip
Removing graphic role
Adding additional flag to enable disable tooltips
Fixing some null checks
This commit is contained in:
Aasim Khan 2022-10-14 09:55:32 -07:00 коммит произвёл GitHub
Родитель be1091893e
Коммит afb5fa7a05
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 102 добавлений и 26 удалений

Просмотреть файл

@ -1,7 +1,7 @@
{
"name": "azdataGraph",
"description": "azdataGraph is a derivative of mxGraph, which is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.",
"version": "0.0.46",
"version": "0.0.47",
"homepage": "https://github.com/microsoft/azdataGraph",
"author": "Microsoft",
"license": "Apache-2.0",

Просмотреть файл

@ -167,8 +167,7 @@ function azdataQueryPlan(queryPlanConfiguration) {
}
azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
const { container, iconPaths, badgeIconPaths, expandCollapsePaths } = queryPlanConfiguration;
const { container, iconPaths, badgeIconPaths, expandCollapsePaths, showTooltipOnClick } = queryPlanConfiguration;
this.container = container;
this.polygonRoots = [];
this.drawnPolygons = [];
@ -189,7 +188,7 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
const selectNext = (evt) => {
graph.tooltipHandler.hide();
let currentCell = this.graph.getSelectionCell();
if(currentCell.collapsed) {
if (currentCell.collapsed) {
return;
}
if (currentCell && currentCell.vertex) {
@ -327,9 +326,16 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
graph.cellsMovable = false;
graph.edgeMovable = false;
graph.setHtmlLabels(true);
graph.container.setAttribute('role', 'tree');
graph.container.firstChild.setAttribute('role', 'tree');
if (showTooltipOnClick) {
this.graph.showTooltipOnClick = showTooltipOnClick;
graph.tooltipHandler.setEnabled(false);
}
graph.showTooltip = true;
graph.isCellSelectable = (cell) => {
if(cell?.isEdge()){
if (cell?.isEdge()) {
return false;
}
return true;
@ -394,14 +400,14 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
cellBodyContainer.setAttribute('aria-level', cell.value.depth);
cellBodyContainer.setAttribute('aria-posinset', cell.value.posInSet);
cellBodyContainer.setAttribute('aria-setsize', cell.value.setSize);
if(cell.value.ariaLabel){
if (cell.value.ariaLabel) {
cellBodyContainer.setAttribute('aria-label', cell.value.ariaLabel);
}
cellContainer.appendChild(cellBodyContainer);
mxEvent.addListener(cellBodyContainer, 'focus', (evt) => {
this.setSelectionCell(cell);
if(cell.highlightShape){
if (cell.highlightShape) {
cell.highlightShape.isDashed = false;
cell.highlightShape.redraw();
cell.highlightShape.updateBoundingBox();
@ -409,13 +415,59 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
});
mxEvent.addListener(cellBodyContainer, 'blur', (evt) => {
if(cell.highlightShape){
if (cell.highlightShape) {
cell.highlightShape.isDashed = true;
cell.highlightShape.redraw();
cell.highlightShape.updateBoundingBox();
}
});
mxEvent.addListener(cellContainer, 'mousemove', (evt) => {
if (this.showTooltipOnClick && this.showTooltip) {
evt.preventDefault();
evt.stopPropagation();
}
})
mxEvent.addListener(cellContainer, 'mouseleave', (evt) => {
if (this.showTooltipOnClick && this.showTooltip) {
this.tooltipHandler.hide();
}
})
mxEvent.addListener(cellContainer, 'click', (evt) => {
if (this.showTooltipOnClick && this.showTooltip) {
const cell = this.getSelectionCell();
const tooltip = this.getTooltipForCell(cell);
if (cell?.geometry) {
const cellContainerRect = cellBodyContainer.getBoundingClientRect();
this.tooltipHandler.show(tooltip, cellContainerRect.x + cellContainerRect.width, cellContainerRect.y + cellContainerRect.height, cell);
}
}
});
mxEvent.addListener(cellBodyContainer, 'keydown', (evt) => {
if (this.showTooltipOnClick && this.showTooltip) {
if (evt.key === 'F3') {
if (this.tooltipHandler.isVisible) {
this.tooltipHandler.hide();
} else {
const cell = this.getSelectionCell();
if (cell?.geometry) {
const cellContainerRect = cellBodyContainer.getBoundingClientRect();
this.tooltipHandler.show(this.getTooltipForCell(cell), cellContainerRect.x + cellContainerRect.width, cellContainerRect.y + cellContainerRect.height, cell);
}
}
evt.preventDefault();
evt.stopPropagation();
} else if (evt.key === 'Escape') {
this.tooltipHandler.hide();
evt.preventDefault();
evt.stopPropagation();
}
}
});
if (cell.edge) {
cellBodyContainer.id = cell.id;
@ -490,11 +542,11 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
// undefined is for the middle parameter since the overwritten definition of foldCells doesn't reference it.
this.foldCells(collapse, undefined, [currentCell]);
cell.cellDivs.body.focus();
if (!collapse) {
self.redrawExpensiveOperatorHighlighting();
}
evt.stopPropagation();
evt.preventDefault();
}
@ -505,8 +557,8 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
});
cellDivs.body.tabIndex = oldTabIndex;
if(this.firstLoad && cell.value.isRoot){
if (this.firstLoad && cell.value.isRoot) {
this.firstLoad = false;
cellDivs.body.tabIndex = 0;
}
@ -703,7 +755,7 @@ azdataQueryPlan.prototype.init = function (queryPlanConfiguration) {
var edge = entry.node.edges[i];
graph.insertWeightedInvertedEdge(parent, edge.id, edge, entry.vertex, vertex);
node.depth = entry.node.depth + 1;
node.posInSet = i+1;
node.posInSet = i + 1;
node.setSize = entry.node.children.length;
stack.push(
@ -1007,6 +1059,19 @@ azdataQueryPlan.prototype.destroy = function () {
}
};
azdataQueryPlan.prototype.setShowTooltipOnClick = function (showTooltipOnClick) {
this.graph.showTooltipOnClick = showTooltipOnClick;
}
azdataQueryPlan.prototype.showTooltip = function (showTooltip) {
this.graph.showTooltip = showTooltip;
if(showTooltip && !this.graph.showTooltipOnClick){
this.graph.tooltipHandler.setEnabled(true);
} else {
this.graph.tooltipHandler.setEnabled(false);
}
}
/**
* Draws a polygon using the points given
* @param {*} cell starting cell where the polygon will start to be drawn.
@ -1300,7 +1365,7 @@ azdataQueryPlan.prototype.findExpensiveOperator = function (getExpenseMetricValu
while (stack.length > 0) {
const node = stack.pop();
const costValue = getExpenseMetricValue(node);
if (costValue) {
expensiveOperators.push(node);
expensiveCostValues.push(costValue);

Просмотреть файл

@ -113,7 +113,7 @@ azdataGraph.prototype.getStyledTooltipForCell = function (cell) {
const footerTopMargin = 'margin-top: 1.5em;';
const metricLabelMargin = 'margin-right: 4em;';
if (cell.value != null && cell.value.metrics != null) {
if (cell?.value != null && cell?.value?.metrics != null) {
var tooltip = `<div style=\"${tooltipWidth}\">`;
// tooltip heading for vertices only

Просмотреть файл

@ -36,6 +36,8 @@ function mxTooltipHandler(graph, delay)
}
};
mxTooltipHandler.prototype.isVisible = false;
/**
* Variable: zIndex
*
@ -140,6 +142,8 @@ mxTooltipHandler.prototype.init = function()
this.div = document.createElement('div');
this.div.className = 'mxTooltip';
this.div.style.visibility = 'hidden';
this.div.setAttribute('role', 'tooltip');
this.div.setAttribute('aria-live','polite');
document.body.appendChild(this.div);
@ -161,11 +165,12 @@ mxTooltipHandler.prototype.init = function()
mxEvent.addListener(this.div, 'mousemove', mxUtils.bind(this, function(evt)
{
var pt = mxUtils.convertPoint(this.graph.container, evt.clientX, evt.clientY);
if( this.sourceCell &&
pt.x < this.sourceCell.geometry.x ||
pt.x > (this.sourceCell.geometry.x + this.sourceCell.geometry.width) ||
pt.y < (this.sourceCell.geometry.y) ||
pt.y > (this.sourceCell.geometry.y + this.sourceCell.geometry.height)
if( this.sourceCell !== undefined &&
pt.x < this.sourceCell?.geometry?.x ||
pt.x > (this.sourceCell?.geometry?.x + this.sourceCell?.geometry?.width) ||
pt.y < (this.sourceCell?.geometry?.y) ||
pt.y > (this.sourceCell?.geometry?.y + this.sourceCell?.geometry?.height)
){
this.hideTooltip();
}
@ -216,10 +221,9 @@ mxTooltipHandler.prototype.mouseMove = function(sender, me)
{
this.reset(me, true);
var state = this.getStateForEvent(me);
if (this.isHideOnHover() || state != this.state || (me.getSource() != this.node &&
if (this.isEnabled() && (this.isHideOnHover() || state != this.state || (me.getSource() != this.node &&
(!this.stateSource || (state != null && this.stateSource ==
(me.isSource(state.shape) || !me.isSource(state.text))))))
(me.isSource(state.shape) || !me.isSource(state.text)))))))
{
this.hideTooltip();
}
@ -318,6 +322,7 @@ mxTooltipHandler.prototype.hideTooltip = function()
{
this.div.style.visibility = 'hidden';
this.div.innerHTML = '';
this.isVisible = false;
}
// {{SQL CARBON EDIT}} setting sourceCell to undefined when we hide the tooltip
this.sourceCell = undefined;
@ -329,8 +334,11 @@ mxTooltipHandler.prototype.hideTooltip = function()
* Shows the tooltip for the specified cell and optional index at the
* specified location (with a vertical offset of 10 pixels).
*/
mxTooltipHandler.prototype.show = function(tip, x, y)
mxTooltipHandler.prototype.show = function(tip, x, y, cell)
{
if(cell){
this.sourceCell = cell;
}
if (!this.destroyed && tip != null && tip.length > 0)
{
// Initializes the DOM nodes if required
@ -385,6 +393,7 @@ mxTooltipHandler.prototype.show = function(tip, x, y)
* fits in the screen or not as we always want to show it.
*/
//mxUtils.fit(this.div);
this.isVisible = true;
}
};
@ -408,5 +417,6 @@ mxTooltipHandler.prototype.destroy = function()
this.destroyed = true;
this.div = null;
this.isVisible = false;
}
};

Просмотреть файл

@ -27,7 +27,8 @@
queryPlanGraph: graph,
iconPaths: iconPaths,
badgeIconPaths: badgePaths,
expandCollapsePaths: collapseExpandPaths
expandCollapsePaths: collapseExpandPaths,
showTooltipOnClick: true
};
new azdataQueryPlan(queryPlanConfiguration);
};