mike-jumper commented on code in PR #927: URL: https://github.com/apache/guacamole-client/pull/927#discussion_r1380569078
########## doc/licenses/d3-path-3.1.0/README: ########## @@ -0,0 +1,8 @@ +d3-path (https://github.com/d3/d3-path) +---------------------------------------------------------- + + Version: 3.1.0 + From: 'Mike Bostock' + License(s): + BSD (bundled/d3-path-3.1.0/LICENSE) Review Comment: Similar to: https://github.com/apache/guacamole-client/blob/ac6e501eff8b11f0c4b9a5bad653e237b979b14d/doc/licenses/jakarta-jaxb-2.3.3/README#L7 and: https://github.com/apache/guacamole-client/blob/ac6e501eff8b11f0c4b9a5bad653e237b979b14d/doc/licenses/woodstox-stax2-api-4.2/README#L7 This should be "BSD 0-clause" to differentiate it from the other BSD license variants. See: https://en.wikipedia.org/wiki/BSD_licenses ########## doc/licenses/d3-shape-3.2.0/README: ########## @@ -0,0 +1,8 @@ +d3-path (https://github.com/d3/d3-shape) +---------------------------------------------------------- + + Version: 3.2.0 + From: 'Mike Bostock' + License(s): + BSD (bundled/d3-shape-3.2.0/LICENSE) Review Comment: Same here - "BSD 0-clause". ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} + */ + const NUM_BUCKETS = 100; + + /** + * Given a list of values to smooth out, produce a smoothed data set with + * the same length as the original provided list. + * + * @param {!Number[]} values Review Comment: This should be `@type {number[]}` (or `@type {!number[]}` if `null` is not tolerated). ########## guacamole/src/main/frontend/src/app/player/directives/player.js: ########## @@ -187,6 +188,57 @@ angular.module('player').directive('guacPlayer', ['$injector', function guacPlay */ $scope.showKeyLog = false; + /** + * The height, in pixels, of the SVG heatmap paths. Note that this is not + * necessarily the actual rendered height, just the initial size of the + * SVG path before any styling is applied. + */ + $scope.HEATMAP_HEIGHT = 100; + + /** + * The width, in pixels, of the SVG heatmap paths. Note that this is not + * necessarily the actual rendered width, just the initial size of the + * SVG path before any styling is applied. + */ + $scope.HEATMAP_WIDTH = 1000; + + /** + * The maximum number of key events per millisecond to display in the + * key event heatmap. Any key event rates exceeding this value will be + * capped at this rate to ensure that unsually large spikes don't make + * swamp the rest of the data. + * + * Note: This is 6 keys per second (events include both presses and + * releases) - equivalent to ~88 words per minute typed. + */ + const KEY_EVENT_RATE_CAP = 12 / 1000; + + /** + * The maximum number of frames per millisecond to display in the + * frame heatmap. Any frame rates exceeding this value will be + * capped at this rate to ensure that unsually large spikes don't make + * swamp the rest of the data. + */ + const FRAME_RATE_CAP = 10 / 1000; + + /** + * An SVG path describing a smoothed curve that visualizes the relative + * number of frames rendered throughout the recording - i.e. a heatmap + * of screen updates. + * + * @type {String} + */ + $scope.frameHeatmap = ''; + + /** + * An SVG path describing a smoothed curve that visualizes the relative + * number of key events recorded throughout the recording - i.e. a + * heatmap of key events. + * + * @type {String} + */ + $scope.keyHeatmap = ''; Review Comment: These should be `@type {string}` (or `@type {!string}` if not nullable). ########## guacamole/src/main/frontend/src/app/player/directives/player.js: ########## @@ -187,6 +188,57 @@ angular.module('player').directive('guacPlayer', ['$injector', function guacPlay */ $scope.showKeyLog = false; + /** + * The height, in pixels, of the SVG heatmap paths. Note that this is not + * necessarily the actual rendered height, just the initial size of the + * SVG path before any styling is applied. + */ + $scope.HEATMAP_HEIGHT = 100; + + /** + * The width, in pixels, of the SVG heatmap paths. Note that this is not + * necessarily the actual rendered width, just the initial size of the + * SVG path before any styling is applied. + */ + $scope.HEATMAP_WIDTH = 1000; + + /** + * The maximum number of key events per millisecond to display in the + * key event heatmap. Any key event rates exceeding this value will be + * capped at this rate to ensure that unsually large spikes don't make + * swamp the rest of the data. + * + * Note: This is 6 keys per second (events include both presses and + * releases) - equivalent to ~88 words per minute typed. + */ + const KEY_EVENT_RATE_CAP = 12 / 1000; + + /** + * The maximum number of frames per millisecond to display in the + * frame heatmap. Any frame rates exceeding this value will be + * capped at this rate to ensure that unsually large spikes don't make + * swamp the rest of the data. + */ + const FRAME_RATE_CAP = 10 / 1000; Review Comment: Please add `@type` annotations. ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} Review Comment: This should be `@type {!number}`. ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} + */ + const NUM_BUCKETS = 100; + + /** + * Given a list of values to smooth out, produce a smoothed data set with + * the same length as the original provided list. + * + * @param {!Number[]} values + * The list of histogram values to smooth out. + * + * @returns + * The smoothed value array. + */ + function smooth(values) { + + // The starting offset into the values array for each calculation + const lookBack = Math.floor(GAUSSIAN_KERNEL.length / 2); + + // Apply the smoothing kernel to each value in the provided array + return _.map(values, (value, index) => { + + // Total up the weighted values for each position in the kernel + return _.reduce(GAUSSIAN_KERNEL, (total, weight, kernelIndex) => { + + // The offset into the original values array for the kernel + const valuesOffset = kernelIndex - lookBack; + + // The position inside the original values array to be included + const valuesIndex = index + valuesOffset; + + // If the contribution to the final smoothed value would be outside + // the bounds of the array, just use the original value instead + const contribution = ((valuesIndex >= 0) && valuesIndex < values.length) + ? values[valuesIndex] : value; + + // Use the provided weight from the kernel and add to the total + return total + (contribution * weight); + + }, 0); + + }); + } + + /** + * Given an array of values, with each value representing an activity count + * during a bucket of time, generate a smooth curve, scaled to PATH_HEIGHT + * height, and PATH_WIDTH width. + * + * @param {!Number[]} bucketizedData + * The bucketized counts to create an SVG path from. + * + * @param {!Number} maxBucketValue + * The size of the largest value in the bucketized data. + * + * @param {!Number} height + * The target height, in pixels, of the highest point in the heatmap. + * + * @param {!Number} width + * The target width, in pixels, of the heatmap. + * + * @returns + * An SVG path representing a smooth curve, passing through all points + * in the provided data. + */ + function createPath(bucketizedData, maxBucketValue, height, width) { + + // Calculate scaling factor to ensure that paths are all the same heigh + const yScalingFactor = height / maxBucketValue; + + // Scale a given Y value appropriately + const scaleYValue = yValue => height - (yValue * yScalingFactor); + + // Calculate scaling factor to ensure that paths are all the same width + const xScalingFactor = width / bucketizedData.length; + + // Construct a continuous curved path + const curvedPath = path(); + const curve = curveCatmullRom(curvedPath); + + curve.lineStart(); + + // Add all the data points + for (let i = 0; i < bucketizedData.length; i++) { + + // Scale up the x value to hit the target width + const x = xScalingFactor * i; + + // Scale and invert the height for display + const y = scaleYValue(bucketizedData[i]); + + // Add the scaled point + curve.point(x, y); + + } + + // Move back to 0 to complete the path + curve.lineEnd(); + curvedPath.lineTo(width, scaleYValue(0)); + + // Generate the SVG path for this curve + const rawPathText = curvedPath.toString(); + + // The SVG path as generated by D3 starts with a move to the first data + // point. This means that when the path ends and the subpath is closed, + // it returns to the position of the first data point instead of the + // origin. To fix this, the initial move command is removed, and the + // path is amended to start at the origin. TODO: Find a better way to + // handle this. + const startAtOrigin = ( + + // Start at origin + 'M0,' + scaleYValue(0) + + + // Line to the first point in the curve, to close the shape + 'L0,' + scaleYValue(bucketizedData[0]) + + ); + + // Strip off the first move command from the path + const strippedPathText = _.replace(rawPathText, /^[^C]*/, ''); + + return startAtOrigin + strippedPathText; + } + + const service = {}; + + /** + * Given a raw array of timestamps indicating when events of a certain type + * occured during a record, generate and return a smoothed SVG path + * indicating how many events occured during each equal-length bucket. + * + * @param {!Number[]} timestamps + * A raw array of timestamps, one for every relevant event. These + * must be monotonically increasing. + * + * @param {!Number} duration + * The duration over which the heatmap should apply. This value may + * be greater than the maximum timestamp value, in which case the path + * will drop to 0 after the last timestamp in the provided array. + * + * @param {Number} maxRate + * The maximum number of events per millisecond that should be displayed + * in the final path. Any rates over this amount will just be capped at + * this value. + * + * @param {!Number} height + * The target height, in pixels, of the highest point in the heatmap. + * + * @param {!Number} width + * The target width, in pixels, of the heatmap. Review Comment: Here, too: `Number` -> `number` ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} + */ + const NUM_BUCKETS = 100; + + /** + * Given a list of values to smooth out, produce a smoothed data set with + * the same length as the original provided list. + * + * @param {!Number[]} values + * The list of histogram values to smooth out. + * + * @returns + * The smoothed value array. + */ + function smooth(values) { + + // The starting offset into the values array for each calculation + const lookBack = Math.floor(GAUSSIAN_KERNEL.length / 2); + + // Apply the smoothing kernel to each value in the provided array + return _.map(values, (value, index) => { + + // Total up the weighted values for each position in the kernel + return _.reduce(GAUSSIAN_KERNEL, (total, weight, kernelIndex) => { + + // The offset into the original values array for the kernel + const valuesOffset = kernelIndex - lookBack; + + // The position inside the original values array to be included + const valuesIndex = index + valuesOffset; + + // If the contribution to the final smoothed value would be outside + // the bounds of the array, just use the original value instead + const contribution = ((valuesIndex >= 0) && valuesIndex < values.length) + ? values[valuesIndex] : value; + + // Use the provided weight from the kernel and add to the total + return total + (contribution * weight); + + }, 0); + + }); + } + + /** + * Given an array of values, with each value representing an activity count + * during a bucket of time, generate a smooth curve, scaled to PATH_HEIGHT + * height, and PATH_WIDTH width. + * + * @param {!Number[]} bucketizedData + * The bucketized counts to create an SVG path from. + * + * @param {!Number} maxBucketValue + * The size of the largest value in the bucketized data. + * + * @param {!Number} height + * The target height, in pixels, of the highest point in the heatmap. + * + * @param {!Number} width + * The target width, in pixels, of the heatmap. + * + * @returns + * An SVG path representing a smooth curve, passing through all points + * in the provided data. Review Comment: Please add return type. ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} + */ + const NUM_BUCKETS = 100; + + /** + * Given a list of values to smooth out, produce a smoothed data set with + * the same length as the original provided list. + * + * @param {!Number[]} values + * The list of histogram values to smooth out. + * + * @returns + * The smoothed value array. + */ + function smooth(values) { + + // The starting offset into the values array for each calculation + const lookBack = Math.floor(GAUSSIAN_KERNEL.length / 2); + + // Apply the smoothing kernel to each value in the provided array + return _.map(values, (value, index) => { + + // Total up the weighted values for each position in the kernel + return _.reduce(GAUSSIAN_KERNEL, (total, weight, kernelIndex) => { + + // The offset into the original values array for the kernel + const valuesOffset = kernelIndex - lookBack; + + // The position inside the original values array to be included + const valuesIndex = index + valuesOffset; + + // If the contribution to the final smoothed value would be outside + // the bounds of the array, just use the original value instead + const contribution = ((valuesIndex >= 0) && valuesIndex < values.length) + ? values[valuesIndex] : value; + + // Use the provided weight from the kernel and add to the total + return total + (contribution * weight); + + }, 0); + + }); + } + + /** + * Given an array of values, with each value representing an activity count + * during a bucket of time, generate a smooth curve, scaled to PATH_HEIGHT + * height, and PATH_WIDTH width. + * + * @param {!Number[]} bucketizedData + * The bucketized counts to create an SVG path from. + * + * @param {!Number} maxBucketValue + * The size of the largest value in the bucketized data. + * + * @param {!Number} height + * The target height, in pixels, of the highest point in the heatmap. + * + * @param {!Number} width + * The target width, in pixels, of the heatmap. Review Comment: Same here: `Number` -> `number` ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} + */ + const GAUSSIAN_KERNEL = [0.0013, 0.1573, 0.6827, 0.1573, 0.0013]; + + /** + * The number of buckets that a series of activity timestamps should be + * divided into. + * + * @type {Number} + */ + const NUM_BUCKETS = 100; + + /** + * Given a list of values to smooth out, produce a smoothed data set with + * the same length as the original provided list. + * + * @param {!Number[]} values + * The list of histogram values to smooth out. + * + * @returns + * The smoothed value array. Review Comment: Please add return type. ########## guacamole/src/main/frontend/src/app/player/services/playerHeatmapService.js: ########## @@ -0,0 +1,264 @@ +/* + * 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. + */ + +import { curveCatmullRom } from 'd3-shape'; +import { path } from 'd3-path'; + +/** + * A service for generating heat maps of activity levels per time interval, + * for session recording playback. + */ +angular.module('player').factory('playerHeatmapService', [() => { + + /** + * A default, relatively-gentle Gaussian smoothing kernel. This kernel + * should help heatmaps look a bit less jagged, while not reducing fidelity + * very much. + * + * @type {Number[]} Review Comment: This should be `@type {!number[]}`. ########## guacamole/src/main/frontend/src/app/player/directives/player.js: ########## @@ -213,6 +265,22 @@ angular.module('player').directive('guacPlayer', ['$injector', function guacPlay */ var mouseActivityTimer = null; + /** + * The recording-relative timestamp of each frame of the recording that + * has been processed so far. + * + * @type {Number[]} + */ + var frameTimestamps = []; + + /** + * The recording-relative timestamp of each text event that has been + * processed so far. + * + * @type {Number[]} + */ + var keyTimestamps = []; Review Comment: These should be `@type {number[]}` (or `@type {!number[]}` if not nullable). -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
