This is an automated email from the ASF dual-hosted git repository. pierrejeambrun pushed a commit to branch v2-5-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit ea8227b385d39f936aff8cd96b5f0bc7d50347ab Author: yuqian90 <[email protected]> AuthorDate: Fri Mar 10 00:59:15 2023 +0800 Fix some long known Graph View UI problems (#29971) * Center clicked node around mouse graph zoom changes Fix find zoom Remove unused args Refactor * rebase * revert redundant change * Fix unused variable * pre-commit --------- Co-authored-by: Qian Yu <[email protected]> (cherry picked from commit ff9cae99bf6f622066f14c33568ed929a523bdad) --- airflow/www/static/js/graph.js | 59 ++++++++++++-------------------- airflow/www/templates/airflow/graph.html | 2 +- airflow/www/views.py | 2 -- 3 files changed, 22 insertions(+), 41 deletions(-) diff --git a/airflow/www/static/js/graph.js b/airflow/www/static/js/graph.js index c6755a6cce..8ca4a99fc7 100644 --- a/airflow/www/static/js/graph.js +++ b/airflow/www/static/js/graph.js @@ -43,10 +43,8 @@ const mapTaskToNode = new Map(); // Below variables are being used in dag.js -const getTaskInstanceURL = `${taskInstancesUrl}?dag_id=${encodeURIComponent(dagId)}&execution_date=${ - encodeURIComponent(executionDate)}`; +const getTaskInstanceURL = `${taskInstancesUrl}?dag_id=${encodeURIComponent(dagId)}&execution_date=${encodeURIComponent(executionDate)}`; -const duration = 500; const stateFocusMap = { success: false, running: false, @@ -255,17 +253,11 @@ function setUpZoomSupport() { // Get Dagre Graph dimensions const graphWidth = g.graph().width; const graphHeight = g.graph().height; - // Get SVG dimensions - const padding = 80; - const svgBb = svg.node().getBoundingClientRect(); - const width = svgBb.width - padding * 2; - const height = svgBb.height - padding; // we are not centering the dag vertically + const { width, height } = svg.node().viewBox.animVal; + const padding = width * 0.05; // Calculate applicable scale for zoom - const zoomScale = Math.min( - Math.min(width / graphWidth, height / graphHeight), - 1.5, // cap zoom level to 1.5 so nodes are not too large - ); + const zoomScale = Math.min(Math.min(width / graphWidth, height / graphHeight)) * 0.8; zoom.translate([(width / 2) - ((graphWidth * zoomScale) / 2) + padding, padding]); zoom.scale(zoomScale); @@ -362,20 +354,7 @@ d3.select('#searchbox').on('keyup', () => { // This moves the matched node to the center of the graph area if (match) { - const transform = d3.transform(d3.select(match).attr('transform')); - - const svgBb = svg.node().getBoundingClientRect(); - transform.translate = [ - svgBb.width / 2 - transform.translate[0], - svgBb.height / 2 - transform.translate[1], - ]; - transform.scale = [1, 1]; - - if (zoom != null) { - zoom.translate(transform.translate); - zoom.scale(1); - zoom.event(innerSvg); - } + focusGroup(match.id, false); } }); @@ -441,7 +420,7 @@ function handleRefresh() { (tis) => { // only refresh if the data has changed if (prevTis !== tis) { - // eslint-disable-next-line no-global-assign + // eslint-disable-next-line no-global-assign updateNodesStates(tis); // Only redraw the graph if labels have changed @@ -631,32 +610,36 @@ function focusedGroupKey() { } // Focus the graph on the expanded/collapsed node -function focusGroup(nodeId) { +function focusGroup(nodeId, followMouse = true) { if (nodeId != null && zoom != null) { - const { x } = g.node(nodeId); + const { x, y } = g.node(nodeId); // This is the total canvas size. - const { width, height } = svg.node().getBoundingClientRect(); + const { width, height } = svg.node().viewBox.animVal; // This is the size of the node or the cluster (i.e. group) let rect = d3.selectAll('g.node').filter((n) => n === nodeId).select('rect'); if (rect.empty()) rect = d3.selectAll('g.cluster').filter((n) => n === nodeId).select('rect'); + const [mouseX, mouseY] = d3.mouse(svg.node()); + // Is there a better way to get nodeWidth and nodeHeight ? const [nodeWidth, nodeHeight] = [ rect[0][0].attributes.width.value, rect[0][0].attributes.height.value, ]; // Calculate zoom scale to fill most of the canvas with the node/cluster in focus. - const scale = Math.min( - Math.min(width / nodeWidth, height / nodeHeight), - 1.5, // cap zoom level to 1.5 so nodes are not too large - ) * 0.9; - - // deltaY of 5 keeps the zoom at the top of the view but with a slight margin - const [deltaX, deltaY] = [width / 2 - x * scale, 5]; + const scale = Math.min(Math.min(width / nodeWidth, height / nodeHeight), 1) * 0.2; + + // Move the graph so that the node that was expanded/collapsed is centered around + // the mouse click. + const [toX, toY] = followMouse ? [mouseX, mouseY] : [width / 2, height / 5]; + const [deltaX, deltaY] = [ + toX - x * scale, + toY + (nodeHeight / 2 - y) * scale, + ]; zoom.translate([deltaX, deltaY]); zoom.scale(scale); - zoom.event(innerSvg.transition().duration(duration)); + zoom.event(innerSvg); const children = new Set(g.children(nodeId)); // Set data attr to highlight the focused group (via CSS). diff --git a/airflow/www/templates/airflow/graph.html b/airflow/www/templates/airflow/graph.html index c4e28c32fb..9d4ee6e817 100644 --- a/airflow/www/templates/airflow/graph.html +++ b/airflow/www/templates/airflow/graph.html @@ -121,7 +121,7 @@ </div> <div class="svg-wrapper"> <div class="graph-svg-wrap"> - <svg id="graph-svg" width="{{ width }}" height="{{ height }}"> + <svg id="graph-svg" viewBox="0 0 100 100"> <g id="dig" transform="translate(20,20)"></g> </svg> </div> diff --git a/airflow/www/views.py b/airflow/www/views.py index 56e3a28a26..bf55a8ffba 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -2874,8 +2874,6 @@ class Airflow(AirflowBaseView): "airflow/graph.html", dag=dag, form=form, - width=request.args.get("width", "100%"), - height=request.args.get("height", "800"), dag_run_id=dag_run_id, execution_date=dttm.isoformat(), state_token=wwwutils.state_token(dt_nr_dr_data["dr_state"]),
