blob: 056769930f58b1d7ed40ac2487368f2a60fcf2de [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.Client',
'nf.ClusterSummary',
'nf.CanvasUtils'],
function ($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils) {
return (nf.Processor = factory($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.Processor =
factory(require('jquery'),
require('d3'),
require('nf.Common'),
require('nf.Client'),
require('nf.ClusterSummary'),
require('nf.CanvasUtils')));
} else {
nf.Processor = factory(root.$,
root.d3,
root.nf.Common,
root.nf.Client,
root.nf.ClusterSummary,
root.nf.CanvasUtils);
}
}(this, function ($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils) {
'use strict';
var nfConnectable;
var nfDraggable;
var nfSelectable;
var nfQuickSelect;
var nfContextMenu;
var PREVIEW_NAME_LENGTH = 25;
// default dimensions for each type of component
var dimensions = {
width: 352,
height: 128
};
// ---------------------------------
// processors currently on the graph
// ---------------------------------
var processorMap;
// -----------------------------------------------------------
// cache for components that are added/removed from the canvas
// -----------------------------------------------------------
var removedCache;
var addedCache;
// --------------------
// component containers
// --------------------
var processorContainer;
// --------------------------
// privately scoped functions
// --------------------------
/**
* Selects the processor elements against the current processor map.
*/
var select = function () {
return processorContainer.selectAll('g.processor').data(processorMap.values(), function (d) {
return d.id;
});
};
/**
* Renders the processors in the specified selection.
*
* @param {selection} entered The selection of processors to be rendered
* @param {boolean} selected Whether the element should be selected
* @return the entered selection
*/
var renderProcessors = function (entered, selected) {
if (entered.empty()) {
return entered;
}
var processor = entered.append('g')
.attrs({
'id': function (d) {
return 'id-' + d.id;
},
'class': 'processor component'
})
.classed('selected', selected)
.call(nfCanvasUtils.position);
// processor border
processor.append('rect')
.attrs({
'class': 'border',
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
},
'fill': 'transparent',
'stroke': 'transparent'
});
// processor body
processor.append('rect')
.attrs({
'class': 'body',
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
});
// processor name
processor.append('text')
.attrs({
'x': 75,
'y': 18,
'width': 230,
'height': 14,
'class': 'processor-name'
});
// processor icon container
processor.append('rect')
.attrs({
'x': 0,
'y': 0,
'width': 50,
'height': 50,
'class': 'processor-icon-container'
});
// processor icon
processor.append('text')
.attrs({
'x': 9,
'y': 35,
'class': 'processor-icon'
})
.text('\ue807');
// restricted icon background
processor.append('circle')
.attrs({
'r': 9,
'cx': 12,
'cy': 12,
'class': 'restricted-background'
});
// restricted icon
processor.append('text')
.attrs({
'x': 7.75,
'y': 17,
'class': 'restricted'
})
.text('\uf132');
// is primary icon background
processor.append('circle')
.attrs({
'r': 9,
'cx': 38,
'cy': 36,
'class': 'is-primary-background'
});
// is primary icon
processor.append('text')
.attrs({
'x': 34.75,
'y': 40,
'class': 'is-primary'
})
.text('P')
.append('title').text(function (d) {
return 'This component is only scheduled to execute on the Primary Node';
});
// make processors selectable
processor.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate);
return processor;
};
/**
* Updates the processors in the specified selection.
*
* @param {selection} updated The processors to update
*/
var updateProcessors = function (updated) {
if (updated.empty()) {
return;
}
// processor border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.permissions.canRead === false;
})
.classed('ghost', function (d) {
return d.permissions.canRead === true && d.component.extensionMissing === true;
});
// processor body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.permissions.canRead === false;
});
updated.each(function (processorData) {
var processor = d3.select(this);
var details = processor.select('g.processor-canvas-details');
// update the component behavior as appropriate
nfCanvasUtils.editable(processor, nfConnectable, nfDraggable);
// if this processor is visible, render everything
if (processor.classed('visible')) {
if (details.empty()) {
details = processor.append('g').attr('class', 'processor-canvas-details');
// run status icon
details.append('text')
.attrs({
'class': 'run-status-icon',
'x': 55,
'y': 23,
'width': 14,
'height': 14
});
// processor type
details.append('text')
.attrs({
'class': 'processor-type',
'x': 75,
'y': 32,
'width': 230,
'height': 12
});
// processor type
details.append('text')
.attrs({
'class': 'processor-bundle',
'x': 75,
'y': 45,
'width': 200,
'height': 12
});
// -----
// stats
// -----
// draw the processor statistics table
// in
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 19,
'x': 0,
'y': 50,
'fill': '#f4f6f7'
});
// border
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 1,
'x': 0,
'y': 68,
'fill': '#c7d2d7'
});
// read/write
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 19,
'x': 0,
'y': 69,
'fill': '#ffffff'
});
// border
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 1,
'x': 0,
'y': 87,
'fill': '#c7d2d7'
});
// out
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 20,
'x': 0,
'y': 88,
'fill': '#f4f6f7'
});
// border
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 1,
'x': 0,
'y': 106,
'fill': '#c7d2d7'
});
// tasks/time
details.append('rect')
.attrs({
'width': function () {
return processorData.dimensions.width;
},
'height': 19,
'x': 0,
'y': 107,
'fill': '#ffffff'
});
// stats label container
var processorStatsLabel = details.append('g')
.attrs({
'transform': 'translate(10, 55)'
});
// in label
processorStatsLabel.append('text')
.attrs({
'width': 73,
'height': 10,
'y': 9,
'class': 'stats-label'
})
.text('In');
// read/write label
processorStatsLabel.append('text')
.attrs({
'width': 73,
'height': 10,
'y': 27,
'class': 'stats-label'
})
.text('Read/Write');
// out label
processorStatsLabel.append('text')
.attrs({
'width': 73,
'height': 10,
'y': 46,
'class': 'stats-label'
})
.text('Out');
// tasks/time label
processorStatsLabel.append('text')
.attrs({
'width': 73,
'height': 10,
'y': 65,
'class': 'stats-label'
})
.text('Tasks/Time');
// stats value container
var processorStatsValue = details.append('g')
.attrs({
'transform': 'translate(85, 55)'
});
// in value
var inText = processorStatsValue.append('text')
.attrs({
'width': 180,
'height': 9,
'y': 9,
'class': 'processor-in stats-value'
});
// in count
inText.append('tspan')
.attrs({
'class': 'count'
});
// in size
inText.append('tspan')
.attrs({
'class': 'size'
});
// read/write value
processorStatsValue.append('text')
.attrs({
'width': 180,
'height': 10,
'y': 27,
'class': 'processor-read-write stats-value'
});
// out value
var outText = processorStatsValue.append('text')
.attrs({
'width': 180,
'height': 10,
'y': 46,
'class': 'processor-out stats-value'
});
// out count
outText.append('tspan')
.attrs({
'class': 'count'
});
// out size
outText.append('tspan')
.attrs({
'class': 'size'
});
// tasks/time value
processorStatsValue.append('text')
.attrs({
'width': 180,
'height': 10,
'y': 65,
'class': 'processor-tasks-time stats-value'
});
// stats value container
var processorStatsInfo = details.append('g')
.attr('transform', 'translate(305, 55)');
// in info
processorStatsInfo.append('text')
.attrs({
'width': 25,
'height': 10,
'y': 9,
'class': 'stats-info'
})
.text('5 min');
// read/write info
processorStatsInfo.append('text')
.attrs({
'width': 25,
'height': 10,
'y': 27,
'class': 'stats-info'
})
.text('5 min');
// out info
processorStatsInfo.append('text')
.attrs({
'width': 25,
'height': 10,
'y': 46,
'class': 'stats-info'
})
.text('5 min');
// tasks/time info
processorStatsInfo.append('text')
.attrs({
'width': 25,
'height': 10,
'y': 65,
'class': 'stats-info'
})
.text('5 min');
// --------
// comments
// --------
details.append('path')
.attrs({
'class': 'component-comments',
'transform': 'translate(' + (processorData.dimensions.width - 2) + ', ' + (processorData.dimensions.height - 10) + ')',
'd': 'm0,0 l0,8 l-8,0 z'
});
// -------------------
// active thread count
// -------------------
// active thread count
details.append('text')
.attrs({
'class': 'active-thread-count-icon',
'y': 46
})
.text('\ue83f');
// active thread background
details.append('text')
.attrs({
'class': 'active-thread-count',
'y': 46
});
// ---------
// bulletins
// ---------
// bulletin background
details.append('rect')
.attrs({
'class': 'bulletin-background',
'x': function (d) {
return processorData.dimensions.width - 24;
},
'width': 24,
'height': 24
});
// bulletin icon
details.append('text')
.attrs({
'class': 'bulletin-icon',
'x': function (d) {
return processorData.dimensions.width - 17;
},
'y': 17
})
.text('\uf24a');
}
if (processorData.permissions.canRead) {
// update the processor name
processor.select('text.processor-name')
.each(function (d) {
var processorName = d3.select(this);
// reset the processor name to handle any previous state
processorName.text(null).selectAll('title').remove();
// apply ellipsis to the processor name as necessary
nfCanvasUtils.ellipsis(processorName, d.component.name, 'processor-name');
}).append('title').text(function (d) {
return d.component.name;
});
// update the processor type
processor.select('text.processor-type')
.each(function (d) {
var processorType = d3.select(this);
// reset the processor type to handle any previous state
processorType.text(null).selectAll('title').remove();
// apply ellipsis to the processor type as necessary
nfCanvasUtils.ellipsis(processorType, nfCommon.formatType(d.component), 'processor-type');
}).append('title').text(function (d) {
return nfCommon.formatType(d.component);
});
// update the processor bundle
processor.select('text.processor-bundle')
.each(function (d) {
var processorBundle = d3.select(this);
// reset the processor type to handle any previous state
processorBundle.text(null).selectAll('title').remove();
// apply ellipsis to the processor type as necessary
nfCanvasUtils.ellipsis(processorBundle, nfCommon.formatBundle(d.component.bundle), 'processor-bundle');
}).append('title').text(function (d) {
return nfCommon.formatBundle(d.component.bundle);
});
// update the processor comments
processor.select('path.component-comments')
.style('visibility', nfCommon.isBlank(processorData.component.config.comments) ? 'hidden' : 'visible')
.each(function () {
// get the tip
var tip = d3.select('#comments-tip-' + processorData.id);
// if there are validation errors generate a tooltip
if (nfCommon.isBlank(processorData.component.config.comments)) {
// remove the tip if necessary
if (!tip.empty()) {
tip.remove();
}
} else {
// create the tip if necessary
if (tip.empty()) {
tip = d3.select('#processor-tooltips').append('div')
.attr('id', function () {
return 'comments-tip-' + processorData.id;
})
.attr('class', 'tooltip nifi-tooltip');
}
// update the tip
tip.text(processorData.component.config.comments);
// add the tooltip
nfCanvasUtils.canvasTooltip(tip, d3.select(this));
}
});
} else {
// clear the processor name
processor.select('text.processor-name').text(null);
// clear the processor type
processor.select('text.processor-type').text(null);
// clear the processor bundle
processor.select('text.processor-bundle').text(null);
// clear the processor comments
processor.select('path.component-comments').style('visibility', 'hidden');
// clear tooltips
processor.call(removeTooltips);
}
// populate the stats
processor.call(updateProcessorStatus);
} else {
if (processorData.permissions.canRead) {
// update the processor name
processor.select('text.processor-name')
.text(function (d) {
var name = d.component.name;
if (name.length > PREVIEW_NAME_LENGTH) {
return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
} else {
return name;
}
});
} else {
// clear the processor name
processor.select('text.processor-name').text(null);
}
// remove the tooltips
processor.call(removeTooltips);
// remove the details if necessary
if (!details.empty()) {
details.remove();
}
}
// ---------------
// processor color
// ---------------
//update the processor icon container
processor.select('rect.processor-icon-container').classed('unauthorized', !processorData.permissions.canRead);
//update the processor icon
processor.select('text.processor-icon').classed('unauthorized', !processorData.permissions.canRead);
//update the processor border
processor.select('rect.border').classed('unauthorized', !processorData.permissions.canRead);
// use the specified color if appropriate
if (processorData.permissions.canRead) {
if (nfCommon.isDefinedAndNotNull(processorData.component.style['background-color'])) {
var color = processorData.component.style['background-color'];
//update the processor icon container
processor.select('rect.processor-icon-container')
.style('fill', function (d) {
return color;
});
//update the processor border
processor.select('rect.border')
.style('stroke', function (d) {
return color;
});
}
}
// update the processor color
processor.select('text.processor-icon')
.style('fill', function (d) {
// get the default color
var color = nfProcessor.defaultIconColor();
if (!d.permissions.canRead) {
return color;
}
// use the specified color if appropriate
if (nfCommon.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
//special case #ffffff implies default fill
if (color.toLowerCase() === '#ffffff') {
color = nfProcessor.defaultIconColor();
} else {
color = nfCommon.determineContrastColor(
nfCommon.substringAfterLast(
color, '#'));
}
}
return color;
});
// restricted component indicator
processor.select('circle.restricted-background').style('visibility', showRestricted);
processor.select('text.restricted').style('visibility', showRestricted);
// is primary component indicator
processor.select('circle.is-primary-background').style('visibility', showIsPrimary);
processor.select('text.is-primary').style('visibility', showIsPrimary);
});
};
/**
* Returns whether the resticted indicator should be shown for a given component
* @param d
* @returns {*}
*/
var showRestricted = function (d) {
if (!d.permissions.canRead) {
return 'hidden';
}
return d.component.restricted ? 'visible' : 'hidden';
};
/**
* Returns whether the is primary indicator should be shown for a given component
* @param d
* @returns {*}
*/
var showIsPrimary = function (d) {
return nfClusterSummary.isClustered() && d.status.aggregateSnapshot.executionNode === 'PRIMARY' ? 'visible' : 'hidden';
};
/**
* Determines whether the specific component needs a tooltip.
*
* @param d
* @return if a tip is required
*/
var needsTip = function (d) {
return (d.permissions.canRead && !nfCommon.isEmpty(d.component.validationErrors)) || d.status.aggregateSnapshot.runStatus === 'Validating';
};
/**
* Gets the tooltip content.
*
* @param d
* @return the tip content
*/
var getTip = function (d) {
if (d.permissions.canRead && !nfCommon.isEmpty(d.component.validationErrors)) {
var list = nfCommon.formatUnorderedList(d.component.validationErrors);
if (list === null || list.length === 0) {
return '';
} else {
return list;
}
} else {
return 'Validating...';
}
};
/**
* Updates the stats for the processors in the specified selection.
*
* @param {selection} updated The processors to update
*/
var updateProcessorStatus = function (updated) {
if (updated.empty()) {
return;
}
// update the run status
updated.select('text.run-status-icon')
.attrs({
'fill': function (d) {
var fill = '#728e9b';
if (d.status.aggregateSnapshot.runStatus === 'Validating') {
fill = '#a8a8a8';
} else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
fill = '#cf9f5d';
} else if (d.status.aggregateSnapshot.runStatus === 'Running') {
fill = '#7dc7a0';
} else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
fill = '#d18686';
}
return fill;
},
'font-family': function (d) {
var family = 'FontAwesome';
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
family = 'flowfont';
}
return family;
}
})
.classed('fa-spin', function (d) {
return d.status.aggregateSnapshot.runStatus === 'Validating';
})
.text(function (d) {
var img = '';
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
img = '\ue802';
} else if (d.status.aggregateSnapshot.runStatus === 'Validating') {
img = '\uf1ce';
} else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
img = '\uf071';
} else if (d.status.aggregateSnapshot.runStatus === 'Running') {
img = '\uf04b';
} else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
img = '\uf04d';
}
return img;
})
.each(function (d) {
// get the tip
var tip = d3.select('#run-status-tip-' + d.id);
// if there are validation errors generate a tooltip
if (needsTip(d)) {
// create the tip if necessary
if (tip.empty()) {
tip = d3.select('#processor-tooltips').append('div')
.attr('id', function () {
return 'run-status-tip-' + d.id;
})
.attr('class', 'tooltip nifi-tooltip');
}
// update the tip
tip.html(function () {
return $('<div></div>').append(getTip(d)).html();
});
// add the tooltip
nfCanvasUtils.canvasTooltip(tip, d3.select(this));
} else {
// remove the tip if necessary
if (!tip.empty()) {
tip.remove();
}
}
});
// in count value
updated.select('text.processor-in tspan.count')
.text(function (d) {
return nfCommon.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
});
// in size value
updated.select('text.processor-in tspan.size')
.text(function (d) {
return ' ' + nfCommon.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
});
// read/write value
updated.select('text.processor-read-write')
.text(function (d) {
return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
});
// out count value
updated.select('text.processor-out tspan.count')
.text(function (d) {
return nfCommon.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
});
// out size value
updated.select('text.processor-out tspan.size')
.text(function (d) {
return ' ' + nfCommon.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
});
// tasks/time value
updated.select('text.processor-tasks-time')
.text(function (d) {
return d.status.aggregateSnapshot.tasks + ' / ' + d.status.aggregateSnapshot.tasksDuration;
});
updated.each(function (d) {
var processor = d3.select(this);
// -------------------
// active thread count
// -------------------
nfCanvasUtils.activeThreadCount(processor, d);
// ---------
// bulletins
// ---------
processor.select('rect.bulletin-background').classed('has-bulletins', function () {
return !nfCommon.isEmpty(d.status.aggregateSnapshot.bulletins);
});
nfCanvasUtils.bulletins(processor, d, function () {
return d3.select('#processor-tooltips');
}, 286);
});
};
/**
* Removes the processors in the specified selection.
*
* @param {selection} removed
*/
var removeProcessors = function (removed) {
if (removed.empty()) {
return;
}
removed.call(removeTooltips).remove();
};
/**
* Removes the tooltips for the processors in the specified selection.
*
* @param {selection} removed
*/
var removeTooltips = function (removed) {
removed.each(function (d) {
// remove any associated tooltips
$('#run-status-tip-' + d.id).remove();
$('#bulletin-tip-' + d.id).remove();
$('#comments-tip-' + d.id).remove();
});
};
var nfProcessor = {
/**
* Initializes of the Processor handler.
*
* @param nfConnectableRef The nfConnectable module.
* @param nfDraggableRef The nfDraggable module.
* @param nfSelectableRef The nfSelectable module.
* @param nfContextMenuRef The nfContextMenu module.
* @param nfQuickSelectRef The nfQuickSelect module.
*/
init: function (nfConnectableRef, nfDraggableRef, nfSelectableRef, nfContextMenuRef, nfQuickSelectRef) {
nfConnectable = nfConnectableRef;
nfDraggable = nfDraggableRef;
nfSelectable = nfSelectableRef;
nfContextMenu = nfContextMenuRef;
nfQuickSelect = nfQuickSelectRef;
processorMap = d3.map();
removedCache = d3.map();
addedCache = d3.map();
// create the processor container
processorContainer = d3.select('#canvas').append('g')
.attrs({
'pointer-events': 'all',
'class': 'processors'
});
},
/**
* Adds the specified processor entity.
*
* @param processorEntities The processor
* @param options Configuration options
*/
add: function (processorEntities, options) {
var selectAll = false;
if (nfCommon.isDefinedAndNotNull(options)) {
selectAll = nfCommon.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
// get the current time
var now = new Date().getTime();
var add = function (processorEntity) {
addedCache.set(processorEntity.id, now);
// add the processor
processorMap.set(processorEntity.id, $.extend({
type: 'Processor',
dimensions: dimensions
}, processorEntity));
};
// determine how to handle the specified processor
if ($.isArray(processorEntities)) {
$.each(processorEntities, function (_, processorEntity) {
add(processorEntity);
});
} else if (nfCommon.isDefinedAndNotNull(processorEntities)) {
add(processorEntities);
}
// select
var selection = select();
// enter
var entered = renderProcessors(selection.enter(), selectAll);
// update
updateProcessors(selection.merge(entered));
},
/**
* Populates the graph with the specified processors.
*
* @argument {object | array} processorEntities The processors to add
* @argument {object} options Configuration options
*/
set: function (processorEntities, options) {
var selectAll = false;
var transition = false;
var overrideRevisionCheck = false;
if (nfCommon.isDefinedAndNotNull(options)) {
selectAll = nfCommon.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nfCommon.isDefinedAndNotNull(options.transition) ? options.transition : transition;
overrideRevisionCheck = nfCommon.isDefinedAndNotNull(options.overrideRevisionCheck) ? options.overrideRevisionCheck : overrideRevisionCheck;
}
var set = function (proposedProcessorEntity) {
var currentProcessorEntity = processorMap.get(proposedProcessorEntity.id);
// set the processor if appropriate due to revision and wasn't previously removed
if ((nfClient.isNewerRevision(currentProcessorEntity, proposedProcessorEntity) && !removedCache.has(proposedProcessorEntity.id)) || overrideRevisionCheck === true) {
processorMap.set(proposedProcessorEntity.id, $.extend({
type: 'Processor',
dimensions: dimensions
}, proposedProcessorEntity));
}
};
// determine how to handle the specified processor
if ($.isArray(processorEntities)) {
$.each(processorMap.keys(), function (_, key) {
var currentProcessorEntity = processorMap.get(key);
var isPresent = $.grep(processorEntities, function (proposedProcessorEntity) {
return proposedProcessorEntity.id === currentProcessorEntity.id;
});
// if the current processor is not present and was not recently added, remove it
if (isPresent.length === 0 && !addedCache.has(key)) {
processorMap.remove(key);
}
});
$.each(processorEntities, function (_, processorEntity) {
set(processorEntity);
});
} else if (nfCommon.isDefinedAndNotNull(processorEntities)) {
set(processorEntities);
}
// select
var selection = select();
// enter
var entered = renderProcessors(selection.enter(), selectAll);
// update
var updated = selection.merge(entered);
updated.call(updateProcessors);
updated.call(nfCanvasUtils.position, transition);
// exit
selection.exit().call(removeProcessors);
},
/**
* If the processor id is specified it is returned. If no processor id
* specified, all processors are returned.
*
* @param {string} id
*/
get: function (id) {
if (nfCommon.isUndefined(id)) {
return processorMap.values();
} else {
return processorMap.get(id);
}
},
/**
* If the processor id is specified it is refresh according to the current
* state. If not processor id is specified, all processors are refreshed.
*
* @param {string} id Optional
*/
refresh: function (id) {
if (nfCommon.isDefinedAndNotNull(id)) {
d3.select('#id-' + id).call(updateProcessors);
} else {
d3.selectAll('g.processor').call(updateProcessors);
}
},
/**
* Positions the component.
*
* @param {string} id The id
*/
position: function (id) {
d3.select('#id-' + id).call(nfCanvasUtils.position);
},
/**
* Refreshes the components necessary after a pan event.
*/
pan: function () {
d3.selectAll('g.processor.entering, g.processor.leaving').call(updateProcessors);
},
/**
* Reloads the processor state from the server and refreshes the UI.
* If the processor is currently unknown, this function just returns.
*
* @param {string} id The processor id
*/
reload: function (id) {
if (processorMap.has(id)) {
var processorEntity = processorMap.get(id);
return $.ajax({
type: 'GET',
url: processorEntity.uri,
dataType: 'json'
}).done(function (response) {
nfProcessor.set(response);
});
}
},
/**
* Removes the specified processor.
*
* @param {array|string} processorIds The processors
*/
remove: function (processorIds) {
var now = new Date().getTime();
if ($.isArray(processorIds)) {
$.each(processorIds, function (_, processorId) {
removedCache.set(processorId, now);
processorMap.remove(processorId);
});
} else {
removedCache.set(processorIds, now);
processorMap.remove(processorIds);
}
// apply the selection and handle all removed processors
select().exit().call(removeProcessors);
},
/**
* Removes all processors.
*/
removeAll: function () {
nfProcessor.remove(processorMap.keys());
},
/**
* Expires the caches up to the specified timestamp.
*
* @param timestamp
*/
expireCaches: function (timestamp) {
var expire = function (cache) {
cache.each(function (entryTimestamp, id) {
if (timestamp > entryTimestamp) {
cache.remove(id);
}
});
};
expire(addedCache);
expire(removedCache);
},
/**
* Returns the default fill color that should be used when drawing a processor.
*/
defaultFillColor: function () {
return '#FFFFFF';
},
/**
* Returns the default icon color that should be used when drawing a processor.
*/
defaultIconColor: function () {
return '#ad9897';
}
};
return nfProcessor;
}));