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:
Родитель
be1091893e
Коммит
afb5fa7a05
|
@ -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);
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче