mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add flow navigator widget
This commit is contained in:
parent
f6274445a2
commit
17c5fdf0d5
@ -144,6 +144,7 @@ module.exports = function(grunt) {
|
|||||||
"editor/js/ui/keyboard.js",
|
"editor/js/ui/keyboard.js",
|
||||||
"editor/js/ui/workspaces.js",
|
"editor/js/ui/workspaces.js",
|
||||||
"editor/js/ui/view.js",
|
"editor/js/ui/view.js",
|
||||||
|
"editor/js/ui/view-navigator.js",
|
||||||
"editor/js/ui/sidebar.js",
|
"editor/js/ui/sidebar.js",
|
||||||
"editor/js/ui/palette.js",
|
"editor/js/ui/palette.js",
|
||||||
"editor/js/ui/tab-info.js",
|
"editor/js/ui/tab-info.js",
|
||||||
|
164
editor/js/ui/view-navigator.js
Normal file
164
editor/js/ui/view-navigator.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
RED.view.navigator = (function() {
|
||||||
|
|
||||||
|
var nav_scale = 25;
|
||||||
|
var nav_width = 5000/nav_scale;
|
||||||
|
var nav_height = 5000/nav_scale;
|
||||||
|
|
||||||
|
var navContainer;
|
||||||
|
var navBox;
|
||||||
|
var navBorder;
|
||||||
|
var navVis;
|
||||||
|
var scrollPos;
|
||||||
|
var scaleFactor;
|
||||||
|
var chartSize;
|
||||||
|
var dimensions;
|
||||||
|
var isDragging;
|
||||||
|
var isShowing = false;
|
||||||
|
|
||||||
|
function refreshNodes() {
|
||||||
|
if (!isShowing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var navNode = navVis.selectAll(".navnode").data(RED.view.getActiveNodes(),function(d){return d.id});
|
||||||
|
navNode.exit().remove();
|
||||||
|
navNode.enter().insert("rect")
|
||||||
|
.attr('class','navnode')
|
||||||
|
.attr("pointer-events", "none");
|
||||||
|
navNode.each(function(d) {
|
||||||
|
d3.select(this).attr("x",function(d) { return (d.x-d.w/2)/nav_scale })
|
||||||
|
.attr("y",function(d) { return (d.y-d.h/2)/nav_scale })
|
||||||
|
.attr("width",function(d) { return Math.max(9,d.w/nav_scale) })
|
||||||
|
.attr("height",function(d) { return Math.max(3,d.h/nav_scale) })
|
||||||
|
.attr("fill",function(d) { return d._def.color;})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function onScroll() {
|
||||||
|
if (!isDragging) {
|
||||||
|
resizeNavBorder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function resizeNavBorder() {
|
||||||
|
if (navBorder) {
|
||||||
|
scaleFactor = RED.view.scale();
|
||||||
|
chartSize = [ $("#chart").width(), $("#chart").height()];
|
||||||
|
scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
|
||||||
|
navBorder.attr('x',scrollPos[0]/nav_scale)
|
||||||
|
.attr('y',scrollPos[1]/nav_scale)
|
||||||
|
.attr('width',chartSize[0]/nav_scale/scaleFactor)
|
||||||
|
.attr('height',chartSize[1]/nav_scale/scaleFactor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function() {
|
||||||
|
|
||||||
|
$(window).resize(resizeNavBorder);
|
||||||
|
RED.events.on("sidebar:resize",resizeNavBorder);
|
||||||
|
|
||||||
|
var hideTimeout;
|
||||||
|
|
||||||
|
navContainer = $('<div>').css({
|
||||||
|
"position":"absolute",
|
||||||
|
"bottom":$("#workspace-footer").height(),
|
||||||
|
"right":0,
|
||||||
|
zIndex: 1
|
||||||
|
}).appendTo("#workspace").hide();
|
||||||
|
|
||||||
|
navBox = d3.select(navContainer[0])
|
||||||
|
.append("svg:svg")
|
||||||
|
.attr("width", nav_width)
|
||||||
|
.attr("height", nav_height)
|
||||||
|
.attr("pointer-events", "all")
|
||||||
|
.style({
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 0,
|
||||||
|
right:0,
|
||||||
|
zIndex: 101,
|
||||||
|
"border-left": "1px solid #ccc",
|
||||||
|
"border-top": "1px solid #ccc",
|
||||||
|
background: "rgba(245,245,245,0.5)",
|
||||||
|
"box-shadow": "-1px 0 3px rgba(0,0,0,0.1)"
|
||||||
|
});
|
||||||
|
|
||||||
|
navBox.append("rect").attr("x",0).attr("y",0).attr("width",nav_width).attr("height",nav_height).style({
|
||||||
|
fill:"none",
|
||||||
|
stroke:"none",
|
||||||
|
pointerEvents:"all"
|
||||||
|
}).on("mousedown", function() {
|
||||||
|
// Update these in case they have changed
|
||||||
|
scaleFactor = RED.view.scale();
|
||||||
|
chartSize = [ $("#chart").width(), $("#chart").height()];
|
||||||
|
dimensions = [chartSize[0]/nav_scale/scaleFactor, chartSize[1]/nav_scale/scaleFactor];
|
||||||
|
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||||
|
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||||
|
navBorder.attr('x',newX).attr('y',newY);
|
||||||
|
isDragging = true;
|
||||||
|
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||||
|
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||||
|
}).on("mousemove", function() {
|
||||||
|
if (!isDragging) { return }
|
||||||
|
if (d3.event.buttons === 0) {
|
||||||
|
isDragging = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var newX = Math.max(0,Math.min(d3.event.offsetX+dimensions[0]/2,nav_width)-dimensions[0]);
|
||||||
|
var newY = Math.max(0,Math.min(d3.event.offsetY+dimensions[1]/2,nav_height)-dimensions[1]);
|
||||||
|
navBorder.attr('x',newX).attr('y',newY);
|
||||||
|
$("#chart").scrollLeft(newX*nav_scale*scaleFactor);
|
||||||
|
$("#chart").scrollTop(newY*nav_scale*scaleFactor);
|
||||||
|
}).on("mouseup", function() {
|
||||||
|
isDragging = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
navBorder = navBox.append("rect")
|
||||||
|
.attr("stroke-dasharray","5,5")
|
||||||
|
.attr("pointer-events", "none")
|
||||||
|
.style({
|
||||||
|
stroke: "#999",
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: "white",
|
||||||
|
});
|
||||||
|
|
||||||
|
navVis = navBox.append("svg:g")
|
||||||
|
|
||||||
|
|
||||||
|
$("#btn-navigate").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (!isShowing) {
|
||||||
|
isShowing = true;
|
||||||
|
$("#btn-navigate").addClass("selected");
|
||||||
|
resizeNavBorder();
|
||||||
|
refreshNodes();
|
||||||
|
$("#chart").on("scroll",onScroll);
|
||||||
|
navContainer.fadeIn(200);
|
||||||
|
} else {
|
||||||
|
isShowing = false;
|
||||||
|
navContainer.fadeOut(100);
|
||||||
|
$("#chart").off("scroll",onScroll);
|
||||||
|
$("#btn-navigate").removeClass("selected");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refresh: refreshNodes,
|
||||||
|
resize: resizeNavBorder
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})();
|
@ -332,6 +332,8 @@ RED.view = (function() {
|
|||||||
redraw();
|
redraw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
RED.view.navigator.init();
|
||||||
|
|
||||||
$("#btn-zoom-out").click(function() {zoomOut();});
|
$("#btn-zoom-out").click(function() {zoomOut();});
|
||||||
$("#btn-zoom-zero").click(function() {zoomZero();});
|
$("#btn-zoom-zero").click(function() {zoomZero();});
|
||||||
$("#btn-zoom-in").click(function() {zoomIn();});
|
$("#btn-zoom-in").click(function() {zoomIn();});
|
||||||
@ -1060,17 +1062,20 @@ RED.view = (function() {
|
|||||||
function zoomIn() {
|
function zoomIn() {
|
||||||
if (scaleFactor < 2) {
|
if (scaleFactor < 2) {
|
||||||
scaleFactor += 0.1;
|
scaleFactor += 0.1;
|
||||||
|
RED.view.navigator.resize();
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function zoomOut() {
|
function zoomOut() {
|
||||||
if (scaleFactor > 0.3) {
|
if (scaleFactor > 0.3) {
|
||||||
scaleFactor -= 0.1;
|
scaleFactor -= 0.1;
|
||||||
|
RED.view.navigator.resize();
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function zoomZero() {
|
function zoomZero() {
|
||||||
scaleFactor = 1;
|
scaleFactor = 1;
|
||||||
|
RED.view.navigator.resize();
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2542,7 +2547,7 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
).classed("link_selected", false);
|
).classed("link_selected", false);
|
||||||
}
|
}
|
||||||
|
RED.view.navigator.refresh();
|
||||||
if (d3.event) {
|
if (d3.event) {
|
||||||
d3.event.preventDefault();
|
d3.event.preventDefault();
|
||||||
}
|
}
|
||||||
@ -2816,7 +2821,9 @@ RED.view = (function() {
|
|||||||
gridSize = Math.max(5,v);
|
gridSize = Math.max(5,v);
|
||||||
updateGrid();
|
updateGrid();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getActiveNodes: function() {
|
||||||
|
return activeNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -203,7 +203,7 @@
|
|||||||
height: 25px;
|
height: 25px;
|
||||||
line-height: 23px;
|
line-height: 23px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
.button-group:not(:last-child) {
|
.button-group:not(:last-child) {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
@ -227,6 +227,7 @@
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 17px;
|
line-height: 17px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
&.text-button {
|
&.text-button {
|
||||||
width: auto;
|
width: auto;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
|
@ -47,7 +47,9 @@
|
|||||||
.workspace-footer-button {
|
.workspace-footer-button {
|
||||||
@include component-footer-button;
|
@include component-footer-button;
|
||||||
}
|
}
|
||||||
|
.workspace-footer-button-toggle {
|
||||||
|
@include component-footer-button-toggle;
|
||||||
|
}
|
||||||
#workspace-footer {
|
#workspace-footer {
|
||||||
@include component-footer;
|
@include component-footer;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-out" href="#"><i class="fa fa-minus"></i></a>
|
||||||
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
||||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||||
|
<a class="workspace-footer-button-toggle" id="btn-navigate" href="#"><i class="fa fa-map-o"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div id="editor-shade" class="hide"></div>
|
<div id="editor-shade" class="hide"></div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user