blob: 6cacb7f64b9620a2cd03b9fd61e0057c2c6dc894 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/* global define, module, require, exports */
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery',
'd3',
'nf.Common',
'nf.CanvasUtils',
'nf.ContextMenu',
'nf.Label'],
function ($, d3, nfCommon, nfCanvasUtils, nfContextMenu, nfLabel) {
return (nf.Birdseye = factory($, d3, nfCommon, nfCanvasUtils, nfContextMenu, nfLabel));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.Birdseye =
factory(require('jquery'),
require('d3'),
require('nf.Common'),
require('nf.CanvasUtils'),
require('nf.ContextMenu'),
require('nf.Label')));
} else {
nf.Birdseye = factory(root.$,
root.d3,
root.nf.Common,
root.nf.CanvasUtils,
root.nf.ContextMenu,
root.nf.Label);
}
}(this, function ($, d3, nfCommon, nfCanvasUtils, nfContextMenu, nfLabel) {
'use strict';
var nfGraph;
var birdseyeGroup;
var componentGroup;
// refreshes the birdseye
var refresh = function (components) {
var translate = nfCanvasUtils.getCanvasTranslate();
var scale = nfCanvasUtils.getCanvasScale();
// scale the translation
translate = [translate[0] / scale, translate[1] / scale];
// get the bounding box for the graph and convert into canvas space
var graphBox = d3.select('#canvas').node().getBoundingClientRect();
var graphLeft = (graphBox.left / scale) - translate[0];
var graphTop = ((graphBox.top - nfCanvasUtils.getCanvasOffset()) / scale) - translate[1];
var graphRight = (graphBox.right / scale) - translate[0];
var graphBottom = (graphBox.bottom / scale) - translate[1];
// get the screen bounding box and convert into canvas space
var canvasContainer = $('#canvas-container');
var screenWidth = canvasContainer.width() / scale;
var screenHeight = canvasContainer.height() / scale;
var screenLeft = -translate[0];
var screenTop = -translate[1];
var screenRight = screenLeft + screenWidth;
var screenBottom = screenTop + screenHeight;
// determine the maximum size of the canvas given the graph and the visible portion on the screen
var canvasLeft = Math.min(graphLeft, screenLeft);
var canvasTop = Math.min(graphTop, screenTop);
var canvasRight = Math.max(graphRight, screenRight);
var canvasBottom = Math.max(graphBottom, screenBottom);
var canvasWidth = canvasRight - canvasLeft;
var canvasHeight = canvasBottom - canvasTop;
// get the width/height we have to work with
var birdseye = $('#birdseye');
var birdseyeWidth = birdseye.width();
var birdseyeHeight = birdseye.height();
// determine the appropriate scale for the birdseye (min scale to accomodate total width and height)
var birdseyeWidthScale = birdseyeWidth / canvasWidth;
var birdseyeHeightScale = birdseyeHeight / canvasHeight;
var birdseyeScale = Math.min(birdseyeWidthScale, birdseyeHeightScale);
// calculate the translation for the birdseye and the brush
var birdseyeTranslate = [0, 0];
var brushTranslate = [0, 0];
if (translate[0] < 0 && translate[1] < 0) {
birdseyeTranslate = [0, 0];
brushTranslate = [-translate[0], -translate[1]];
} else if (translate[0] >= 0 && translate[1] < 0) {
birdseyeTranslate = [translate[0], 0];
brushTranslate = [0, -translate[1]];
} else if (translate[0] < 0 && translate[1] >= 0) {
birdseyeTranslate = [0, translate[1]];
brushTranslate = [-translate[0], 0];
} else {
birdseyeTranslate = [translate[0], translate[1]];
brushTranslate = [0, 0];
}
// offset in case the graph has positive/negative coordinates and panning appropriately
var offsetX = 0;
var left = -graphLeft;
if (translate[0] < 0) {
if (translate[0] < left) {
offsetX = left;
} else {
offsetX = left - (left - translate[0]);
}
} else {
if (translate[0] < left) {
offsetX = left - translate[0];
}
}
var offsetY = 0;
var top = -graphTop;
if (translate[1] < 0) {
if (translate[1] < top) {
offsetY = top;
} else {
offsetY = top - (top - translate[1]);
}
} else {
if (translate[1] < top) {
offsetY = top - translate[1];
}
}
// adjust the translations of the birdseye and brush to account for the offset
birdseyeTranslate = [birdseyeTranslate[0] + offsetX, birdseyeTranslate[1] + offsetY];
brushTranslate = [brushTranslate[0] + offsetX, brushTranslate[1] + offsetY];
// update the birdseye
birdseyeGroup.attr('transform', 'scale(' + birdseyeScale + ')');
componentGroup.attr('transform', 'translate(' + birdseyeTranslate + ')');
// update the brush
d3.select('rect.birdseye-brush')
.attrs({
'width': screenWidth,
'height': screenHeight,
'stroke-width': (2 / birdseyeScale),
'transform': function (d) {
d.x = brushTranslate[0];
d.y = brushTranslate[1];
return 'translate(' + brushTranslate + ')';
}
});
// redraw the canvas
var canvasElement = d3.select('#birdseye-canvas').node();
var context = canvasElement.getContext('2d');
context.save();
// clear the current canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvasElement.width, canvasElement.height);
context.restore();
context.save();
// apply the current transformation
context.translate(birdseyeTranslate[0] * birdseyeScale, birdseyeTranslate[1] * birdseyeScale);
context.scale(birdseyeScale, birdseyeScale);
// labels
$.each(components.labels, function (_, d) {
var color = nfLabel.defaultColor();
if (d.permissions.canRead) {
// use the specified color if appropriate
if (nfCommon.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
}
context.fillStyle = color;
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
// funnels
context.fillStyle = '#ad9897';
$.each(components.funnels, function (_, d) {
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
// ports
context.fillStyle = '#bbdcde';
$.each(components.ports, function (_, d) {
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
// remote process groups
context.fillStyle = '#728e9b';
$.each(components.remoteProcessGroups, function (_, d) {
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
// process groups
$.each(components.processGroups, function (_, d) {
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
// processors
$.each(components.processors, function (_, d) {
//default color
var color = '#dde4eb';
if (d.permissions.canRead) {
// use the specified color if appropriate
if (nfCommon.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
//if the background color is #ffffff use the default instead
if (color === '#ffffff') {
color = '#dde4eb';
}
}
}
context.fillStyle = color;
context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
});
context.restore();
};
// whether or not the birdseye is open, don't adjust unless necessary
var visible = true;
var nfBirdseye = {
/**
* Initializes of the graph controller.
*
* @param nfGraphRef The nfConnectable module.
*/
init: function (nfGraphRef) {
nfGraph = nfGraphRef;
var birdseye = $('#birdseye');
d3.select('#birdseye').append('canvas')
.attr('id', 'birdseye-canvas')
.attr('width', birdseye.width())
.attr('height', birdseye.height());
// build the birdseye svg
var svg = d3.select('#birdseye').append('svg')
.attr('width', birdseye.width())
.attr('height', birdseye.height());
// group birdseye components together
birdseyeGroup = svg.append('g')
.attr('class', 'birdseye');
// processor in the birdseye
componentGroup = birdseyeGroup.append('g')
.attr('pointer-events', 'none');
// define the brush drag behavior
var brush = d3.drag()
.subject(function (d) {
return {
x: d.x,
y: d.y,
source: 'birdseye'
};
})
.on('drag', function (d) {
d.x += d3.event.dx;
d.y += d3.event.dy;
// update the location of the brush
d3.select(this).attr('transform', function () {
return 'translate(' + d.x + ', ' + d.y + ')';
});
// transform the canvas
nfCanvasUtils.translateCanvas([-d3.event.dx, -d3.event.dy]);
})
.on('end', function () {
// update component visibility
nfGraph.updateVisibility();
// persist the users view
nfCanvasUtils.persistUserView();
// refresh the birdseye
nfBirdseye.refresh();
});
// context area
birdseyeGroup.append('g')
.attrs({
'pointer-events': 'all',
'class': 'birdseye-brush-container'
})
.append('rect')
.attr('class', 'birdseye-brush moveable')
.datum({
x: 0,
y: 0
})
.call(brush);
},
/**
* Handles rendering of the birdseye tool.
*/
refresh: function () {
if (visible) {
refresh(nfGraph.get());
}
},
/**
* Function that needs to be call when the birdseye visibility changes.
*
* @param {boolean} isVisible
*/
updateBirdseyeVisibility: function (isVisible) {
var birdseye = $('#birdseye');
// update the outline collapse icon
if (isVisible) {
// show the outline
birdseye.show();
visible = true;
// refresh the birdseye as it may have changed
refresh(nfGraph.get());
} else {
// hide the outline
birdseye.hide();
visible = false;
}
}
};
return nfBirdseye;
}));