[Style] JSLint Compliance

This commit is contained in:
Pete Richards 2015-08-14 11:39:05 -07:00
parent a0dc3da8fb
commit 056b3f61ce
4 changed files with 228 additions and 210 deletions

View File

@ -7,15 +7,17 @@ define(
// TODO: Store this in more accessible locations / retrieve from
// domainObject metadata.
var DOMAIN_INTERVAL = 1 * 60 * 1000; // One minute.
var DOMAIN_INTERVAL = 2 * 60 * 1000; // Two minutes.
function PlotController($scope, colorService) {
var plotHistory = [];
var isLive = true;
var maxDomain = +new Date();
var subscriptions = [];
var palette = new colorService.ColorPalette();
var setToDefaultViewport = function() {
var plotHistory = [],
isLive = true,
maxDomain = +new Date(),
subscriptions = [],
palette = new colorService.ColorPalette();
function setToDefaultViewport() {
// TODO: We shouldn't set the viewport until we have received data or something has given us a reasonable viewport.
$scope.viewport = {
topLeft: {
@ -27,15 +29,15 @@ define(
range: -1
}
};
};
}
setToDefaultViewport();
$scope.displayableRange = function(rangeValue) {
$scope.displayableRange = function (rangeValue) {
// TODO: Call format function provided by domain object.
return rangeValue;
};
$scope.displayableDomain = function(domainValue) {
$scope.displayableDomain = function (domainValue) {
// TODO: Call format function provided by domain object.
return new Date(domainValue).toUTCString();
};
@ -44,25 +46,33 @@ define(
$scope.rectangles = [];
var updateSeriesFromTelemetry = function(series, seriesIndex, telemetry) {
var domainValue = telemetry.getDomainValue(telemetry.getPointCount() - 1);
var rangeValue = telemetry.getRangeValue(telemetry.getPointCount() - 1);
function updateSeriesFromTelemetry(series, seriesIndex, telemetry) {
var domainValue = telemetry.getDomainValue(
telemetry.getPointCount() - 1
),
rangeValue = telemetry.getRangeValue(
telemetry.getPointCount() - 1
),
newTelemetry;
// Track the biggest domain we've seen for sticky-ness.
maxDomain = Math.max(maxDomain, domainValue);
var newTelemetry = {
newTelemetry = {
domain: domainValue,
range: rangeValue
};
series.data.push(newTelemetry);
$scope.$broadcast('series:data:add', seriesIndex, [newTelemetry]);
};
}
var subscribeToDomainObject = function(domainObject) {
var telemetryCapability = domainObject.getCapability('telemetry');
var model = domainObject.getModel();
function subscribeToDomainObject(domainObject) {
var telemetryCapability = domainObject.getCapability('telemetry'),
model = domainObject.getModel(),
series,
seriesIndex,
updater;
var series = {
series = {
name: model.name,
// TODO: Bring back PlotPalette.
color: palette.getColor($scope.series.length),
@ -70,17 +80,25 @@ define(
};
$scope.series.push(series);
var seriesIndex = $scope.series.indexOf(series);
seriesIndex = $scope.series.indexOf(series);
var updater = updateSeriesFromTelemetry.bind(
updater = updateSeriesFromTelemetry.bind(
null,
series,
seriesIndex
);
subscriptions.push(telemetryCapability.subscribe(updater));
};
}
var linkDomainObject = function(domainObject) {
function unlinkDomainObject() {
subscriptions.forEach(function(subscription) {
subscription.unsubscribe();
});
subscriptions = [];
}
function linkDomainObject(domainObject) {
unlinkDomainObject();
if (domainObject.hasCapability('telemetry')) {
subscribeToDomainObject(domainObject);
@ -98,23 +116,17 @@ define(
} else {
throw new Error('Domain object type not supported.');
}
};
}
var unlinkDomainObject = function() {
subscriptions.forEach(function(subscription) {
subscription.unsubscribe();
});
subscriptions = [];
};
var onUserViewportChangeStart = function() {
function onUserViewportChangeStart() {
// TODO: this is a great time to track a history entry.
// Disable live mode so they have full control of viewport.
plotHistory.push($scope.viewport);
isLive = false;
};
}
var onUserViewportChangeEnd = function(event, viewport) {
function onUserViewportChangeEnd(event, viewport) {
// If the new viewport is "close enough" to the maxDomain then
// enable live mode. Set empirically to 10% of the domain
// interval.
@ -127,10 +139,10 @@ define(
isLive = false;
}
plotHistory.push(viewport);
};
}
var viewportForMaxDomain = function() {
var viewport = {
function viewportForMaxDomain() {
return {
topLeft: {
range: $scope.viewport.topLeft.range,
domain: maxDomain - DOMAIN_INTERVAL
@ -140,14 +152,13 @@ define(
domain: maxDomain
}
};
return viewport;
};
}
var followDataIfLive = function() {
function followDataIfLive() {
if (isLive) {
$scope.viewport = viewportForMaxDomain();
}
};
}
$scope.$on('series:data:add', followDataIfLive);
$scope.$on('user:viewport:change:end', onUserViewportChangeEnd);
@ -155,7 +166,7 @@ define(
$scope.$watch('domainObject', linkDomainObject);
var controller = {
return {
historyBack: function() {
// TODO: Step History Back.
},
@ -166,8 +177,6 @@ define(
// TODO: Reset view to defaults. Keep history stack alive?
}
};
return controller;
}
return PlotController;

View File

@ -51,24 +51,6 @@ define(
return;
}
function redraw() {
if (isDestroyed) {
return;
}
requestAnimationFrame(redraw);
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
drawAPI.clear();
createOffset();
if (!offset) {
return;
}
updateViewport();
drawSeries();
drawRectangles();
}
function createOffset() {
if (offset) {
return;
@ -84,18 +66,30 @@ define(
);
}
function drawIfResized() {
if (canvas.width !== canvas.offsetWidth ||
canvas.height !== canvas.offsetHeight) {
redraw();
}
}
function destroyChart() {
isDestroyed = true;
if (activeInterval) {
$interval.cancel(activeInterval);
function lineFromSeries(series) {
// TODO: handle when lines get longer than 10,000 points.
// Each line allocates 10,000 points. This should be more
// that we ever need, but we have to decide how to handle
// this at the higher level. I imagine the plot controller
// should watch it's series and when they get huge, slice
// them in half and delete the oldest half.
//
// As long as the controller replaces $scope.series with a
// new series object, then this directive will
// automatically generate new arrays for those lines.
// In practice, the overhead of regenerating these lines
// appears minimal.
var lineBuffer = new Float32Array(20000),
i = 0;
for (i = 0; i < series.data.length; i++) {
lineBuffer[2*i] = offset.domain(series.data[i].domain);
lineBuffer[2*i+1] = offset.range(series.data[i].range);
}
return {
color: series.color,
buffer: lineBuffer,
pointCount: series.data.length
};
}
function drawSeries() {
@ -132,7 +126,10 @@ define(
}
function updateViewport() {
var dimensions = [
var dimensions,
origin;
dimensions = [
Math.abs(
offset.domain($scope.viewport.topLeft.domain) -
offset.domain($scope.viewport.bottomRight.domain)
@ -143,7 +140,7 @@ define(
)
];
var origin = [
origin = [
offset.domain(
$scope.viewport.topLeft.domain
),
@ -158,31 +155,6 @@ define(
);
}
function lineFromSeries(series) {
// TODO: handle when lines get longer than 10,000 points.
// Each line allocates 10,000 points. This should be more
// that we ever need, but we have to decide how to handle
// this at the higher level. I imagine the plot controller
// should watch it's series and when they get huge, slice
// them in half and delete the oldest half.
//
// As long as the controller replaces $scope.series with a
// new series object, then this directive will
// automatically generate new arrays for those lines.
// In practice, the overhead of regenerating these lines
// appears minimal.
var lineBuffer = new Float32Array(20000);
for (var i = 0; i < series.data.length; i++) {
lineBuffer[2*i] = offset.domain(series.data[i].domain);
lineBuffer[2*i+1] = offset.range(series.data[i].range);
}
return {
color: series.color,
buffer: lineBuffer,
pointCount: series.data.length
};
}
function onSeriesDataAdd(event, seriesIndex, points) {
var line = lines[seriesIndex];
points.forEach(function (point) {
@ -192,6 +164,41 @@ define(
});
}
function redraw() {
if (isDestroyed) {
return;
}
requestAnimationFrame(redraw);
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
drawAPI.clear();
createOffset();
if (!offset) {
return;
}
updateViewport();
drawSeries();
drawRectangles();
}
function drawIfResized() {
if (canvas.width !== canvas.offsetWidth ||
canvas.height !== canvas.offsetHeight) {
redraw();
}
}
function destroyChart() {
isDestroyed = true;
if (activeInterval) {
$interval.cancel(activeInterval);
}
}
// Check for resize, on a timer
activeInterval = $interval(drawIfResized, 1000);

View File

@ -7,8 +7,8 @@ define(
function (utils) {
"use strict";
var RANGE_TICK_COUNT = 7;
var DOMAIN_TICK_COUNT = 5;
var RANGE_TICK_COUNT = 7,
DOMAIN_TICK_COUNT = 5;
function MCTPlot() {
@ -40,34 +40,37 @@ define(
}
var dragStart;
var marqueeBox = {};
var marqueeRect; // Set when exists.
var chartElementBounds;
var $canvas = $element.find('canvas');
var dragStart,
marqueeBox = {},
marqueeRect, // Set when exists.
chartElementBounds,
$canvas = $element.find('canvas');
var updateAxesForCurrentViewport = function() {
function updateAxesForCurrentViewport() {
// Update axes definitions for current viewport.
['domain', 'range'].forEach(function(axisName) {
var axis = $scope.axes[axisName];
var firstTick = $scope.viewport.topLeft[axisName];
var lastTick = $scope.viewport.bottomRight[axisName];
var axisSize = firstTick - lastTick;
var denominator = axis.tickCount - 1;
var axis = $scope.axes[axisName],
firstTick = $scope.viewport.topLeft[axisName],
lastTick = $scope.viewport.bottomRight[axisName],
axisSize = firstTick - lastTick,
denominator = axis.tickCount - 1,
tickNumber,
tickIncrement,
tickValue;
// Yes, ticksize is negative for domain and positive for range.
// It's because ticks are generated/displayed top to bottom and left to right.
axis.ticks = [];
for (var tickNumber = 0; tickNumber < axis.tickCount; tickNumber++) {
var tickIncrement = (axisSize * (tickNumber / denominator));
var tickValue = firstTick - tickIncrement;
for (tickNumber = 0; tickNumber < axis.tickCount; tickNumber++) {
tickIncrement = (axisSize * (tickNumber / denominator));
tickValue = firstTick - tickIncrement;
axis.ticks.push(
tickValue
);
}
});
};
}
var drawMarquee = function() {
function drawMarquee() {
// Create rectangle for Marquee if it should be set.
if (marqueeBox && marqueeBox.start && marqueeBox.end) {
if (!marqueeRect) {
@ -79,30 +82,88 @@ define(
marqueeRect.color = [1, 1, 1, 0.5];
marqueeRect.layer = 'top'; // TODO: implement this.
$scope.$broadcast('rectangle-change');
} else if (marqueeRect && $scope.rectangles.indexOf(marqueeRect) != -1) {
} else if (marqueeRect && $scope.rectangles.indexOf(marqueeRect) !== -1) {
$scope.rectangles.splice($scope.rectangles.indexOf(marqueeRect));
marqueeRect = undefined;
$scope.$broadcast('rectangle-change');
}
};
}
var untrackMousePosition = function() {
function untrackMousePosition() {
$scope.mouseCoordinates = undefined;
};
}
function updateMarquee() {
// Update the marquee box in progress.
marqueeBox.end = $scope.mouseCoordinates.positionAsPlotPoint;
drawMarquee();
}
function startMarquee() {
marqueeBox.start = $scope.mouseCoordinates.positionAsPlotPoint;
}
function endMarquee() {
// marqueeBox start/end are opposite corners but we need
// topLeft and bottomRight.
var boxPoints = utils.boxPointsFromOppositeCorners(marqueeBox.start, marqueeBox.end),
newViewport = utils.oppositeCornersFromBoxPoints(boxPoints);
var trackMousePosition = function($event) {
marqueeBox = {};
drawMarquee();
$scope.$emit('user:viewport:change:end', newViewport);
$scope.viewport = newViewport;
}
function startDrag($event) {
$scope.$emit('user:viewport:change:start');
if (!$scope.mouseCoordinates) {
return;
}
$event.preventDefault();
// Track drag location relative to position over element
// not domain, as chart viewport will change as we drag.
dragStart = $scope.mouseCoordinates.positionAsPlotPoint;
// Tell controller that we're starting to navigate.
return false;
}
function updateDrag() {
// calculate offset between points. Apply that offset to viewport.
var newPosition = $scope.mouseCoordinates.positionAsPlotPoint,
dDomain = dragStart.domain - newPosition.domain,
dRange = dragStart.range - newPosition.range;
$scope.viewport = {
topLeft: {
domain: $scope.viewport.topLeft.domain + dDomain,
range: $scope.viewport.topLeft.range + dRange
},
bottomRight: {
domain: $scope.viewport.bottomRight.domain + dDomain,
range: $scope.viewport.bottomRight.range + dRange
}
};
}
function endDrag() {
dragStart = undefined;
$scope.$emit('user:viewport:change:end', $scope.viewport);
}
function trackMousePosition($event) {
// Calculate coordinates of mouse related to canvas and as
// domain, range value and make available in scope for display.
var bounds = $event.target.getBoundingClientRect();
var bounds = $event.target.getBoundingClientRect(),
positionOverElement,
positionAsPlotPoint;
chartElementBounds = bounds;
var positionOverElement = {
positionOverElement = {
x: $event.clientX - bounds.left,
y: $event.clientY - bounds.top
};
var positionAsPlotPoint = utils.elementPositionAsPlotPosition(
positionAsPlotPoint = utils.elementPositionAsPlotPosition(
positionOverElement,
bounds,
$scope.viewport
@ -120,104 +181,46 @@ define(
if (dragStart) {
updateDrag();
}
};
}
var startMarquee = function() {
marqueeBox.start = $scope.mouseCoordinates.positionAsPlotPoint;
};
var updateMarquee = function() {
// Update the marquee box in progress.
marqueeBox.end = $scope.mouseCoordinates.positionAsPlotPoint;
drawMarquee();
};
var endMarquee = function() {
// marqueeBox start/end are opposite corners but we need
// topLeft and bottomRight.
var boxPoints = utils.boxPointsFromOppositeCorners(marqueeBox.start, marqueeBox.end);
var newViewport = utils.oppositeCornersFromBoxPoints(boxPoints);
marqueeBox = {};
drawMarquee();
$scope.$emit('user:viewport:change:end', newViewport);
$scope.viewport = newViewport;
};
var startDrag = function($event) {
$scope.$emit('user:viewport:change:start');
if (!$scope.mouseCoordinates) {
return;
}
$event.preventDefault();
// Track drag location relative to position over element
// not domain, as chart viewport will change as we drag.
dragStart = $scope.mouseCoordinates.positionAsPlotPoint;
// Tell controller that we're starting to navigate.
return false;
};
var updateDrag = function() {
// calculate offset between points. Apply that offset to viewport.
var newPosition = $scope.mouseCoordinates.positionAsPlotPoint;
var dDomain = dragStart.domain - newPosition.domain;
var dRange = dragStart.range - newPosition.range;
$scope.viewport = {
topLeft: {
domain: $scope.viewport.topLeft.domain + dDomain,
range: $scope.viewport.topLeft.range + dRange
},
bottomRight: {
domain: $scope.viewport.bottomRight.domain + dDomain,
range: $scope.viewport.bottomRight.range + dRange
}
};
};
var endDrag = function() {
dragStart = undefined;
$scope.$emit('user:viewport:change:end', $scope.viewport);
};
var watchForMarquee = function() {
function watchForMarquee() {
$canvas.removeClass('plot-drag');
$canvas.addClass('plot-marquee');
$canvas.on('mousedown', startMarquee);
$canvas.on('mouseup', endMarquee);
$canvas.off('mousedown', startDrag);
$canvas.off('mouseup', endDrag);
};
}
var watchForDrag = function() {
function watchForDrag() {
$canvas.addClass('plot-drag');
$canvas.removeClass('plot-marquee');
$canvas.on('mousedown', startDrag);
$canvas.on('mouseup', endDrag);
$canvas.off('mousedown', startMarquee);
$canvas.off('mouseup', endMarquee);
};
}
var stopWatching = function() {
function toggleInteractionMode(event) {
if (event.keyCode === '18') { // control key.
watchForDrag();
}
}
function resetInteractionMode(event) {
if (event.keyCode === '18') {
watchForMarquee();
}
}
function stopWatching() {
$canvas.off('mousedown', startDrag);
$canvas.off('mouseup', endDrag);
$canvas.off('mousedown', startMarquee);
$canvas.off('mouseup', endMarquee);
window.removeEventListener('keydown', toggleInteractionMode);
window.removeEventListener('keyup', resetInteractionMode);
};
var toggleInteractionMode = function(event) {
if (event.keyCode == '18') { // control key.
watchForDrag();
}
};
var resetInteractionMode = function(event) {
if (event.keyCode == '18') {
watchForMarquee();
}
};
}
$canvas.on('mousemove', trackMousePosition);
$canvas.on('mouseleave', untrackMousePosition);
@ -226,7 +229,7 @@ define(
window.addEventListener('keydown', toggleInteractionMode);
window.addEventListener('keyup', resetInteractionMode);
var onViewportChange = function() {
function onViewportChange() {
if ($scope.mouseCoordinates && chartElementBounds) {
$scope.mouseCoordinates.positionAsPlotPoint =
utils.elementPositionAsPlotPosition(
@ -235,11 +238,9 @@ define(
$scope.viewport
);
}
if (marqueeBox && marqueeBox.start) {
// TODO: Discuss whether marqueeBox start should be fixed to data or fixed to canvas element, especially when "isLive is true".
}
// TODO: Discuss whether marqueeBox start should be fixed to data or fixed to canvas element, especially when "isLive is true".
updateAxesForCurrentViewport();
};
}
$scope.$watchCollection('viewport', onViewportChange);

View File

@ -1,4 +1,4 @@
/*global define */
/*global define,$log */
define(
[
@ -25,7 +25,8 @@ define(
the draw API to.
*/
getDrawAPI: function (canvas) {
for (var i = 0; i < CHARTS.length; i++) {
var i;
for (i = 0; i < CHARTS.length; i++) {
try {
return new CHARTS[i](canvas);
} catch (e) {
@ -42,4 +43,4 @@ define(
}
};
}
);
);