\
';
- $(that.element).html(content);
- },
+ $(that.element).html(content);
+ },
- _adaptContent: function() {
- var that = this;
- if (!that.options.showChannelGainAdjustmentButtons) {
- $(that.element).find('.adjustment_buttons').hide();
- }
- if (!that.options.showArtifactButtons) {
- $(that.element).find('.artifact_panel').hide();
- }
- if (!that.options.showSleepStageButtons) {
- $(that.element).find('.sleep_stage_panel').hide();
- }
- if (!that.options.showNavigationButtons) {
- $(that.element).find('.navigation_panel').hide();
- }
- if (!that.options.showBackToLastActiveWindowButton) {
- $(that.element).find('.backToLastActiveWindow').hide();
- }
- if (!that.options.showBookmarkCurrentPageButton) {
- $(that.element).find('.bookmarkCurrentPage').hide();
- }
- if (!that._isArbitrating()) {
- $(that.element).find('.jumpToLastDisagreementWindow').hide();
- $(that.element).find('.jumpToNextDisagreementWindow').hide();
- }
- if (!that.options.showFastBackwardButton) {
- $(that.element).find('.fastBackward').hide();
- }
- if (!that.options.showBackwardButton) {
- $(that.element).find('.backward').hide();
- }
- if (!that.options.showForwardButton) {
- $(that.element).find('.forward').hide();
- }
- if (!that.options.showFastForwardButton) {
- $(that.element).find('.fastForward').hide();
- }
- if (!that.options.showShortcuts) {
- $(that.element).find('.keyboardShortcuts').hide();
- }
- if (!that.options.showAnnotationTime) {
- $(that.element).find('.annotationTime').hide();
- }
- if (!that.options.showLogoutButton) {
- $(that.element).find('.logout').hide();
- }
- if (!that.options.showInputPanelContainer) {
- $(that.element).parents('.annotator-edf').find('.input-panel-container').hide();
- $(that.element).find('.mark-assignment-as-completed').show();
- that._updateMarkAssignmentAsCompletedButtonState();
- }
- if (!that._isHITModeEnabled()) {
- $(that.element).find('.progress').hide();
- }
- $(that.element).css({
- marginTop: that.options.marginTop,
- marginBottom: that.options.marginBottom,
+ _adaptContent: function () {
+ var that = this;
+ if (!that.options.showChannelGainAdjustmentButtons) {
+ $(".adjustment_buttons").hide();
+ }
+ if (!that.options.showArtifactButtons) {
+ $(".artifact_panel").hide();
+ }
+ if (!that.options.showSleepStageButtons) {
+ $(".sleep_stage_panel").hide();
+ }
+ if (!that.options.showNavigationButtons) {
+ $(".navigation_panel").hide();
+ }
+ if (!that.options.showBackToLastActiveWindowButton) {
+ $(".backToLastActiveWindow").hide();
+ }
+ if (!that.options.showBookmarkCurrentPageButton) {
+ $(".bookmarkCurrentPage").hide();
+ }
+ if (!that._isArbitrating()) {
+ $(".jumpToLastDisagreementWindow").hide();
+ $(".jumpToNextDisagreementWindow").hide();
+ }
+ if (!that.options.showFastBackwardButton) {
+ $(".fastBackward").hide();
+ }
+ if (!that.options.showBackwardButton) {
+ $(".backward").hide();
+ }
+ if (!that.options.showForwardButton) {
+ $(".forward").hide();
+ }
+ if (!that.options.showFastForwardButton) {
+ $(".fastForward").hide();
+ }
+ if (!that.options.showShortcuts) {
+ $(".keyboardShortcuts").hide();
+ }
+ if (!that.options.showAnnotationTime) {
+ $(".annotationTime").hide();
+ }
+ if (!that.options.showLogoutButton) {
+ $(".logout").hide();
+ }
+ if (!that.options.showInputPanelContainer) {
+ $(that.element)
+ .parents(".annotator-edf")
+ .find(".input-panel-container")
+ .hide();
+ // $(".mark-assignment-as-completed").show();
+ $(".mark-assignment-as-completed").hide();
+
+ that._updateMarkAssignmentAsCompletedButtonState();
+ }
+ if (!that._isHITModeEnabled()) {
+ $(".progress").hide();
+ }
+ $(that.element).css({
+ marginTop: that.options.marginTop,
+ marginBottom: that.options.marginBottom,
+ });
+ },
+
+ _updateMarkAssignmentAsCompletedButtonState: function () {
+ var that = this;
+ $(that.element)
+ .find(".mark-assignment-as-completed")
+ .prop(
+ "disabled",
+ !that.options.context.assignment.canBeMarkedAsCompleted({
+ reactive: false,
})
- },
-
- _updateMarkAssignmentAsCompletedButtonState: function() {
- var that = this;
- $(that.element).find('.mark-assignment-as-completed').prop('disabled', !that.options.context.assignment.canBeMarkedAsCompleted({ reactive: false }));
- },
-
- _forcePlayTrainingVideo: function() {
- var that = this;
- var videoBox = bootbox.dialog({
- title: 'Training Video (PLEASE TURN UP YOUR SOUND VOLUME)',
- onEscape: false,
- backdrop: false,
- closeButton: false,
- animate: true,
- message: '',
- size: 'large',
- });
- videoBox.appendTo(that.element);
- videoBox.css({
- backgroundColor: 'rgba(0, 0, 0, 1)',
- zIndex: 999999,
- });
- if (that.options.trainingVideo.blockInteraction) {
- videoBox.find('.interaction-blocker').css({
- position: 'fixed',
- width: '100%',
- height: '100%',
- left: 0,
- top: 0,
- });
- }
- var videoContainer = videoBox.find('.training-video');
- var videoId = that.options.trainingVideo.vimeoId;
- var aspectRatio = 513 / 287
- var width = Math.round(videoContainer.width());
- var height = Math.round(width / aspectRatio);
- var playerId = that._getUUID();
- $.getJSON('http://www.vimeo.com/api/oembed.json?url=' + encodeURIComponent('http://vimeo.com/' + videoId) + '&title=0&byline=0&portrait=0&badge=0&loop=0&autoplay=1&width=' + width + '&height=' + height + '&api=1&player_id=' + playerId + '&callback=?', function(data) {
- var playerIFrame = $(data.html).attr('id', playerId).appendTo(videoContainer);
- var player = $f(playerIFrame[0]);
- player.addEvent('ready', function() {
- player.addEvent('finish',function() {
- videoBox.remove();
- });
- });
+ );
+ },
+
+ _forcePlayTrainingVideo: function () {
+ var that = this;
+ var videoBox = bootbox.dialog({
+ title: "Training Video (PLEASE TURN UP YOUR SOUND VOLUME)",
+ onEscape: false,
+ backdrop: false,
+ closeButton: false,
+ animate: true,
+ message:
+ '',
+ size: "large",
+ });
+ videoBox.appendTo(that.element);
+ videoBox.css({
+ backgroundColor: "rgba(0, 0, 0, 1)",
+ zIndex: 999999,
+ });
+ if (that.options.trainingVideo.blockInteraction) {
+ videoBox.find(".interaction-blocker").css({
+ position: "fixed",
+ width: "100%",
+ height: "100%",
+ left: 0,
+ top: 0,
+ });
+ }
+ var videoContainer = videoBox.find(".training-video");
+ var videoId = that.options.trainingVideo.vimeoId;
+ var aspectRatio = 513 / 287;
+ var width = Math.round(videoContainer.width());
+ var height = Math.round(width / aspectRatio);
+ var playerId = that._getUUID();
+ $.getJSON(
+ "http://www.vimeo.com/api/oembed.json?url=" +
+ encodeURIComponent("http://vimeo.com/" + videoId) +
+ "&title=0&byline=0&portrait=0&badge=0&loop=0&autoplay=1&width=" +
+ width +
+ "&height=" +
+ height +
+ "&api=1&player_id=" +
+ playerId +
+ "&callback=?",
+ function (data) {
+ var playerIFrame = $(data.html)
+ .attr("id", playerId)
+ .appendTo(videoContainer);
+ var player = $f(playerIFrame[0]);
+ player.addEvent("ready", function () {
+ player.addEvent("finish", function () {
+ videoBox.remove();
+ });
});
- },
-
- _showConsentForm: function() {
- var that = this;
- var confirmationCodeInfo = '';
- if (that.options.showConfirmationCode && that.options.confirmationCode) {
- confirmationCodeInfo = '. For the payment to be processed correctly you need to enter the confirmation code presented to you at the end of the task into the corresponding input field in the instructions panel on Mechanical Turk';
- }
- bootbox.dialog({
- onEscape: false,
- backdrop: false,
- closeButton: false,
- animate: true,
- title: 'Information Consent',
- message: ' \
+ }
+ );
+ },
+
+ _showConsentForm: function () {
+ var that = this;
+ var confirmationCodeInfo = "";
+ if (that.options.showConfirmationCode && that.options.confirmationCode) {
+ confirmationCodeInfo =
+ ". For the payment to be processed correctly you need to enter the confirmation code presented to you at the end of the task into the corresponding input field in the instructions panel on Mechanical Turk";
+ }
+ bootbox
+ .dialog({
+ onEscape: false,
+ backdrop: false,
+ closeButton: false,
+ animate: true,
+ title: "Information Consent",
+ message:
+ ' \
\
You are invited to participate in a research study conducted by Mike Schaekermann under the supervision of Professor Edith Law of the University of Waterloo, Canada. The objectives of the research study are to develop a low cost crowdsourcing system for EEG analysis for use in the third world.
\
- If you decide to participate, you will be asked to complete a 20-30 minute online EEG analysis task, as described on the task listing. Participation in this study is voluntary. You may decline to answer any questions that you do not wish to answer and you can withdraw your participation at any time by closing this browser tab or window. You will be paid $' + that.options.payment.toFixed(2) + ' upon completion of the task' + confirmationCodeInfo + '. Unfortunately we are unable to pay participants who do not complete the task. There are no known or anticipated risks from participating in this study.
\
+ If you decide to participate, you will be asked to complete a 20-30 minute online EEG analysis task, as described on the task listing. Participation in this study is voluntary. You may decline to answer any questions that you do not wish to answer and you can withdraw your participation at any time by closing this browser tab or window. You will be paid $' +
+ that.options.payment.toFixed(2) +
+ " upon completion of the task" +
+ confirmationCodeInfo +
+ ". Unfortunately we are unable to pay participants who do not complete the task. There are no known or anticipated risks from participating in this study.
\
It is important for you to know that any information that you provide will be confidential. All of the data will be summarized and no individual could be identified from these summarized results. Furthermore, the web site is programmed to collect responses alone and will not collect any information that could potentially identify you (such as machine identifiers). The data collected from this study will be maintained on a password-protected computer database in a restricted access area of the university. As well, the data will be electronically archived after completion of the study and maintained for eight years and then erased.
\
This survey uses Mechanical Turk which is a United States of America company. Consequently, USA authorities under provisions of the Patriot Act may access this survey data. If you prefer not to submit your data through Mechanical Turk, please do not participate.
\
Note that the remuneration you receive may be taxable income. You are responsible for reporting this income for tax purposes. Should you have any questions about the study, please contact either Mike Schaekermann (mschaeke@uwaterloo.ca) or Edith Law (edith.law@uwaterloo.ca). Further, if you would like to receive a copy of the results of this study, please contact either investigator.
\
I would like to assure you that this study has been reviewed and received ethics clearance through a University of Waterloo Research Ethics Committee. However, the final decision about participation is yours. Should you have any comments or concerns resulting about your participation in this study, please contact Dr. Maureen Nummelin in the Office of Research Ethics at 1-519-888-4567, Ext. 36005 or maureen.nummelin@uwaterloo.ca.
\
\
- ',
- buttons: {
- consent: {
- label: 'I understand and accept the participant consent agreement',
- className: 'btn-success',
- }
- }
- }).css({
- zIndex: 99999,
- }).appendTo(that.element);
- },
-
- _setVisibilityStatusForInfoPanel: function(isVisible) {
- var that = this;
- const setVisibilityStatus = that.options.setVisibilityStatusForInfoPanel;
- if (!setVisibilityStatus) return;
- setVisibilityStatus(isVisible);
- },
-
- _showInfoPanel: function() {
- var that = this;
- that._setVisibilityStatusForInfoPanel(true);
- },
-
- _hideInfoPanel: function() {
- var that = this;
- that._setVisibilityStatusForInfoPanel(false);
- },
-
- _toggleInfoPanel: function() {
- var that = this;
- const toggle = that.options.toggleInfoPanel;
- if (!toggle) return;
- toggle();
- },
-
- _isHITModeEnabled: function() {
- var that = this;
- return (
- that._isVisibleRegionDefined()
- && that.options.visibleRegion.hitModeEnabled
- );
- },
-
- _isVisibleRegionDefined: function() {
- var that = this;
- return (
- that.options.visibleRegion.start !== undefined
- && that.options.visibleRegion.end !== undefined
- );
- },
-
- _setupHITMode: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return;
-
- that.options.showBackToLastActiveWindowButton = false;
- that.options.showBookmarkCurrentPageButton = false;
- that.options.showFastBackwardButton = false;
- that.options.showBackwardButton = false;
- that.options.showForwardButton = false;
- that.options.showFastForwardButton = false;
- that.options.showShortcuts = false;
- that.options.showAnnotationTime = false;
-
- $(that.element).find('.graph_footer .middle').append(' \
+ ",
+ buttons: {
+ consent: {
+ label: "I understand and accept the participant consent agreement",
+ className: "btn-success",
+ },
+ },
+ })
+ .css({
+ zIndex: 99999,
+ })
+ .appendTo(that.element);
+ },
+
+ _setVisibilityStatusForInfoPanel: function (isVisible) {
+ var that = this;
+ const setVisibilityStatus = that.options.setVisibilityStatusForInfoPanel;
+ if (!setVisibilityStatus) return;
+ setVisibilityStatus(isVisible);
+ },
+
+ _showInfoPanel: function () {
+ var that = this;
+ that._setVisibilityStatusForInfoPanel(true);
+ },
+
+ _hideInfoPanel: function () {
+ var that = this;
+ that._setVisibilityStatusForInfoPanel(false);
+ },
+
+ _toggleInfoPanel: function () {
+ var that = this;
+ const toggle = that.options.toggleInfoPanel;
+ if (!toggle) return;
+ toggle();
+ },
+
+ _isHITModeEnabled: function () {
+ var that = this;
+ return (
+ that._isVisibleRegionDefined() &&
+ that.options.visibleRegion.hitModeEnabled
+ );
+ },
+
+ _isVisibleRegionDefined: function () {
+ var that = this;
+ return (
+ that.options.visibleRegion.start !== undefined &&
+ that.options.visibleRegion.end !== undefined
+ );
+ },
+
+ _setupHITMode: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return;
+
+ that.options.showBackToLastActiveWindowButton = false;
+ that.options.showBookmarkCurrentPageButton = false;
+ that.options.showFastBackwardButton = false;
+ that.options.showBackwardButton = false;
+ that.options.showForwardButton = false;
+ that.options.showFastForwardButton = false;
+ that.options.showShortcuts = false;
+ that.options.showAnnotationTime = false;
+
+ $(that.element)
+ .find(".graph_footer .middle")
+ .append(
+ ' \
\
\
\
- ');
-
- $(that.element).find('.submit-annotations').click(function () {
- that._blockGraphInteraction();
- if (that._isCurrentWindowTrainingWindow()) {
- that._revealCorrectAnnotations();
- }
- // log this window as complete and
- // set bookmark to next window so that
- // on page load, the user cannot change
- // any annotations made before submitting
- that._saveUserEventWindowComplete();
- that._savePreferences({ startTime: that.vars.currentWindowStart + that.options.windowSizeInSeconds })
- $(that.element).find('.submit-annotations').prop('disabled', true);
- $(that.element).find('.next-window').prop('disabled', false);
+ '
+ );
+
+ $(that.element)
+ .find(".submit-annotations")
+ .click(function () {
+ that._blockGraphInteraction();
+ if (that._isCurrentWindowTrainingWindow()) {
+ that._revealCorrectAnnotations();
+ }
+ // log this window as complete and
+ // set bookmark to next window so that
+ // on page load, the user cannot change
+ // any annotations made before submitting
+ that._saveUserEventWindowComplete();
+ that._savePreferences({
+ startTime:
+ that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds,
});
-
- $(that.element).find('.next-window').click(function () {
- $(that.element).find('.no-features').prop('disabled', false);
- $(that.element).find('.submit-features').prop('disabled', true);
- $(that.element).find('.next-window').prop('disabled', true);
- if (that._isCurrentWindowLastTrainingWindow() && !that._isTrainingOnly()) {
- bootbox.alert({
- closeButton: false,
- title: 'End of the Training Phase',
- message: 'You just completed the last window of the training phase. That means that, from now on, you will not be able to see the correct answer after submitting yours any longer. The examples panel below, however, will stay visible throughout the entire task. Hopefully, the training phase helped you learn more about the signal pattern we are looking for!',
- callback: function() {
- that._shiftChart(1);
- that._unblockGraphInteraction();
- }
- }).appendTo(that.element);
- }
- else {
+ $(that.element).find(".submit-annotations").prop("disabled", true);
+ $(".next-window").prop("disabled", false);
+ });
+
+ $(that.element)
+ .find(".next-window")
+ .click(function () {
+ $(".no-features").prop("disabled", false);
+ $(".submit-features").prop("disabled", true);
+ $(".next-window").prop("disabled", true);
+ if (
+ that._isCurrentWindowLastTrainingWindow() &&
+ !that._isTrainingOnly()
+ ) {
+ bootbox
+ .alert({
+ closeButton: false,
+ title: "End of the Training Phase",
+ message:
+ "You just completed the last window of the training phase. That means that, from now on, you will not be able to see the correct answer after submitting yours any longer. The examples panel below, however, will stay visible throughout the entire task. Hopefully, the training phase helped you learn more about the signal pattern we are looking for!",
+ callback: function () {
that._shiftChart(1);
that._unblockGraphInteraction();
- }
- });
-
- that._fetchOptionsFromURLParameter();
- },
-
- _getCurrentWindowIndexInVisibleRegion: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return;
- var windowIndex = Math.floor((that.vars.currentWindowStart - that.options.visibleRegion.start) / that.options.windowSizeInSeconds);
- return windowIndex;
- },
-
- _getNumberOfTrainingWindows: function() {
- var that = this;
- var training = that.options.visibleRegion.training;
- if (!that._isTrainingEnabled()) {
- return 0;
- }
- if (training.numberOfInitialWindowsUsedForTraining > 0) {
- return training.numberOfInitialWindowsUsedForTraining;
- }
- return that._getSpecifiedTrainingWindows().length;
- },
-
- _areTrainingWindowsSpecified: function() {
- var that = this;
- that._getSpecifiedTrainingWindows();
- return (
- that.vars.specifiedTrainingWindows !== undefined
- && that.vars.specifiedTrainingWindows.length > 0
- );
- },
-
- _getCurrentTrainingWindow: function() {
- var that = this;
- if (!that._areTrainingWindowsSpecified()) {
- return;
- }
- var trainingWindows = that._getSpecifiedTrainingWindows();
- var currentIndex = that.vars.currentTrainingWindowIndex;
- if (currentIndex > trainingWindows.length - 1) {
- return;
- }
- var trainingWindow = trainingWindows[currentIndex];
- return trainingWindow;
- },
-
- _isCurrentWindowSpecifiedTrainingWindow: function() {
- var that = this;
- if (!that._areTrainingWindowsSpecified()) return false;
- return that.vars.currentTrainingWindowIndex < that._getNumberOfTrainingWindows();
- },
-
- _getSpecifiedTrainingWindows: function() {
- var that = this;
- if (that.vars.specifiedTrainingWindows) {
- return that.vars.specifiedTrainingWindows;
- }
- var training = that.options.visibleRegion.training;
- if (!that._isTrainingEnabled() || training.numberOfInitialWindowsUsedForTraining > 0) {
- return [];
- }
- if (training.windows && training.windows.length > 0) {
- that.vars.specifiedTrainingWindows = training.windows;
- return that.vars.specifiedTrainingWindows;
- }
- var windows = [];
- var featureOrder = that.options.features.order;
- var featureOptions = that.options.features.options;
- for (f = 0; f < featureOrder.length; ++f) {
- var feature = featureOrder[f];
- var featureTrainingWindows = featureOptions[feature].training.windows;
- if (featureTrainingWindows && featureTrainingWindows.length > 0) {
- windows.push.apply(windows, featureTrainingWindows);
- }
- }
- that.vars.specifiedTrainingWindows = windows;
- return that.vars.specifiedTrainingWindows;
- },
-
- _isTrainingEnabled: function() {
- var that = this;
- return (that._isHITModeEnabled() && that.options.visibleRegion.training.enabled);
- },
-
- _isTrainingOnly: function() {
- var that = this;
- return that.options.visibleRegion.training.isTrainingOnly;
- },
-
- _isCurrentWindowTrainingWindow: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return false;
- return that._getWindowIndexForTraining() <= that._getNumberOfTrainingWindows() - 1;
- },
-
- _isCurrentWindowFirstTrainingWindow: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return false;
- return (
- that._getNumberOfTrainingWindows() > 0
- && that._getWindowIndexForTraining() === 0
- );
- },
-
- _isCurrentWindowLastTrainingWindow: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return false;
- return that._getWindowIndexForTraining() == that._getNumberOfTrainingWindows() - 1;
- },
-
- _getWindowIndexForTraining: function() {
- var that = this;
- if (!that._isHITModeEnabled()) return false;
- if (that._areTrainingWindowsSpecified()) {
- return that.vars.currentTrainingWindowIndex;
- }
- else {
- return that._getCurrentWindowIndexInVisibleRegion();
- }
- },
-
- _revealCorrectAnnotations: function() {
- var that = this;
- that._getAnnotations(that.vars.currentWindowRecording, that.vars.currentWindowStart, that.vars.currentWindowStart + that.options.windowSizeInSeconds, true);
- },
-
- _setupExamplesMode: function() {
- var that = this;
- var examples = that.options.features.examples;
-
- if (!examples || examples.length == 0) {
- console.log('There are no examples for this viewer.');
- return;
- }
- examples.sort(function(a, b) {
- return a.start - b.start;
- });
- var firstExample = examples[0];
- var recordingName = firstExample.recording;
- var channelsDisplayed = [firstExample.channels_displayed[firstExample.channels]];
- that.options.recordingName = recordingName;
- that.options.channelsDisplayed = channelsDisplayed;
- that.options.graph.height = 200;
- that.options.features.showUserAnnotations = false;
- that.options.features.order = [ firstExample.type ];
- that.options.isReadOnly = true;
- that.options.channelGainAdjustmentEnabled = false;
- that.options.showChannelGainAdjustmentButtons = false;
- that.options.keyboardInputEnabled = false;
- that.options.showArtifactButtons = false;
- that.options.showNavigationButtons = false;
- that.options.showReferenceLines = false;
- that.options.features.cheatSheetsEnabled = true;
- that.options.features.openCheatSheetOnPageLoad = true;
- that.options.showTimeLabels = false;
- that._fetchOptionsFromURLParameter();
-
- $(that.element).find('.button_container').prepend('Examples for:');
- $(that.element).find('.button_container').append(' \
+ },
+ })
+ .appendTo(that.element);
+ } else {
+ that._shiftChart(1);
+ that._unblockGraphInteraction();
+ }
+ });
+
+ that._fetchOptionsFromURLParameter();
+ },
+
+ _getCurrentWindowIndexInVisibleRegion: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return;
+ var windowIndex = Math.floor(
+ (that.vars.currentWindowStart - that.options.visibleRegion.start) /
+ that.vars.xAxisScaleInSeconds
+ );
+ return windowIndex;
+ },
+
+ _getNumberOfTrainingWindows: function () {
+ var that = this;
+ var training = that.options.visibleRegion.training;
+ if (!that._isTrainingEnabled()) {
+ return 0;
+ }
+ if (training.numberOfInitialWindowsUsedForTraining > 0) {
+ return training.numberOfInitialWindowsUsedForTraining;
+ }
+ return that._getSpecifiedTrainingWindows().length;
+ },
+
+ _areTrainingWindowsSpecified: function () {
+ var that = this;
+ that._getSpecifiedTrainingWindows();
+ return (
+ that.vars.specifiedTrainingWindows !== undefined &&
+ that.vars.specifiedTrainingWindows.length > 0
+ );
+ },
+
+ _getCurrentTrainingWindow: function () {
+ var that = this;
+ if (!that._areTrainingWindowsSpecified()) {
+ return;
+ }
+ var trainingWindows = that._getSpecifiedTrainingWindows();
+ var currentIndex = that.vars.currentTrainingWindowIndex;
+ if (currentIndex > trainingWindows.length - 1) {
+ return;
+ }
+ var trainingWindow = trainingWindows[currentIndex];
+ return trainingWindow;
+ },
+
+ _isCurrentWindowSpecifiedTrainingWindow: function () {
+ var that = this;
+ if (!that._areTrainingWindowsSpecified()) return false;
+ return (
+ that.vars.currentTrainingWindowIndex < that._getNumberOfTrainingWindows()
+ );
+ },
+
+ _getSpecifiedTrainingWindows: function () {
+ var that = this;
+ if (that.vars.specifiedTrainingWindows) {
+ return that.vars.specifiedTrainingWindows;
+ }
+ var training = that.options.visibleRegion.training;
+ if (
+ !that._isTrainingEnabled() ||
+ training.numberOfInitialWindowsUsedForTraining > 0
+ ) {
+ return [];
+ }
+ if (training.windows && training.windows.length > 0) {
+ that.vars.specifiedTrainingWindows = training.windows;
+ return that.vars.specifiedTrainingWindows;
+ }
+ var windows = [];
+ var featureOrder = that.options.features.order;
+ var featureOptions = that.options.features.options;
+ for (f = 0; f < featureOrder.length; ++f) {
+ var feature = featureOrder[f];
+ var featureTrainingWindows = featureOptions[feature].training.windows;
+ if (featureTrainingWindows && featureTrainingWindows.length > 0) {
+ windows.push.apply(windows, featureTrainingWindows);
+ }
+ }
+ that.vars.specifiedTrainingWindows = windows;
+ return that.vars.specifiedTrainingWindows;
+ },
+
+ _isTrainingEnabled: function () {
+ var that = this;
+ return (
+ that._isHITModeEnabled() && that.options.visibleRegion.training.enabled
+ );
+ },
+
+ _isTrainingOnly: function () {
+ var that = this;
+ return that.options.visibleRegion.training.isTrainingOnly;
+ },
+
+ _isCurrentWindowTrainingWindow: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return false;
+ return (
+ that._getWindowIndexForTraining() <=
+ that._getNumberOfTrainingWindows() - 1
+ );
+ },
+
+ _isCurrentWindowFirstTrainingWindow: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return false;
+ return (
+ that._getNumberOfTrainingWindows() > 0 &&
+ that._getWindowIndexForTraining() === 0
+ );
+ },
+
+ _isCurrentWindowLastTrainingWindow: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return false;
+ return (
+ that._getWindowIndexForTraining() ==
+ that._getNumberOfTrainingWindows() - 1
+ );
+ },
+
+ _getWindowIndexForTraining: function () {
+ var that = this;
+ if (!that._isHITModeEnabled()) return false;
+ if (that._areTrainingWindowsSpecified()) {
+ return that.vars.currentTrainingWindowIndex;
+ } else {
+ return that._getCurrentWindowIndexInVisibleRegion();
+ }
+ },
+
+ _revealCorrectAnnotations: function () {
+ var that = this;
+ that._getAnnotations(
+ that.vars.currentWindowRecording,
+ that.vars.currentWindowStart,
+ that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds,
+ true
+ );
+ },
+
+ _setupExamplesMode: function () {
+ var that = this;
+ var examples = that.options.features.examples;
+
+ if (!examples || examples.length == 0) {
+ //console.log('There are no examples for this viewer.');
+ return;
+ }
+ examples.sort(function (a, b) {
+ return a.start - b.start;
+ });
+ var firstExample = examples[0];
+ var recordingName = firstExample.recording;
+ var channelsDisplayed = [
+ firstExample.channels_displayed[firstExample.channels],
+ ];
+ let id = Data.findOne({ path: recordingName })._id;
+ that.options.allRecordings = [{ _id: id, path: recordingName }];
+ that.options.channelsDisplayed = channelsDisplayed;
+ that.options.graph.height = 200;
+ that.options.features.showUserAnnotations = false;
+ that.options.features.order = [firstExample.type];
+ that.options.isReadOnly = true;
+ that.options.channelGainAdjustmentEnabled = true;
+ that.options.showChannelGainAdjustmentButtons = true;
+ that.options.keyboardInputEnabled = false;
+ that.options.showArtifactButtons = false;
+ that.options.showNavigationButtons = false;
+ that.options.showReferenceLines = false;
+ that.options.features.cheatSheetsEnabled = true;
+ that.options.features.openCheatSheetOnPageLoad = true;
+ that.options.showTimeLabels = true;
+ that._fetchOptionsFromURLParameter();
+
+ $(that.element)
+ .find(".button_container")
+ .prepend('Examples for:');
+ $(that.element)
+ .find(".button_container")
+ .append(
+ ' \
'
+ ).appendTo(that.element.find(".graph_container"));
+ var loadingCompleted = false;
+ function updateLoadingProgress() {
+ var percentage = Math.max(
+ 0,
+ Math.min(
+ 100,
+ Math.round((numWindowsLoaded / numWindowsToRequestTotal) * 100)
+ )
+ );
+ progressBar.find(".indicator").css("width", percentage + "%");
+ if (percentage >= 100 && !loadingCompleted) {
+ loadingCompleted = true;
+ setTimeout(() => {
+ progressBar.remove();
+ callback();
+ }, 500);
+ }
+ }
+ updateLoadingProgress();
+ //console.log("channelsDisplayedPerMontage:", channelsDisplayedPerMontage);
+ channelsDisplayedPerMontage.forEach(function (channelsDisplayed, m) {
+ for (var i = 0; i < numWindowsToRequestPerMontage; ++i) {
+ var startTime = i * that.vars.xAxisScaleInSeconds;
+ var options = {
+ recordings: that.options.allRecordings,
+ channels_displayed: channelsDisplayed,
+ start_time: i * that.vars.xAxisScaleInSeconds + 90,
+ window_length: that.vars.xAxisScaleInSeconds,
+ target_sampling_rate: that.options.targetSamplingRate,
+ use_high_precision_sampling: that.options.useHighPrecisionSampling,
+ };
+ ////console.log(options);
+ that._requestData(options, function (data, error) {
+ if (error) {
+ console.log(error);
+ }
+ ++numWindowsLoaded;
+ updateLoadingProgress();
});
- },
-
- _setupFeaturePanel: function() {
- var that = this;
- $('[data-toggle="popover"]').popover({ trigger: 'hover' });
-
- var firstFeature = that.options.features.order[0];
- that.vars.activeFeatureType = firstFeature;
-
- for (var i = 0; i < that.options.features.order.length; i++) {
- var feature_key = that.options.features.order[i];
- var feature_name = that.options.features.options[feature_key].name;
- var featureButton = $('').data('annotation-type', feature_key);
- $(that.element).find('.feature_panel').append(featureButton);
- $('').appendTo('head');
- }
- $(that.element).find('.feature').click(function(event) {
- that._selectFeatureClass($(this));
+ }
+ });
+ },
+
+ _getRecordingMetadata: function () {
+ // get the metadata and total length of the recording
+ var that = this;
+ return new Promise((resolve, reject) => {
+ if (
+ Object.keys(that.vars.recordingMetadata).length ===
+ that.options.allRecordings.length
+ ) {
+ return resolve(that);
+ }
+ Meteor.call(
+ "get.edf.metadata.and.length",
+ that.options.allRecordings,
+ (error, results) => {
+ if (error) {
+ throw new Error("Cannot get recording metadata\n" + error);
+ }
+ that.vars.recordingLengthInSeconds = results.lengthInSeconds;
+ that.vars.recordingMetadata = results.allMetadata;
+ return resolve(that);
+ }
+ );
+ });
+ },
+
+ _triggerOnReadyEvent: function () {
+ var that = this;
+ $(that.element).parents(".assignment-container").trigger("readyToStart");
+ },
+
+ _getUserStatus: function () {
+ var that = this;
+ //console.log("_getUserStatus.that:", that);
+ that._setupMontageSelector();
+ //console.log("Finish _setupMontageSelector");
+ that._setupFrequencyFilterSelector();
+ //console.log("Finish _setupFrequencyFilterSelector");
+ that._setupXAxisScaleSelector();
+ //console.log("Finish _setupXAxisScaleSelector");
+ that._setupAnnotationChoice();
+ //console.log("Finish _setupAnnotationChoice");
+ that._setupAnnotationDisplayType();
+ //console.log("Finish _setupAnnotationDisplayType");
+
+ //console.log("before ifs");
+ if (that.options.experiment.running) {
+ //console.log("that.options.experiment.running");
+ that._updateNavigationStatusForExperiment();
+ var currentWindowIndex =
+ that.options.experiment.current_condition.current_window_index;
+ var conditionWindows = that.options.experiment.current_condition.windows;
+ let id = Data.findOne({
+ path: that.options.experiment.current_condition.recording_name,
+ })._id;
+ that.options.allRecordings = [
+ {
+ _id: id,
+ path: that.options.experiment.current_condition.recording_name,
+ },
+ ];
+ var initialWindowStart = conditionWindows[currentWindowIndex];
+ that.vars.lastActiveWindowStart = initialWindowStart;
+ that._switchToWindow(
+ that.options.allRecordings,
+ initialWindowStart,
+ that.vars.xAxisScaleInSeconds
+ );
+ } else if (that._areTrainingWindowsSpecified()) {
+ //console.log("that._areTrainingWindowsSpecified")
+ var trainingWindow = that._getCurrentTrainingWindow();
+ let id = Data.findOne({ path: trainingWindow.recordingName })._id;
+ trainingWindow.recordingName = [
+ { _id: id, path: trainingWindow.recordingName },
+ ];
+ that._switchToWindow(
+ trainingWindow.recordingName,
+ trainingWindow.timeStart,
+ trainingWindow.windowSizeInSeconds
+ );
+ } else if (that.options.allRecordings.length > 0) {
+ //console.log("that.options.allRecordings")
+ that._loadChannelTimeshiftFromPreference();
+ that.vars.lastActiveWindowStart = +that.options.startTime;
+ const context = that.options.context;
+ const preferencesArbitrationRoundNumber = !!context.preferences
+ .arbitrationRoundNumber
+ ? context.preferences.arbitrationRoundNumber
+ : 0;
+ if (
+ that._isArbitrating() &&
+ preferencesArbitrationRoundNumber < that._getArbitrationRoundNumberInt()
+ ) {
+ that.vars.currentWindowStart = 0;
+ that.vars.lastActiveWindowStart =
+ that._getClosestDisagreementWindowStartTimeInSeconds(1);
+ if (that.vars.lastActiveWindowStart === false) {
+ that.vars.lastActiveWindowStart = that.options.startTime;
+ }
+ }
+ that._switchToWindow(
+ that.options.allRecordings,
+ that.vars.lastActiveWindowStart,
+ that.vars.xAxisScaleInSeconds
+ );
+ } else {
+ alert("Could not retrieve user data.");
+ return;
+ }
+ // that._triggerOnReadyEvent();
+ // $(window).resize(that._reinitChart);
+ },
+
+ _setupArtifactPanel: function () {
+ var activeClass = "teal darken-4";
+ var that = this;
+ $(that.element)
+ .find(".artifact_panel button.artifact")
+ .click(function () {
+ var button = $(this);
+ var type = button.data("annotation-type");
+ that._saveArtifactAnnotation(type);
+ button.addClass(activeClass).siblings().removeClass(activeClass);
+ });
+ },
+
+ _setupSleepStagePanel: function () {
+ // //console.log("inside sleep");
+ var inactiveClass = "grey lighten-1";
+ var activeClassSelectedInPreviousRound =
+ "selected-in-previous-round " + inactiveClass;
+ var activeClassSelectedInCurrentRound = "teal";
+ var activeClasses =
+ activeClassSelectedInPreviousRound +
+ " " +
+ activeClassSelectedInCurrentRound;
+ var that = this;
+ $(that.element)
+ .find(".sleep_stage_panel button.sleep_stage")
+ .click(function () {
+ // //console.log("clicked");
+
+ var button = $(this);
+ var type = button.data("annotation-type");
+ button
+ .removeClass(inactiveClass)
+ .addClass(activeClassSelectedInCurrentRound)
+ .siblings()
+ .removeClass(activeClasses)
+ .addClass(inactiveClass);
+
+ that.vars.currType = type;
+ that._setupAnnotationInteraction();
+ that._saveSleepStageAnnotation(type);
+ });
+ },
+
+ _setupNavigationPanel: function () {
+ var that = this;
+ that._setJumpToLastDisagreementWindowEnabledStatus(false);
+ that._setJumpToNextDisagreementWindowEnabledStatus(false);
+ that._setForwardEnabledStatus(false);
+ that._setFastForwardEnabledStatus(false);
+ that._setBackwardEnabledStatus(false);
+ that._setFastBackwardEnabledStatus(false);
+
+ if (that.options.showBackToLastActiveWindowButton) {
+ $(that.element)
+ .find(".backToLastActiveWindow")
+ .click(function () {
+ that._switchBackToLastActiveWindow();
});
- $(that.element).find('.feature.' + firstFeature)
- .addClass('active')
- .siblings()
- .removeClass('active');
- },
-
- _preloadEntireRecording: function(callback) {
- var that = this;
- if (that._isArbitrating()) {
- callback();
- return;
- }
- var montages = that._getMontages();
- var channelsDisplayedPerMontage = [];
- if (montages) {
- montages.forEach(function(montage) {
- channelsDisplayedPerMontage.push(that._getChannelsDisplayed(montage));
- });
- }
- else {
- channelsDisplayedPerMontage = [ that._getChannelsDisplayed() ];
- }
- var recordingLengthInSeconds = that.vars.recordingMetadata.LengthInSeconds;
- // For local debugging, only
- // preload a maximum of 10 epochs
- if (!Meteor.isProduction) {
- recordingLengthInSeconds = Math.min(10 * that.options.windowSizeInSeconds, recordingLengthInSeconds);
- }
- var numWindowsToRequestPerMontage = Math.ceil(recordingLengthInSeconds / that.options.windowSizeInSeconds);
- var numWindowsToRequestTotal = numWindowsToRequestPerMontage * channelsDisplayedPerMontage.length;
- var numWindowsLoaded = 0;
- var progressBar = $('
').appendTo(that.element.find('.graph_container'));
- var loadingCompleted = false;
- function updateLoadingProgress() {
- var percentage = Math.max(0, Math.min(100, Math.round(numWindowsLoaded / numWindowsToRequestTotal * 100)));
- progressBar.find('.indicator').css('width', percentage + '%');
- if (percentage >= 100 && !loadingCompleted) {
- loadingCompleted = true;
- setTimeout(() => {
- progressBar.remove();
- callback();
- }, 500);
- }
- }
- updateLoadingProgress();
- channelsDisplayedPerMontage.forEach(function(channelsDisplayed, m) {
- for (var i = 0; i < numWindowsToRequestPerMontage; ++i) {
- var startTime = i * that.options.windowSizeInSeconds;
- var options = {
- recording_name: that.options.recordingName,
- channels_displayed: channelsDisplayed,
- start_time: i * that.options.windowSizeInSeconds,
- window_length: that.options.windowSizeInSeconds,
- target_sampling_rate: that.options.targetSamplingRate,
- use_high_precision_sampling: that.options.useHighPrecisionSampling,
- };
- that._requestData(options, function(data, error) {
- if (error) {
- console.log(error);
- }
- ++numWindowsLoaded;
- updateLoadingProgress();
- });
- }
+ }
+ if (that.options.showBookmarkCurrentPageButton) {
+ $(that.element)
+ .find(".bookmarkCurrentPage")
+ .click(function () {
+ that._toggleBookmarkCurrentPage();
});
- },
-
- _getRecordingMetadata: function(callback) {
- var that = this;
- if (that.vars.recordingMetadata) {
- callback(that.vars.recordingMetadata);
- return;
- }
- Meteor.call('get.edf.metadata', that.options.recordingName, function(error, metadata) {
- if (error) {
- callback(null, error.message);
- return;
- }
- that.vars.recordingMetadata = metadata;
- callback(that.vars.recordingMetadata);
+ }
+ if (that._isArbitrating()) {
+ $(that.element)
+ .find(".jumpToLastDisagreementWindow")
+ .click(function () {
+ that._jumpToClosestDisagreementWindow(-1);
});
- },
-
- _triggerOnReadyEvent: function() {
- var that = this;
- $(that.element).parents('.assignment-container').trigger('readyToStart');
- },
-
- _getUserStatus: function() {
- var that = this;
- that._setupMontageSelector();
- that._setupFrequencyFilterSelector();
- if (that.options.experiment.running) {
- that._updateNavigationStatusForExperiment();
- var currentWindowIndex = that.options.experiment.current_condition.current_window_index;
- var conditionWindows = that.options.experiment.current_condition.windows;
- that.options.recordingName = that.options.experiment.current_condition.recording_name;
- var initialWindowStart = conditionWindows[currentWindowIndex];
- that.vars.lastActiveWindowStart = initialWindowStart;
- that._switchToWindow(that.options.recordingName, initialWindowStart, that.options.windowSizeInSeconds);
- }
- else if (that._areTrainingWindowsSpecified()) {
- var trainingWindow = that._getCurrentTrainingWindow();
- that._switchToWindow(trainingWindow.recordingName, trainingWindow.timeStart, trainingWindow.windowSizeInSeconds);
- }
- else if (that.options.recordingName) {
- that.vars.lastActiveWindowStart = that.options.startTime;
- const context = that.options.context;
- const preferencesArbitrationRoundNumber = !!context.preferences.arbitrationRoundNumber ? context.preferences.arbitrationRoundNumber : 0;
- if (
- that._isArbitrating()
- && preferencesArbitrationRoundNumber < that._getArbitrationRoundNumberInt()
- ) {
- that.vars.currentWindowStart = 0;
- that.vars.lastActiveWindowStart = that._getClosestDisagreementWindowStartTimeInSeconds(1);
- if (that.vars.lastActiveWindowStart === false) {
- that.vars.lastActiveWindowStart = that.options.startTime;
- }
- }
- that._switchToWindow(that.options.recordingName, that.vars.lastActiveWindowStart, that.options.windowSizeInSeconds);
- }
- else {
- alert('Could not retrieve user data.');
- return;
- }
- that._triggerOnReadyEvent();
- $(window).resize(that._reinitChart);
- },
-
- _setupArtifactPanel: function() {
- var activeClass = 'teal darken-4';
- var that = this;
- $(that.element).find('.artifact_panel button.artifact').click(function() {
- var button = $(this);
- var type = button.data('annotation-type');
- that._saveArtifactAnnotation(type);
- button
- .addClass(activeClass)
- .siblings()
- .removeClass(activeClass);
+ $(that.element)
+ .find(".jumpToNextDisagreementWindow")
+ .click(function () {
+ that._jumpToClosestDisagreementWindow(1);
});
- },
-
- _setupSleepStagePanel: function() {
- var inactiveClass = 'grey lighten-1';
- var activeClassSelectedInPreviousRound = 'selected-in-previous-round ' + inactiveClass;
- var activeClassSelectedInCurrentRound = 'teal';
- var activeClasses = activeClassSelectedInPreviousRound + ' ' + activeClassSelectedInCurrentRound;
- var that = this;
- $(that.element).find('.sleep_stage_panel button.sleep_stage').click(function() {
- var button = $(this);
- var type = button.data('annotation-type');
- button
- .removeClass(inactiveClass)
- .addClass(activeClassSelectedInCurrentRound)
- .siblings()
- .removeClass(activeClasses)
- .addClass(inactiveClass);
- that._saveSleepStageAnnotation(type);
+ }
+ if (that.options.showForwardButton) {
+ $(that.element)
+ .find(".forward")
+ .click(function () {
+ that._shiftChart(1/5);
});
- },
-
- _setupNavigationPanel: function() {
- var that = this;
- that._setJumpToLastDisagreementWindowEnabledStatus(false);
- that._setJumpToNextDisagreementWindowEnabledStatus(false);
- that._setForwardEnabledStatus(false);
- that._setFastForwardEnabledStatus(false);
- that._setBackwardEnabledStatus(false);
- that._setFastBackwardEnabledStatus(false);
-
- if (that.options.showBackToLastActiveWindowButton) {
- $(that.element).find('.backToLastActiveWindow').click(function() {
- that._switchBackToLastActiveWindow();
- });
- }
- if (that.options.showBookmarkCurrentPageButton) {
- $(that.element).find('.bookmarkCurrentPage').click(function() {
- that._toggleBookmarkCurrentPage();
- });
- }
- if (that._isArbitrating()) {
- $(that.element).find('.jumpToLastDisagreementWindow').click(function() {
- that._jumpToClosestDisagreementWindow(-1);
- });
- $(that.element).find('.jumpToNextDisagreementWindow').click(function() {
- that._jumpToClosestDisagreementWindow(1);
- });
- }
- if (that.options.showForwardButton) {
- $(that.element).find('.forward').click(function() {
- that._shiftChart(1);
- });
- }
- if (that.options.showBackwardButton) {
- $(that.element).find('.backward').click(function() {
- that._shiftChart(-1);
- });
- }
- if (that.options.showFastForwardButton) {
- $(that.element).find('.fastForward').click(function() {
- that._shiftChart(that.options.windowJumpSizeFastForwardBackward);
- });
- }
- if (that.options.showFastBackwardButton) {
- $(that.element).find('.fastBackward').click(function() {
- that._shiftChart(-that.options.windowJumpSizeFastForwardBackward);
- });
- }
- $(that.element).find('.gainUp').click(function() {
- that._updateChannelGain('step_increase');
+ }
+ if (that.options.showBackwardButton) {
+ $(that.element)
+ .find(".backward")
+ .click(function () {
+ that._shiftChart(-1/5);
});
- $(that.element).find('.gainDown').click(function() {
- that._updateChannelGain('step_decrease');
+ }
+ if (that.options.showFastForwardButton) {
+ $(that.element)
+ .find(".fastForward")
+ .click(function () {
+ that._shiftChart(that.options.windowJumpSizeFastForwardBackward);
});
- $(that.element).find('.gainReset').click(function() {
- that._updateChannelGain('reset');
+ }
+ if (that.options.showFastBackwardButton) {
+ $(that.element)
+ .find(".fastBackward")
+ .click(function () {
+ that._shiftChart(-that.options.windowJumpSizeFastForwardBackward);
});
- if (that.options.keyboardInputEnabled) {
- // setup arrow key navigation
- $(document).on('keydown', that._keyDownCallback);
- }
- },
-
- _getClosestDisagreementWindowStartTimeInSeconds: function(direction) {
- var that = this;
- if (!that._isArbitrating()) return false;
- annotationsWithDisagreement = that.options.context.assignment.annotationsWithDisagreementForCurrentArbitrationRound({ reactive: false });
- let notReclassified = Object.values(annotationsWithDisagreement.notReclassified).map(values => values[0].annotation.value.position.start);
- if (direction < 0) {
- notReclassified = notReclassified.filter(start => start < that.vars.currentWindowStart);
- if (notReclassified.length == 0) return false;
- return Math.max.apply(null, notReclassified);
- }
- else {
- notReclassified = notReclassified.filter(start => start > that.vars.currentWindowStart);
- if (notReclassified.length == 0) return false;
- return Math.min.apply(null, notReclassified);
- }
- return false;
- },
-
- _updateJumpToClosestDisagreementWindowButtonsEnabledStatus: function() {
- var that = this;
- const lastDisagreementWindowExists = that._getClosestDisagreementWindowStartTimeInSeconds(-1) !== false;
- that._setJumpToLastDisagreementWindowEnabledStatus(lastDisagreementWindowExists);
- const nextDisagreementWindowExists = that._getClosestDisagreementWindowStartTimeInSeconds(1) !== false;
- that._setJumpToNextDisagreementWindowEnabledStatus(nextDisagreementWindowExists);
- },
-
- _jumpToClosestDisagreementWindow: function(direction) {
- var that = this;
- var startInSeconds = that._getClosestDisagreementWindowStartTimeInSeconds(direction);
- if (startInSeconds === false) return;
- that.jumpToEpochWithStartTime(startInSeconds);
- },
-
- _keyDownCallback: function(e) {
- var that = this;
- if ($(e.target).is('input, textarea, select')) {
- return;
- }
- if (swal.isVisible()) {
- return;
- }
- var keyCode = e.which;
- var metaKeyPressed = e.metaKey;
- if (keyCode == 82 && metaKeyPressed) {
- // Suppress any action on CTRL+R / CMD+R page reload
- return;
- }
- if (keyCode == 72) {
- that._toggleClassificationSummary();
- } else if(keyCode == 66 && that.options.showBookmarkCurrentPageButton) {
- that._toggleBookmarkCurrentPage();
- return;
- } else if((keyCode == 37 /* || keyCode == 65 */ || keyCode == 34) && that.options.showBackwardButton) { // left arrow, a, page down
- // backward
- e.preventDefault();
- that._shiftChart(-1);
- return;
- } else if ((keyCode == 39 /* || keyCode == 68 */ || keyCode == 33) && that.options.showForwardButton) { // right arrow, d, page up
- // forward
- e.preventDefault();
- that._shiftChart(1);
- return;
- } else if (keyCode == 38) { // up arrow
- // fast foward
- e.preventDefault();
- that._updateChannelGain('step_increase');
- return;
- } else if (keyCode == 40) { // down arrow
- // fast backward
- e.preventDefault();
- that._updateChannelGain('step_decrease');
- return;
- } else if (keyCode == 65) {
- that._jumpToClosestDisagreementWindow(-1);
- } else if (keyCode == 68) {
- that._jumpToClosestDisagreementWindow(1);
- } else if (that.options.showSleepStageButtons) {
- var sleepStageShortCutPressed = false;
- $(that.element).find('.sleep_stage_panel .shortcut-key').each(function() {
- var character = $(this).text();
- var characterKeyCodeLowerCase = character.toLowerCase().charCodeAt(0);
- var characterKeyCodeAlternative = character.toUpperCase().charCodeAt(0);
- if (characterKeyCodeLowerCase >= 48 && characterKeyCodeLowerCase <= 57) {
- characterKeyCodeAlternative = characterKeyCodeLowerCase + 48;
- }
- if (keyCode == characterKeyCodeLowerCase || keyCode == characterKeyCodeAlternative) {
- e.preventDefault();
- sleepStageShortCutPressed = true;
- var button = $(this).parents('.sleep_stage').first();
- button.click();
- }
- });
- if (sleepStageShortCutPressed) {
- return;
- }
- // make it possible to choose feature classificaiton using number keys
- } else if (keyCode >= 49 && keyCode <= 57) {
- e.preventDefault();
- var featureClassButton = $(that.element).find('.feature').eq(keyCode - 49)
- if (featureClassButton) {
- that._selectFeatureClass(featureClassButton);
- }
- return;
- // separate case for the numpad keys, because javascript is a stupid language
- } else if (keyCode >= 97 && keyCode <= 105) {
- e.preventDefault();
- var featureClassButton = $(that.element).find('.feature').eq(keyCode - 97)
- if (featureClassButton) {
- that._selectFeatureClass(featureClassButton);
- }
- return;
- }
- },
-
- _toggleClassificationSummary: function() {
- var that = this;
- var classificationSummaryElement = that._getClassificationSummaryElement();
- if (classificationSummaryElement.is(':visible')) {
- classificationSummaryElement.hide();
- classificationSummaryElement.css({ height: 0 });
- }
- else {
- classificationSummaryElement.show();
- classificationSummaryElement.css({ height: '' });
- }
- that._reinitChart();
- },
+ }
+ $(that.element)
+ .find(".gainUp")
+ .click(function () {
+ that._updateChannelGain("step_increase");
+ });
+ $(that.element)
+ .find(".gainDown")
+ .click(function () {
+ that._updateChannelGain("step_decrease");
+ });
+ $(that.element)
+ .find(".gainReset")
+ .click(function () {
+ that._updateChannelGain("reset");
+ });
+ if (that.options.keyboardInputEnabled) {
+ // setup arrow key navigation
+ $(document).on("keydown", that._keyDownCallback);
+ }
+ },
- _toggleBookmarkCurrentPage: function() {
- var that = this;
- const bookmarkedPages = that.options.context.preferences.annotatorConfig.bookmarkedPages || {};
- const pageKey = that.vars.currentWindowStart;
- if (bookmarkedPages[pageKey] === true) {
- delete bookmarkedPages[pageKey];
- }
- else {
- bookmarkedPages[pageKey] = true;
- }
- that._reinitChart();
- that._updateBookmarkCurrentPageButton();
+ _destroyCrosshair: function () {
+ var that = this;
+ if (that.vars.crosshair) {
+ that.vars.crosshair.destroy();
+ that.vars.crosshair = undefined;
+ }
+ return;
+ },
+
+ _isInCrosshairSyncMode: function () {
+ var that = this;
+ return that.vars.timeSyncMode === "crosshair";
+ },
+
+ _isInOffsetSyncMode: function () {
+ var that = this;
+ return that.vars.timeSyncMode === "offset";
+ },
+
+ _isInNoTimelockMode: function () {
+ var that = this;
+ return that.vars.timeSyncMode === "notimelock";
+ },
+
+ _toggleNoTimelockScroll: function (toggle) {
+ var that = this;
+ var chart = that.vars.chart;
+
+ function scroll(e) {
+ let dist = e.deltaY * 0.025;
+ let channelIndex = that.vars.selectedChannelIndex;
+ if (channelIndex !== undefined) {
+ let modifiedDataId = chart.series[channelIndex].options.custom.dataId;
+ let timeshift = that.vars.channelTimeshift[modifiedDataId];
+ timeshift = timeshift ? timeshift + dist : dist;
+ let recordingLength =
+ that.vars.recordingMetadata[modifiedDataId].LengthInSeconds;
+ that.vars.channelTimeshift[modifiedDataId] = Math.min(
+ recordingLength,
+ Math.max(0, timeshift)
+ );
+ // that.vars.reprint = 1;
that._savePreferences({
- bookmarkedPages: bookmarkedPages,
+ channelTimeshift: that.vars.channelTimeshift,
});
- },
-
- _updateBookmarkCurrentPageButton: function() {
- var that = this;
- const bookmarkedPages = that.options.context.preferences.annotatorConfig.bookmarkedPages || {};
- const pageKey = that.vars.currentWindowStart;
- const isBookmarked = bookmarkedPages[pageKey] === true;
- $(that.element).find('.bookmarkCurrentPage').prop('disabled', null).toggleClass('active', isBookmarked);
- },
-
- _setupTrainingPhase: function() {
- var that = this;
- if (!that._areTrainingWindowsSpecified()) return;
- that._setForwardEnabledStatus(true);
- that._getSpecifiedTrainingWindows();
- },
-
- _setupArbitration: function() {
- var that = this;
- if (!that._isArbitrating()) return;
- that.options.numberOfForwardWindowsToPrefetch = 2;
- that.options.numberOfFastForwardWindowsToPrefetch = 0;
- that.options.numberOfBackwardWindowsToPrefetch = 2;
- that.options.numberOfFastBackwardWindowsToPrefetch = 0;
- },
-
- _setJumpToLastDisagreementWindowEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.jumpToLastDisagreementWindow = status;
- $(that.element).find('.jumpToLastDisagreementWindow').prop('disabled', !status);
- },
-
- _setJumpToNextDisagreementWindowEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.jumpToNextDisagreementWindow = status;
- $(that.element).find('.jumpToNextDisagreementWindow').prop('disabled', !status);
- },
-
- _setForwardEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.forwardEnabled = status;
- $(that.element).find('.forward').prop('disabled', !status);
- },
-
- _setFastForwardEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.fastForwardEnabled = status;
- $(that.element).find('.fastForward').prop('disabled', !status);
- },
-
- _setBackwardEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.backwardEnabled = status;
- $(that.element).find('.backward').prop('disabled', !status);
- },
-
- _setFastBackwardEnabledStatus: function(status) {
- var that = this;
- var status = !!status;
-
- that.vars.fastBackwardEnabled = status;
- $(that.element).find('.fastBackward').prop('disabled', !status);
- },
+ that._reloadCurrentWindow();
+ }
+ }
- _selectFeatureClass: function(featureClassButton) {
- /* called with the user clicks on one of the feature toggle buttons, or presses one of the
+ if (toggle) {
+ Highcharts.addEvent(document, "wheel", scroll);
+ } else {
+ Highcharts.removeEvent(document, "wheel", scroll);
+ that.vars.reprint = 1;
+ that._reloadCurrentWindow();
+ }
+ },
+
+ _toggleTimeSyncMode: function (mode) {
+ var that = this;
+ switch (mode) {
+ case "crosshair":
+ $(".timesync").prop("disabled", false);
+ that._toggleNoTimelockScroll(false);
+ that._displayCrosshair(that.vars.crosshairPosition);
+ break;
+ case "notimelock":
+ $(".timesync").prop("disabled", true);
+ that._destroyCrosshair();
+ that._toggleNoTimelockScroll(true);
+ $(".time_sync").text("");
+ that.vars.currentTimeDiff = 0;
+ break;
+ case "offset":
+ // $(".time_sync").text("");
+ $(".timesync").prop("disabled", false);
+ that._toggleNoTimelockScroll(false);
+ that._destroyCrosshair();
+ break;
+ case "undefined":
+ default:
+ $(".timesync").prop("disabled", true);
+ that._toggleNoTimelockScroll(false);
+ that._destroyCrosshair();
+ break;
+ }
+ },
+
+ _performCrosshairSync: function () {
+ var that = this;
+ let crosshairPosition = that.vars.crosshairPosition;
+ let ids = crosshairPosition.map((rec) => rec.dataId);
+ let currentDiff = ids.map((id) => that.vars.channelTimeshift[id]);
+ if (crosshairPosition.length === 2) {
+ // calculate the difference between two recordings after adding the current difference
+ let diff =
+ crosshairPosition[0].timeInSeconds - crosshairPosition[1].timeInSeconds;
+ that.vars.currentTimeDiff += diff;
+ console.log("=======" + diff + "======");
+ $(".time_sync").text("Time Difference: " + that.vars.currentTimeDiff);
+ if (diff > 0) {
+ if (currentDiff[1]) {
+ let remainder = diff - currentDiff[1];
+ if (remainder > 0) {
+ that.vars.channelTimeshift[ids[1]] = 0;
+ that.vars.channelTimeshift[ids[0]] = currentDiff[0]
+ ? currentDiff[0] + remainder
+ : remainder;
+ } else {
+ that.vars.channelTimeshift[ids[1]] = -remainder;
+ }
+ } else {
+ that.vars.channelTimeshift[ids[0]] = currentDiff[0]
+ ? currentDiff[0] + diff
+ : diff;
+ }
+ } else if (diff < 0) {
+ diff = -diff;
+ if (currentDiff[0]) {
+ let remainder = diff - currentDiff[0];
+ if (remainder > 0) {
+ that.vars.channelTimeshift[ids[0]] = 0;
+ that.vars.channelTimeshift[ids[1]] = currentDiff[1]
+ ? currentDiff[1] + remainder
+ : remainder;
+ } else {
+ that.vars.channelTimeshift[ids[0]] = -remainder;
+ }
+ } else {
+ that.vars.channelTimeshift[ids[1]] = currentDiff[1]
+ ? currentDiff[1] + diff
+ : diff;
+ }
+ }
+ that.vars.reprint = 1;
+ that.vars.crosshairPosition = [];
+ $(this.element)
+ .find(".timesync_panel select")
+ .val("undefined")
+ .change()
+ .material_select();
+ that._savePreferences({
+ channelTimeshift: that.vars.channelTimeshift,
+ });
+
+ $("#alignment-alert").hide();
+ that._reloadCurrentWindow();
+ }
+ },
+
+ _performOffsetSync: function () {
+ var that = this;
+ that.vars.channelTimeshift = {};
+ that.vars.reprint = 1;
+ $(this.element)
+ .find(".timesync_panel select")
+ .val("undefined")
+ .change()
+ .material_select();
+ that._savePreferences({ channelTimeshift: that.vars.channelTimeshift });
+ that._reloadCurrentWindow();
+ console.log(that.vars.channelTimeshift);
+ that.vars.currentTimeDiff = 0;
+ $(".time_sync").text("");
+ },
+
+ _setupTimeSyncPanel: function () {
+ var that = this;
+ let timeSyncOptions = that.options.timeSyncOptions || [];
+ timeSyncOptions.forEach((timeSyncOption) => {
+ let selectContainer = $(
+ ''
+ ).appendTo(that.element.find(".timesync_panel"));
+ let select = selectContainer.find("select");
+ let defaultOptionIndex = null;
+ timeSyncOption.options.forEach((option, i) => {
+ let selectedString = "";
+ if (option.default) {
+ selectedString = ' selected="selected"';
+ defaultOptionIndex = i;
+ }
+ select.append(
+ `"
+ );
+ });
+
+ select.material_select();
+ select.change(function () {
+ if (defaultOptionIndex)
+ delete timeSyncOption.options[defaultOptionIndex].default;
+ timeSyncOption.options[select.prop("selectedIndex")].default = true;
+ that.vars.timeSyncMode = select.val();
+ that._toggleTimeSyncMode(select.val());
+ that._renderAlignmentAlert();
+ });
+ });
+ $(that.element)
+ .find(".timesync")
+ .click(function () {
+ if (that._isInCrosshairSyncMode()) {
+ that._performCrosshairSync();
+ } else if (that._isInOffsetSyncMode()) {
+ that._performOffsetSync();
+ } else if (that._isInNoTimelockMode()) {
+ // future implementations:
+ // besides free scrolling by mouse wheel,
+ // adding [+/-] hh:mm:ss option and [shift left/right] buttons
+ }
+ });
+ },
+
+ _isInCrosshairWindow: function (crosshair) {
+ var that = this;
+ return (
+ that.vars.currentWindowStart <= crosshair.timeInSeconds &&
+ crosshair.timeInSeconds <=
+ that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ _displayCrosshair: function (crosshairPosition) {
+ var that = this;
+ that._destroyCrosshair();
+ if (!that._isInCrosshairSyncMode()) return;
+ let chart = that.vars.chart;
+ that.vars.crosshair = chart.renderer.g().add();
+ crosshairPosition.forEach((crosshair) => {
+ if (!that._isInCrosshairWindow(crosshair)) return;
+ let left = chart.plotLeft;
+ let top = chart.plotTop;
+ let height = chart.plotHeight;
+ let heightPerChannel =
+ height / that.vars.currentWindowData.channels.length;
+ let firstIndexOfChannel = undefined;
+ let lastIndexOfChannel = undefined;
+ chart.series.forEach((channel, i) => {
+ if (
+ channel.options.custom.dataId === crosshair.dataId &&
+ channel.points.length
+ ) {
+ if (typeof firstIndexOfChannel === "undefined") {
+ firstIndexOfChannel = i;
+ }
+ lastIndexOfChannel = i;
+ }
+ });
+ let crosshairTop = firstIndexOfChannel * heightPerChannel;
+ let crosshairBottom = (lastIndexOfChannel + 1) * heightPerChannel;
+ // draw the crosshair using svgPath and add it as a highchart SVGElement
+ let svgPath = [
+ "M",
+ left + crosshair.plotX,
+ top + crosshairTop,
+ "L",
+ left + crosshair.plotX,
+ top + crosshairBottom,
+ ];
+ chart.renderer
+ .path(svgPath)
+ .attr({
+ "stroke-width": 1,
+ stroke: "blue",
+ })
+ .add(that.vars.crosshair);
+ });
+ },
+
+ //checks what the dataId is of the top/bottom channels when aligning 2 channels
+ //used to check if the channel is the top or bottom one when using crosshair alignment
+ _getTopDataId: function () {
+ //get all the channels
+ var that = this;
+ const channels = that.vars.currentWindowData.channels;
+ //get the first channel
+ const firstChannel = channels[0];
+ //get the dataId of the first channel
+ const firstChannelDataId = firstChannel.dataId;
+ return firstChannelDataId;
+ },
+
+ _getBottomDataId: function () {
+ //get all the channels
+ var that = this;
+ const channels = that.vars.currentWindowData.channels;
+ //get the last channel
+ const lastChannel = channels[channels.length - 1];
+ //get the dataId of the last channel
+ const lastChannelDataId = lastChannel.dataId;
+ return lastChannelDataId;
+ },
+
+ _isFromSource: function (dataId, source) {
+ var that = this;
+ // console.log("dataId: " + dataId);
+ // console.log("source: " + source);
+ let found = false;
+
+ that.options.context.dataset.forEach((dataset) => {
+ // console.log(dataset, dataset._id, dataset.source);
+ // console.log(dataset._id === dataId);
+ // console.log(dataset.source === source);
+ if (dataset._id === dataId && dataset.source === source) {
+ // console.log(true)
+ found = true;
+ }
+ });
+
+ return found;
+ },
+
+ _isFromPSG: function (dataId) {
+ var that = this;
+ return that._isFromSource(dataId, "PSG");
+ },
+
+ _setCrosshair: function (point) {
+ var that = this;
+
+ // console.log("======getTopDataId()======");
+ // console.log(that._getTopDataId());
+ // console.log("======getBottomDataId()=====");
+ // console.log(that._getBottomDataId());
+ // console.log("======that.options======");
+ // console.log(that.options);
+ // console.log("======that.isFromPSG======");
+ // console.log("-top")
+ // console.log(that._isFromPSG(that._getTopDataId()));
+ // console.log("-bottom")
+ // console.log(that._isFromPSG(that._getBottomDataId()));
+ console.log(that._isFromPSG(point.dataId));
+
+ if (!that._isInCrosshairSyncMode()) return;
+
+ if (
+ that.vars.crosshairPosition.length === 0 &&
+ !that._isFromPSG(point.dataId)
+ )
+ return;
+ let crosshairPosition = that.vars.crosshairPosition;
+ let sameRecording = false;
+ let index = undefined;
+ crosshairPosition.forEach((crosshair, i) => {
+ if (crosshair.dataId === point.dataId) {
+ sameRecording = true;
+ index = i;
+ }
+ });
+ if (sameRecording) {
+ crosshairPosition[index] = point;
+ } else {
+ if (crosshairPosition.length < 2) {
+ crosshairPosition.push(point);
+ }
+ // if (crosshairPosition.length > 2) {
+ // crosshairPosition.shift();
+ // }
+ }
+ that.vars.crosshairPosition = crosshairPosition;
+ that._displayCrosshair(crosshairPosition);
+ that._renderAlignmentAlert();
+ },
+
+ _getClosestDisagreementWindowStartTimeInSeconds: function (direction) {
+ var that = this;
+ if (!that._isArbitrating()) return false;
+ annotationsWithDisagreement =
+ that.options.context.assignment.annotationsWithDisagreementForCurrentArbitrationRound(
+ { reactive: false }
+ );
+ let notReclassified = Object.values(
+ annotationsWithDisagreement.notReclassified
+ ).map((values) => values[0].annotation.value.position.start);
+ if (direction < 0) {
+ notReclassified = notReclassified.filter(
+ (start) => start < that.vars.currentWindowStart
+ );
+ if (notReclassified.length == 0) return false;
+ return Math.max.apply(null, notReclassified);
+ } else {
+ notReclassified = notReclassified.filter(
+ (start) => start > that.vars.currentWindowStart
+ );
+ if (notReclassified.length == 0) return false;
+ return Math.min.apply(null, notReclassified);
+ }
+ return false;
+ },
+
+ _updateJumpToClosestDisagreementWindowButtonsEnabledStatus: function () {
+ var that = this;
+ const lastDisagreementWindowExists =
+ that._getClosestDisagreementWindowStartTimeInSeconds(-1) !== false;
+ that._setJumpToLastDisagreementWindowEnabledStatus(
+ lastDisagreementWindowExists
+ );
+ const nextDisagreementWindowExists =
+ that._getClosestDisagreementWindowStartTimeInSeconds(1) !== false;
+ that._setJumpToNextDisagreementWindowEnabledStatus(
+ nextDisagreementWindowExists
+ );
+ },
+
+ _jumpToClosestDisagreementWindow: function (direction) {
+ var that = this;
+ var startInSeconds =
+ that._getClosestDisagreementWindowStartTimeInSeconds(direction);
+ if (startInSeconds === false) return;
+ that.jumpToEpochWithStartTime(startInSeconds);
+ },
+
+ // handles keypress events
+ _keyDownCallback: function (e) {
+ var that = this;
+ if ($(e.target).is("input, textarea, select")) {
+ return;
+ }
+ if (swal.isVisible()) {
+ return;
+ }
+ var keyCode = e.which;
+ var metaKeyPressed = e.metaKey;
+ if (keyCode == 82 && metaKeyPressed) {
+ // Suppress any action on CTRL+R / CMD+R page reload
+ return;
+ }
+ if (keyCode == 72) {
+ that._toggleClassificationSummary();
+ } else if (keyCode == 66 && that.options.showBookmarkCurrentPageButton) {
+ that._toggleBookmarkCurrentPage();
+ return;
+ } else if (
+ (keyCode == 37 /* || keyCode == 65 */ || keyCode == 34) &&
+ that.options.showBackwardButton
+ ) {
+ // left arrow, a, page down
+ // backward
+ e.preventDefault();
+ that._shiftChart(-1);
+ return;
+ } else if (
+ (keyCode == 39 /* || keyCode == 68 */ || keyCode == 33) &&
+ that.options.showForwardButton
+ ) {
+ // right arrow, d, page up
+ // forward
+ e.preventDefault();
+ that._shiftChart(1);
+ return;
+ } else if (keyCode == 38) {
+ // up arrow
+ // fast foward
+ e.preventDefault();
+ that._updateChannelGain("step_increase");
+ return;
+ } else if (keyCode == 40) {
+ // down arrow
+ // fast backward
+ e.preventDefault();
+ that._updateChannelGain("step_decrease");
+ return;
+ } else if (keyCode == 65) {
+ that._jumpToClosestDisagreementWindow(-1);
+ } else if (keyCode == 68) {
+ that._jumpToClosestDisagreementWindow(1);
+ } else if (that.options.showSleepStageButtons) {
+ var sleepStageShortCutPressed = false;
+ $(that.element)
+ .find(".sleep_stage_panel .shortcut-key")
+ .each(function () {
+ var character = $(this).text();
+ var characterKeyCodeLowerCase = character.toLowerCase().charCodeAt(0);
+ var characterKeyCodeAlternative = character
+ .toUpperCase()
+ .charCodeAt(0);
+ if (
+ characterKeyCodeLowerCase >= 48 &&
+ characterKeyCodeLowerCase <= 57
+ ) {
+ characterKeyCodeAlternative = characterKeyCodeLowerCase + 48;
+ }
+ if (
+ keyCode == characterKeyCodeLowerCase ||
+ keyCode == characterKeyCodeAlternative
+ ) {
+ e.preventDefault();
+ sleepStageShortCutPressed = true;
+ var button = $(this).parents(".sleep_stage").first();
+ button.click();
+ }
+ });
+ if (sleepStageShortCutPressed) {
+ return;
+ }
+ // make it possible to choose feature classificaiton using number keys
+ } else if (keyCode >= 49 && keyCode <= 57) {
+ e.preventDefault();
+ var featureClassButton = $(that.element)
+ .find(".feature")
+ .eq(keyCode - 49);
+ if (featureClassButton) {
+ that._selectFeatureClass(featureClassButton);
+ }
+ return;
+ // separate case for the numpad keys, because javascript is a stupid language
+ } else if (keyCode >= 97 && keyCode <= 105) {
+ e.preventDefault();
+ var featureClassButton = $(that.element)
+ .find(".feature")
+ .eq(keyCode - 97);
+ if (featureClassButton) {
+ that._selectFeatureClass(featureClassButton);
+ }
+ return;
+ }
+ },
+
+ _toggleClassificationSummary: function () {
+ var that = this;
+ var classificationSummaryElement = that._getClassificationSummaryElement();
+ if (classificationSummaryElement.is(":visible")) {
+ classificationSummaryElement.hide();
+ classificationSummaryElement.css({ height: 0 });
+ } else {
+ classificationSummaryElement.show();
+ classificationSummaryElement.css({ height: "" });
+ }
+ that._reinitChart();
+ },
+
+ _toggleBookmarkCurrentPage: function () {
+ var that = this;
+ const bookmarkedPages =
+ that.options.context.preferences.annotatorConfig.bookmarkedPages || {};
+ const pageKey = that.vars.currentWindowStart;
+ if (bookmarkedPages[pageKey] === true) {
+ delete bookmarkedPages[pageKey];
+ } else {
+ bookmarkedPages[pageKey] = true;
+ }
+ that._reinitChart();
+ that._updateBookmarkCurrentPageButton();
+ that._savePreferences({
+ bookmarkedPages: bookmarkedPages,
+ });
+ },
+
+ _updateBookmarkCurrentPageButton: function () {
+ var that = this;
+ const bookmarkedPages =
+ that.options.context.preferences.annotatorConfig.bookmarkedPages || {};
+ const pageKey = that.vars.currentWindowStart;
+ const isBookmarked = bookmarkedPages[pageKey] === true;
+ $(that.element)
+ .find(".bookmarkCurrentPage")
+ .prop("disabled", null)
+ .toggleClass("active", isBookmarked);
+ },
+
+ _setupTrainingPhase: function () {
+ var that = this;
+ if (!that._areTrainingWindowsSpecified()) return;
+ that._setForwardEnabledStatus(true);
+ that._getSpecifiedTrainingWindows();
+ },
+
+ _setupArbitration: function () {
+ var that = this;
+ if (!that._isArbitrating()) return;
+ that.options.numberOfForwardWindowsToPrefetch = 2;
+ that.options.numberOfFastForwardWindowsToPrefetch = 0;
+ that.options.numberOfBackwardWindowsToPrefetch = 2;
+ that.options.numberOfFastBackwardWindowsToPrefetch = 0;
+ },
+
+ _setJumpToLastDisagreementWindowEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.jumpToLastDisagreementWindow = status;
+ $(that.element)
+ .find(".jumpToLastDisagreementWindow")
+ .prop("disabled", !status);
+ },
+
+ _setJumpToNextDisagreementWindowEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.jumpToNextDisagreementWindow = status;
+ $(that.element)
+ .find(".jumpToNextDisagreementWindow")
+ .prop("disabled", !status);
+ },
+
+ _setForwardEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.forwardEnabled = status;
+ $(".forward").prop("disabled", !status);
+ },
+
+ _setFastForwardEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.fastForwardEnabled = status;
+ $(".fastForward").prop("disabled", !status);
+ },
+
+ _setBackwardEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.backwardEnabled = status;
+ $(".backward").prop("disabled", !status);
+ },
+
+ _setFastBackwardEnabledStatus: function (status) {
+ var that = this;
+ var status = !!status;
+
+ that.vars.fastBackwardEnabled = status;
+ $(".fastBackward").prop("disabled", !status);
+ },
+
+ _selectFeatureClass: function (featureClassButton) {
+ /* called with the user clicks on one of the feature toggle buttons, or presses one of the
relevant number keys, this method updates the state of the toggle buttons, and sets the
feature type */
- var that = this;
- featureClassButton.addClass('active');
- featureClassButton.siblings().removeClass('active');
- that.vars.activeFeatureType = featureClassButton.data('annotation-type');
- },
-
- _shiftChart: function(windows) {
- var that = this;
- if (!that.vars.forwardEnabled && windows >= 1) return;
- if (!that.vars.fastForwardEnabled && windows >= that.options.windowJumpSizeFastForwardBackward) return;
- if (!that.vars.backwardEnabled && windows <= -1) return;
- if (!that.vars.fastBackwardEnabled && windows <= -that.options.windowJumpSizeFastForwardBackward) return;
- var nextRecordingName = that.options.recordingName;
- var nextWindowSizeInSeconds = that.options.windowSizeInSeconds;
- var nextWindowStart = that.options.currentWindowStart;
- if (that.options.experiment.running) {
- var currentWindowIndex = that.options.experiment.current_condition.current_window_index;
- currentWindowIndex += windows;
- that.options.experiment.current_condition.current_window_index = currentWindowIndex;
- nextWindowStart = that.options.experiment.current_condition.windows[currentWindowIndex];
- that._updateNavigationStatusForExperiment();
- }
- else if (
- that._areTrainingWindowsSpecified()
- && that._isCurrentWindowTrainingWindow()
- ) {
- that.vars.currentTrainingWindowIndex += windows;
- if (that._isCurrentWindowTrainingWindow()) {
- var nextTrainingWindow = that._getCurrentTrainingWindow();
- nextRecordingName = nextTrainingWindow.recordingName;
- nextWindowStart = nextTrainingWindow.timeStart;
- nextWindowSizeInSeconds = nextTrainingWindow.windowSizeInSeconds;
- }
- else {
- nextWindowStart = that.options.startTime;
- nextWindowSizeInSeconds = that.options.windowSizeInSeconds;
- }
- that._flushAnnotations();
- }
- else {
- if (that._areTrainingWindowsSpecified()) {
- that.vars.currentTrainingWindowIndex += windows;
- }
- nextWindowStart = Math.max(0, that.vars.currentWindowStart + that.options.windowSizeInSeconds * windows);
- }
- that._switchToWindow(nextRecordingName, nextWindowStart, nextWindowSizeInSeconds);
- },
-
- _switchToWindow: function (recording_name, start_time, window_length) {
- var that = this;
- if (!that._isCurrentWindowSpecifiedTrainingWindow()) {
- if (that.options.visibleRegion.start !== undefined) {
- start_time = Math.max(that.options.visibleRegion.start, start_time);
- start_time = window_length * Math.ceil(start_time / window_length);
- that._setBackwardEnabledStatus(start_time - window_length >= that.options.visibleRegion.start);
- that._setFastBackwardEnabledStatus(start_time - window_length * that.options.windowJumpSizeFastForwardBackward >= that.options.visibleRegion.start);
- }
-
- if (that.options.visibleRegion.end !== undefined) {
- start_time = Math.min(that.options.visibleRegion.end - window_length, start_time);
- start_time = window_length * Math.floor(start_time / window_length);
- var forwardEnabled = start_time + window_length <= that.options.visibleRegion.end - window_length;
- that._setForwardEnabledStatus(forwardEnabled);
- if (!forwardEnabled) {
- that._lastWindowReached();
- }
- that._setFastForwardEnabledStatus(start_time + window_length * that.options.windowJumpSizeFastForwardBackward < that.options.visibleRegion.end - window_length);
- }
- }
+ var that = this;
+ featureClassButton.addClass("active");
+ featureClassButton.siblings().removeClass("active");
+ that.vars.activeFeatureType = featureClassButton.data("annotation-type");
+ },
+
+ _shiftChart: function (windows) {
+ var that = this;
+ if (!that.vars.forwardEnabled && windows >= 1) return;
+ if (
+ !that.vars.fastForwardEnabled &&
+ windows >= that.options.windowJumpSizeFastForwardBackward
+ )
+ return;
+ if (!that.vars.backwardEnabled && windows <= -1) return;
+ if (
+ !that.vars.fastBackwardEnabled &&
+ windows <= -that.options.windowJumpSizeFastForwardBackward
+ )
+ return;
+ var nextRecordings = that.options.allRecordings;
+ var nextWindowSizeInSeconds = that.vars.xAxisScaleInSeconds;
+ var nextWindowStart = that.options.currentWindowStart;
+ if (that.options.experiment.running) {
+ var currentWindowIndex =
+ that.options.experiment.current_condition.current_window_index;
+ currentWindowIndex += windows;
+ that.options.experiment.current_condition.current_window_index =
+ currentWindowIndex;
+ nextWindowStart =
+ that.options.experiment.current_condition.windows[currentWindowIndex];
+ that._updateNavigationStatusForExperiment();
+ } else if (
+ that._areTrainingWindowsSpecified() &&
+ that._isCurrentWindowTrainingWindow()
+ ) {
+ that.vars.currentTrainingWindowIndex += windows;
+ if (that._isCurrentWindowTrainingWindow()) {
+ var nextTrainingWindow = that._getCurrentTrainingWindow();
+ let id = Data.findOne({
+ path: nextTrainingWindow.recordingName,
+ })._id;
+ nextRecordings = [{ _id: id, path: nextTrainingWindow.recordingName }];
+ nextWindowStart = nextTrainingWindow.timeStart;
+ nextWindowSizeInSeconds = nextTrainingWindow.windowSizeInSeconds;
+ } else {
+ nextWindowStart = that.options.startTime;
+ nextWindowSizeInSeconds = that.vars.xAxisScaleInSeconds;
+ }
+ that._flushAnnotations();
+ } else {
+ if (that._areTrainingWindowsSpecified()) {
+ that.vars.currentTrainingWindowIndex += windows;
+ }
+ nextWindowStart = Math.max(
+ 0,
+ that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds * windows
+ );
+ }
+ that._switchToWindow(
+ nextRecordings,
+ nextWindowStart,
+ nextWindowSizeInSeconds
+ );
+ },
+
+ _switchToWindow: function (allRecordings, start_time, window_length) {
+ // the main funciton called when navigating to another window
+ var that = this;
+ //console.log("_switchToWindow.that:", that);
+
+ // can be ignored for now, something to do with the machine learning component of the app
+ // console.log(!that._isCurrentWindowSpecifiedTrainingWindow());
+
+ if (!that._isCurrentWindowSpecifiedTrainingWindow()) {
+ //console.log("0");
+ if (that.options.visibleRegion.start !== undefined) {
+ //console.log("0-1");
+ start_time = Math.max(that.options.visibleRegion.start, start_time);
+ start_time = window_length * Math.ceil(start_time / window_length);
+
+ that._setBackwardEnabledStatus(
+ start_time - window_length >= that.options.visibleRegion.start
+ );
+ that._setFastBackwardEnabledStatus(
+ start_time -
+ window_length * that.options.windowJumpSizeFastForwardBackward >=
+ that.options.visibleRegion.start
+ );
+ }
+ // console.log(that.options.visibleRegion.end);
+ if (that.options.visibleRegion.end !== undefined) {
+ //console.log("0-2");
+ start_time = Math.min(
+ that.options.visibleRegion.end - window_length,
+ start_time
+ );
+ start_time = window_length * Math.floor(start_time / window_length);
+ var forwardEnabled =
+ start_time + window_length <=
+ that.options.visibleRegion.end - window_length;
+ that._setForwardEnabledStatus(forwardEnabled);
+ if (!forwardEnabled) {
+ //console.log("0-2-1");
+ that._lastWindowReached();
+ }
+ var fastForwardEnabled = start_time +
+ window_length * that.options.windowJumpSizeFastForwardBackward <
+ that.options.visibleRegion.end - window_length;
+
+ // console.log(fastForwardEnabled);
- if (that.vars.currentWindowStart != start_time) {
- that._setNumberOfAnnotationsInCurrentWindow(0);
- }
+ that._setFastForwardEnabledStatus(
+ fastForwardEnabled
+ );
+ }
+ }
- that.vars.currentWindowStart = start_time;
- that.vars.currentWindowRecording = recording_name;
- that._updateJumpToClosestDisagreementWindowButtonsEnabledStatus();
+ if (that.vars.currentWindowStart != start_time) {
+ //if the window has changed (i.e. the user has clicked on a new window)
+ //console.log("1");
+ that._setNumberOfAnnotationsInCurrentWindow(0); // reset the number of annotations in the current window
+ }
- if (that._isVisibleRegionDefined()) {
- var progress = that._getProgressInPercent();
- $(that.element).find('.progress-bar').css('width', progress + '%');
- }
+ that.vars.currentWindowStart = start_time; // update the current window start
+ that.vars.currentWindowRecording = that.options.recordingName; // update the current window recording
+ that._updateJumpToClosestDisagreementWindowButtonsEnabledStatus();
+
+ //
+ if (that._isVisibleRegionDefined()) {
+ //console.log("2");
+ var progress = that._getProgressInPercent();
+ $(that.element)
+ .find(".progress-bar")
+ .css("width", progress + "%");
+ }
- if (that._isCurrentWindowLastTrainingWindow() && that._isTrainingOnly()) {
- that._lastWindowReached();
- }
+ if (that._isCurrentWindowLastTrainingWindow() && that._isTrainingOnly()) {
+ //console.log("3");
+ that._lastWindowReached();
+ }
- if (that._isCurrentWindowFirstTrainingWindow() && !that._isTrainingOnly()) {
- bootbox.alert({
- closeButton: false,
- title: 'Beginning of the Training Phase',
- message: 'Welcome to our CrowdEEG experiment for scientific crowdsourcing!
This is the beginning of the training phase, meaning that, for the next ' + that._getNumberOfTrainingWindows() + ' window(s), we will show you the correct answer after you have submitted yours. The examples panel below will be visible throughout the entire task. We hope the training phase will help you learn more about the signal pattern we are looking for.',
- callback: function() {
- that._saveUserEventWindowBegin();
- },
- }).css({zIndex: 1}).appendTo(that.element);
- }
- else {
+ if (that._isCurrentWindowFirstTrainingWindow() && !that._isTrainingOnly()) {
+ //console.log("4");
+ bootbox
+ .alert({
+ closeButton: false,
+ title: "Beginning of the Training Phase",
+ message:
+ "Welcome to our CrowdEEG experiment for scientific crowdsourcing!
This is the beginning of the training phase, meaning that, for the next " +
+ that._getNumberOfTrainingWindows() +
+ " window(s), we will show you the correct answer after you have submitted yours. The examples panel below will be visible throughout the entire task. We hope the training phase will help you learn more about the signal pattern we are looking for.",
+ callback: function () {
that._saveUserEventWindowBegin();
- }
-
- that._savePreferences({ startTime: start_time })
+ },
+ })
+ .css({ zIndex: 1 })
+ .appendTo(that.element);
+ } else {
+ //console.log("4-1");
+ that._saveUserEventWindowBegin();
+ }
- var windowsToRequest = [
- start_time
- ];
+ that._savePreferences({ startTime: start_time });
+
+ var windowsToRequest = [
+ //stores all "pre loaded" windows
+ start_time,
+ ];
+ if (
+ !that._isCurrentWindowSpecifiedTrainingWindow() &&
+ !that.options.experiment.running &&
+ !that._isInNoTimelockMode() // stop caching windows if in no timelock mode
+ ) {
+ //console.log("5");
+ for (var i = 1; i <= that.options.numberOfForwardWindowsToPrefetch; ++i) {
+ windowsToRequest.push(start_time + i * window_length);
+ }
+ for (
+ var i = 1;
+ i <= that.options.numberOfFastForwardWindowsToPrefetch;
+ ++i
+ ) {
+ let window = start_time + i * that.options.windowJumpSizeFastForwardBackward * window_length;
+ if (!windowsToRequest.includes(window)) {
+ windowsToRequest.push(window);
+ }
+ }
+ for (
+ var i = 1;
+ i <= that.options.numberOfBackwardWindowsToPrefetch;
+ ++i
+ ) {
+ let window = start_time - i * window_length;
+ if (!windowsToRequest.includes(window)) {
+ windowsToRequest.push(window);
+ }
+ }
+ for (
+ var i = 1;
+ i <= that.options.numberOfFastBackwardWindowsToPrefetch;
+ ++i
+ ) {
+ let window = start_time - i * that.options.windowJumpSizeFastForwardBackward * window_length;
+ if (!windowsToRequest.includes(window)) {
+ windowsToRequest.push(window);
+ }
+ }
+ }
+ windowsToRequest.forEach((windowStartTime) => {
+ //console.log("6, windowStartTime:", windowStartTime);
+ // gets the data for all the prefetched windows
+ var startTime = (windowStartTime > 0 ?
+ (windowStartTime < that.vars.recordingLengthInSeconds + window_length ? Math.min(that.vars.recordingLengthInSeconds, windowStartTime) : windowStartTime):
+ (windowStartTime > -window_length ? Math.max(0, windowStartTime) : windowStartTime)
+ );
+
+ var options = {
+ recordings: allRecordings,
+ channels_displayed: that._getChannelsDisplayed(), // get all channels we would like to display
+ start_time: startTime,
+ channel_timeshift: that.vars.channelTimeshift,
+ window_length: window_length,
+ target_sampling_rate: that.options.targetSamplingRate,
+ use_high_precision_sampling: that.options.useHighPrecisionSampling,
+ };
+ that._requestData(options, (data, errorData) => {
+ //console.log("7, data:", data);
+ var windowAvailable = !errorData;
+ // console.log(errorData);
if (
- !that._isCurrentWindowSpecifiedTrainingWindow()
- && !that.options.experiment.running
+ windowAvailable &&
+ windowStartTime == that.vars.currentWindowStart
) {
- for (var i = 1; i <= that.options.numberOfForwardWindowsToPrefetch; ++i) {
- windowsToRequest.push(start_time + i * window_length);
- }
- for (var i = 1; i <= that.options.numberOfFastForwardWindowsToPrefetch; ++i) {
- windowsToRequest.push(start_time + i * that.options.windowJumpSizeFastForwardBackward * window_length);
- }
- for (var i = 1; i <= that.options.numberOfBackwardWindowsToPrefetch; ++i) {
- windowsToRequest.push(start_time - i * window_length);
- }
- for (var i = 1; i <= that.options.numberOfFastBackwardWindowsToPrefetch; ++i) {
- windowsToRequest.push(start_time - i * that.options.windowJumpSizeFastForwardBackward * window_length);
- }
- }
-
- windowsToRequest.forEach((windowStartTime) => {
- var options = {
- recording_name: recording_name,
- channels_displayed: that._getChannelsDisplayed(),
- start_time: windowStartTime,
- window_length: window_length,
- target_sampling_rate: that.options.targetSamplingRate,
- use_high_precision_sampling: that.options.useHighPrecisionSampling,
- };
- that._requestData(options, (data, errorData) => {
- var windowAvailable = !errorData;
- if (windowAvailable && windowStartTime == that.vars.currentWindowStart) {
- that._applyFrequencyFilters(data, (dataFiltered) => {
- that.vars.currentWindowData = dataFiltered;
- that._populateGraph(that.vars.currentWindowData);
- });
- }
- if (!that.options.experiment.running) {
- switch (windowStartTime) {
- case that.vars.currentWindowStart + window_length:
- if (that.options.visibleRegion.end === undefined) {
- that._setForwardEnabledStatus(windowAvailable);
- if (!windowAvailable) {
- that._lastWindowReached();
- }
- }
- break;
- case that.vars.currentWindowStart + window_length * that.options.windowJumpSizeFastForwardBackward:
- if (that.options.visibleRegion.end === undefined) {
- that._setFastForwardEnabledStatus(windowAvailable);
- }
- break;
- case that.vars.currentWindowStart - window_length:
- if (that.options.visibleRegion.start === undefined) {
- that._setBackwardEnabledStatus(windowAvailable);
- }
- break;
- case that.vars.currentWindowStart - window_length * that.options.windowJumpSizeFastForwardBackward:
- if (that.options.visibleRegion.start === undefined) {
- that._setFastBackwardEnabledStatus(windowAvailable);
- }
- break;
- }
- }
- });
- });
- },
-
- jumpToEpochWithStartTime: function(epochStartTimeInSeconds) {
- var that = this;
- if (isNaN(epochStartTimeInSeconds) || epochStartTimeInSeconds === undefined) {
- console.error('Cannot jump to epoch with start time', epochStartTimeInSeconds);
- return;
- }
- that._switchToWindow(that.options.recordingName, epochStartTimeInSeconds, that.options.windowSizeInSeconds);
- },
-
- getCurrentWindowStartReactive: function() {
- var that = this;
- return that.vars.currentWindowStartReactive.get();
- },
-
- _reloadCurrentWindow: function() {
- var that = this;
- that._switchToWindow(that.options.recordingName, that.vars.currentWindowStart, that.options.windowSizeInSeconds);
- },
-
- _reinitChart: function() {
- var that = this;
- if (that.vars.chart) {
- that.vars.chart.destroy();
+ that._applyFrequencyFilters(data, (dataFiltered) => {
+ that.vars.currentWindowData = dataFiltered;
+ that._populateGraph(that.vars.currentWindowData);
+ });
}
- that.vars.chart = undefined;
- that.vars.annotationsLoaded = false;
- that.vars.annotationsCache = {};
- that._reloadCurrentWindow();
- },
-
- _getProgressInPercent: function() {
- var that = this;
- if (!that._isVisibleRegionDefined()) return;
- var windowSize = that.options.windowSizeInSeconds;
- var start = windowSize * Math.ceil(that.options.visibleRegion.start / windowSize);
- var end = windowSize * Math.floor((that.options.visibleRegion.end - windowSize) / windowSize);
- if (!that._areTrainingWindowsSpecified()) {
- var progress = (that.vars.currentWindowStart - start + windowSize) / (end - start + 2 * windowSize);
- }
- else {
- var numberOfTrainingWindows = that._getNumberOfTrainingWindows();
- var numberOfWindowsInVisibleRegion = Math.floor((end - start) / windowSize);
- var numberOfWindowsTotal = numberOfWindowsInVisibleRegion + numberOfTrainingWindows;
- var currentWindowIndex = that.vars.currentTrainingWindowIndex;
- var progress = (currentWindowIndex + 1) / (numberOfWindowsTotal + 2);
- }
- var progressInPercent = Math.ceil(progress * 100);
- return progressInPercent;
- },
-
- _switchBackToLastActiveWindow: function() {
- var that = this;
- if (!that.vars.lastActiveWindowStart) {
- that.vars.lastActiveWindowStart = 0;
- } that._switchToWindow(that.options.recordingName, that.vars.lastActiveWindowStart, that.options.windowSizeInSeconds);
-
- },
-
- _requestData: function(options, callback) {
- var that = this;
- var identifierKey = that._getIdentifierKeyForDataRequest(options);
- var noDataError = 'No data available for window with options ' + JSON.stringify(options);
- if (options.start_time < 0) {
- that.vars.windowsCache[identifierKey] = false;
- }
- else if (options.start_time > that.vars.recordingMetadata.LengthInSeconds) {
- that.vars.windowsCache[identifierKey] = false;
- }
-
- if (that.vars.windowsCache[identifierKey] === false) {
- if (callback) {
- callback(null, noDataError);
- }
- return;
- }
-
- if (that.vars.windowsCache[identifierKey]) {
- if (that.vars.windowsCache[identifierKey].data && callback) {
- callback(that.vars.windowsCache[identifierKey].data);
- }
- return;
- }
-
- const numSecondsToPadBeforeAndAfter = 2;
-
- const optionsPadded = JSON.parse(JSON.stringify(options));
- optionsPadded.start_time -= numSecondsToPadBeforeAndAfter;
- optionsPadded.start_time = Math.max(0, optionsPadded.start_time);
- const numSecondsPaddedBefore = options.start_time - optionsPadded.start_time;
- optionsPadded.window_length = options.window_length + numSecondsPaddedBefore + numSecondsToPadBeforeAndAfter;
+ that._displayCrosshair(that.vars.crosshairPosition);
+ if (!that.options.experiment.running) {
+ if (that._isInNoTimelockMode()) {
+ that._setForwardEnabledStatus(false);
+ that._setFastForwardEnabledStatus(false);
+ that._setBackwardEnabledStatus(false);
+ that._setFastBackwardEnabledStatus(false);
+ } else {
+ // enable/disable the forward backward buttons according to the current position
+
- Meteor.call('get.edf.data', optionsPadded, (error, data) => {
- if (error) {
- console.log(error.message);
- callback(null, error.message);
- return;
- }
- if (!that._isDataValid(data)) {
- that.vars.windowsCache[identifierKey] = false;
- if (callback) {
- callback(null, noDataError);
- }
- }
- else {
- that.vars.windowsCache[identifierKey].data = that._transformData(data, numSecondsPaddedBefore, options.window_length, numSecondsToPadBeforeAndAfter);
- if (callback) {
- callback(that.vars.windowsCache[identifierKey].data);
+ switch (windowStartTime) {
+ case that.vars.currentWindowStart + window_length:
+ if (that.options.visibleRegion.end === undefined) {
+ //console.log('winAva:', windowAvailable);
+ that._setForwardEnabledStatus(windowAvailable);
+ if (!windowAvailable) {
+ that._lastWindowReached();
+ }
}
- }
- });
-
- that.vars.windowsCache[identifierKey] = {
- request: 'placeholder'
- };
- },
+
+ case that.vars.currentWindowStart +
+ window_length * that.options.windowJumpSizeFastForwardBackward:
+ if (that.options.visibleRegion.end === undefined) {
- _transformData: function(input, numSecondsPaddedBefore, numSecondsDataOfInterest, numSecondsPaddedAfter) {
- var that = this;
- var channels = [];
- var channelAudioRepresentations = {};
- var channelNumSamples = {};
- var samplingRate = input.sampling_rate;
- for (var name in input.channel_values) {
- var values = input.channel_values[name];
- var offlineCtx = new OfflineAudioContext(1, values.length, that.vars.audioContextSampleRate);
- var audioBuffer = offlineCtx.createBuffer(1, values.length, offlineCtx.sampleRate);
- var scaleFactorFrequency = offlineCtx.sampleRate / samplingRate;
- var scaleFactorAmplitude = values.map(Math.abs).reduce((a, b) => Math.max(a, b));
- var valuesScaled = values;
- if (scaleFactorAmplitude != 0) {
- valuesScaled = values.map(v => v / scaleFactorAmplitude);
- }
- audioBuffer.copyToChannel(valuesScaled, 0, 0);
- channelAudioRepresentations[name] = {
- buffer: audioBuffer,
- scaleFactors: {
- frequency: scaleFactorFrequency,
- amplitude: scaleFactorAmplitude,
- },
- };
- var numSamplesPaddedBefore = numSecondsPaddedBefore * samplingRate;
- var numSamplesDataOfInterest = Math.min(numSecondsDataOfInterest * samplingRate, values.length - numSamplesPaddedBefore);
- var numSamplesPaddedAfter = values.length - numSamplesPaddedBefore - numSamplesDataOfInterest;
- channelNumSamples[name] = {
- paddedBefore: numSamplesPaddedBefore,
- dataOfInterest: numSamplesDataOfInterest,
- paddedAfter: numSamplesPaddedAfter,
- };
- }
- for (var i = 0; i < input.channel_order.length; ++i) {
- var name = input.channel_order[i];
- var channel = {
- name: name,
- audio: channelAudioRepresentations[name],
- numSamples: channelNumSamples[name],
- }
- channel.valuesPadded = new Float32Array(channel.audio.buffer.length - channel.numSamples.paddedBefore);
- channels.push(channel);
- }
- var output = {
- channels: channels,
- sampling_rate: input.sampling_rate
- }
- return output;
- },
-
- _applyFrequencyFilters: function(data, callback) {
- var that = this;
- var numRemainingChannelsToFilter = data.channels.length;
- var maxDetectableFrequencyInHz = data.sampling_rate / 2;
- var frequencyFilters = that.vars.frequencyFilters || [];
- data.channels.forEach((channel, c) => {
- var staticFrequencyFilters = that._getStaticFrequencyFiltersForChannel(channel);
- var buffer = channel.audio.buffer;
- var offlineCtx = new OfflineAudioContext(1, buffer.length, that.vars.audioContextSampleRate);
- var valuesFiltered = data.channels[c].valuesFilteredHolder;
- var bufferSource = offlineCtx.createBufferSource();
- bufferSource.buffer = buffer;
- var currentNode = bufferSource;
- const allFrequencyFilters = staticFrequencyFilters.concat(frequencyFilters);
- allFrequencyFilters.forEach((frequencyFilter) => {
- var filterType = frequencyFilter.type;
- var frequencyInHz = parseFloat(frequencyFilter.selectedValue);
- if (isNaN(frequencyInHz) || frequencyInHz === undefined || frequencyInHz <= 0) {
- return;
+ that._setFastForwardEnabledStatus(windowAvailable);
}
- if (frequencyInHz > maxDetectableFrequencyInHz) {
- // console.log('Not applying ' + filterType + ' filter with frequency ' + frequencyInHz + 'Hz as it exceeds the maximum detectable frequency of ' + maxDetectableFrequencyInHz + 'Hz for this data, sampled at ' + data.sampling_rate + 'Hz.');
- return;
+ // break;
+ case that.vars.currentWindowStart - window_length:
+ if (that.options.visibleRegion.start === undefined) {
+ that._setBackwardEnabledStatus(windowAvailable);
}
- // console.log('Applying ' + filterType + ' filter with frequency ' + frequencyInHz + 'Hz.');
- var filterNode = offlineCtx.createBiquadFilter();
- filterNode.type = filterType;
- var scaleFactorFrequency = channel.audio.scaleFactors.frequency;
- filterNode.frequency.value = frequencyInHz * scaleFactorFrequency;
- // If filter results are not as expected,
- // double check settings for Q factor:
- // - https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
- // - https://electronics.stackexchange.com/questions/221887/does-q-factor-matter-for-low-pass-and-high-pass-filters
- // - https://stackoverflow.com/questions/33540440/bandpass-filter-which-frequency-and-q-value-to-represent-frequency-range
- // filterNode.Q.value = 1 (default)
- currentNode.connect(filterNode);
- currentNode = filterNode;
- });
- currentNode.connect(offlineCtx.destination);
- bufferSource.start();
- offlineCtx.startRendering().then((bufferFiltered) => {
- bufferFiltered.copyFromChannel(channel.valuesPadded, 0, channel.numSamples.paddedBefore);
- channel.values = channel.valuesPadded.subarray(0, channel.numSamples.dataOfInterest);
- var scaleFactorAmplitude = channel.audio.scaleFactors.amplitude;
- if (scaleFactorAmplitude != 0) {
- channel.values = channel.values.map(v => v * scaleFactorAmplitude);
- }
- --numRemainingChannelsToFilter;
- if (numRemainingChannelsToFilter <= 0) {
- callback(data);
+ // break;
+ case that.vars.currentWindowStart -
+ window_length * that.options.windowJumpSizeFastForwardBackward:
+ if (that.options.visibleRegion.start === undefined) {
+ that._setFastBackwardEnabledStatus(windowAvailable);
}
- }).catch((error) => {
- console.error('Rendering failed', error);
- });
- });
- },
+ // break;
+ }
+ }
+ }
+ });
+ });
+ },
+
+ jumpToEpochWithStartTime: function (epochStartTimeInSeconds) {
+ var that = this;
+ if (
+ isNaN(epochStartTimeInSeconds) ||
+ epochStartTimeInSeconds === undefined
+ ) {
+ console.error(
+ "Cannot jump to epoch with start time",
+ epochStartTimeInSeconds
+ );
+ return;
+ }
+ that._switchToWindow(
+ that.options.allRecordings,
+ epochStartTimeInSeconds,
+ that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ getCurrentWindowStartReactive: function () {
+ var that = this;
+ return that.vars.currentWindowStartReactive.get();
+ },
+
+ _reloadCurrentWindow: function () {
+ //console.log("_reloadCurrentWindow");
+ var that = this;
+ // reloads the current window by "switching" to it using the current window start time, the current x axis scale and the current recordings
+ that._switchToWindow(
+ that.options.allRecordings,
+ that.vars.currentWindowStart,
+ that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ _reinitChart: function () {
+ //function that reinitializes the charts
+ var that = this;
+ if (that.vars.chart) {
+ that.vars.chart.destroy(); //destroys the chart
+ }
- _getIdentifierObjectForDataRequest: function(options) {
- var options = options || {};
- var relevantOptions = [
- 'recording_name',
- 'start_time',
- 'window_length',
- 'channels_displayed',
- ];
- var identifierObject = {};
- for (var i = 0; i < relevantOptions.length; ++i) {
- identifierObject[relevantOptions[i]] = options[relevantOptions[i]];
- }
- return identifierObject;
- },
+ // deletes all annotations currently loaded and cached
+ that.vars.chart = undefined;
+ that.vars.annotationsLoaded = false;
+ that.vars.annotationsCache = {};
+
+ //console.log("_reinitChart");
+ that._reloadCurrentWindow();
+ },
+
+ _getProgressInPercent: function () {
+ var that = this;
+ if (!that._isVisibleRegionDefined()) return;
+ var windowSize = that.vars.xAxisScaleInSeconds;
+ var start =
+ windowSize * Math.ceil(that.options.visibleRegion.start / windowSize);
+ var end =
+ windowSize *
+ Math.floor((that.options.visibleRegion.end - windowSize) / windowSize);
+ if (!that._areTrainingWindowsSpecified()) {
+ var progress =
+ (that.vars.currentWindowStart - start + windowSize) /
+ (end - start + 2 * windowSize);
+ } else {
+ var numberOfTrainingWindows = that._getNumberOfTrainingWindows();
+ var numberOfWindowsInVisibleRegion = Math.floor(
+ (end - start) / windowSize
+ );
+ var numberOfWindowsTotal =
+ numberOfWindowsInVisibleRegion + numberOfTrainingWindows;
+ var currentWindowIndex = that.vars.currentTrainingWindowIndex;
+ var progress = (currentWindowIndex + 1) / (numberOfWindowsTotal + 2);
+ }
+ var progressInPercent = Math.ceil(progress * 100);
+ return progressInPercent;
+ },
+
+ _switchBackToLastActiveWindow: function () {
+ var that = this;
+ if (!that.vars.lastActiveWindowStart) {
+ that.vars.lastActiveWindowStart = 0;
+ }
+ that._switchToWindow(
+ that.options.allRecordings,
+ that.vars.lastActiveWindowStart,
+ that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ _requestData: function (options, callback) {
+ var that = this;
+ // console.log(that.vars.allRecordings);
+ // identifierKey includes:
+ // 'recordings'
+ // 'start_time'
+ // 'window_length'
+ // 'channels_displayed'
+ var identifierKey = that._getIdentifierKeyForDataRequest(options);
+ //console.log("identifierKey", identifierKey);
+ var noDataError =
+ "No data available for window with options " + JSON.stringify(options);
+
+ if (options.start_time < 0) {
+ that.vars.windowsCache[identifierKey] = false;
+ //console.log("options.start_time < 0");
+ } else if (options.start_time > that.vars.recordingLengthInSeconds) {
+ that.vars.windowsCache[identifierKey] = false;
+ //console.log("options.start_time > that.vars.recordingLengthInSeconds");
+ }
+ if (that.vars.windowsCache[identifierKey] === false) {
+ if (callback) {
+ //console.log("that.vars.windowsCache[identifierKey] === false");
- _getIdentifierKeyForDataRequest: function(options) {
- var that = this;
- var identifierKey = JSON.stringify(that._getIdentifierObjectForDataRequest(options));
- return identifierKey;
- },
+ callback(null, noDataError);
+ }
+ return;
+ }
- _isDataValid: function(data) {
- if (!data) return false;
- if (!data.sampling_rate) return false;
- if (!data.channel_order) return false;
- if (!data.channel_values) return false;
- for (let c = 0; c < data.channel_values.length; ++c) {
- if (data.channel_values[c].length == 0) {
- return false;
- }
- }
- return true;
- },
+ var reprint = that.vars.reprint;
+ //console.log("reprint", reprint);
+ if (reprint === 1 || that._isInNoTimelockMode()) {
+ that.vars.windowsCache = {};
+ } else if (
+ that.vars.windowsCache[identifierKey] &&
+ that.vars.windowsCache[identifierKey].data &&
+ callback
+ ) {
+ callback(that.vars.windowsCache[identifierKey].data);
+ return;
+ }
+ const numSecondsToPadBeforeAndAfter = 2;
+
+ const optionsPadded = JSON.parse(JSON.stringify(options));
+
+ optionsPadded.start_time -= numSecondsToPadBeforeAndAfter;
+
+ optionsPadded.start_time = Math.max(0, optionsPadded.start_time);
+
+ const numSecondsPaddedBefore =
+ options.start_time - optionsPadded.start_time;
+
+ optionsPadded.window_length =
+ options.window_length +
+ numSecondsPaddedBefore +
+ numSecondsToPadBeforeAndAfter;
+
+ optionsPadded.low_resolution_data =
+ that._isInNoTimelockMode() ||
+ optionsPadded.window_length >
+ 300 + numSecondsPaddedBefore + numSecondsToPadBeforeAndAfter;
+
+ Meteor.call("get.edf.data", optionsPadded, (error, data) => {
+ if (error) {
+ //console.log(error.message);
+ callback(null, error.message);
+ return;
+ }
+ //console.log("edf.data", data);
+ if (!that._isDataValid(data)) {
+ that.vars.windowsCache[identifierKey] = false;
+
+ if (callback) {
+ callback(null, noDataError);
+ }
+ } else {
+ that.vars.windowsCache[identifierKey] = {};
+ // transform the data before storing or displaying them
+ that.vars.windowsCache[identifierKey].data = that._transformData(
+ data,
+ numSecondsPaddedBefore,
+ options.window_length,
+ numSecondsToPadBeforeAndAfter
+ );
+ that.vars.reprint = 0;
+ if (callback) {
+ callback(that.vars.windowsCache[identifierKey].data);
+ }
+ }
+ });
+
+ that.vars.windowsCache[identifierKey] = {
+ request: "placeholder",
+ };
+ },
+
+ _transformData: function (
+ input,
+ numSecondsPaddedBefore,
+ numSecondsDataOfInterest,
+ numSecondsPaddedAfter
+ ) {
+ // //console.log("inside here");
+ var that = this;
+ var channels = [];
+ var options = that.vars.valueOptions;
+ if (options == null) {
+ options = 0;
+ }
- _populateGraph: function(data) {
- /* plot all of the points to the chart */
- var that = this;
- // if the chart object does not yet exist, because the user is loading the page for the first time
- // or refreshing the page, then it's necessary to initialize the plot area
- if (!that.vars.chart) {
- // if this is the first pageload, then we'll need to load the entire
- that._initGraph(data);
- // if the plot area has already been initialized, simply update the data displayed using AJAX calls
- }
- that._updateChannelDataInSeries(that.vars.chart.series, data);
- that.vars.chart.xAxis[0].setExtremes(that.vars.currentWindowStart, that.vars.currentWindowStart + that.options.windowSizeInSeconds, false, false);
- that.vars.chart.redraw(); // efficiently redraw the entire window in one go
- var chart = that.vars.chart;
- // use the chart start/end so that data and annotations can never
- // get out of synch
- that._refreshAnnotations();
- that._renderChannelSelection();
- that._updateBookmarkCurrentPageButton();
- that.vars.currentWindowStartReactive.set(that.vars.currentWindowStart);
- },
+ var channelAudioRepresentations = {};
+ var channelNumSamples = {};
+ var samplingRate = input.sampling_rate;
+ // console.log("samplingRate", samplingRate);
+ // console.log(that.options.targetSamplingRate);
+ // for each dataId in the channelvalues array
+ for (var dataId in input.channel_values) {
+ // console.log(that._getCurrentMontage());
+ //console.log(
+ // "==============================================================================================="
+ // );
+ for (var name in input.channel_values[dataId]) {
+ var values = input.channel_values[dataId][name];
+ // console.log("Channel Name:" + name);
+ // console.log(values);
+ ////console.log(that.vars.audioContextSampleRate);
+ var offlineCtx = new OfflineAudioContext(
+ 1,
+ values.length,
+ that.vars.audioContextSampleRate
+ );
+ var audioBuffer = offlineCtx.createBuffer(
+ 1,
+ values.length,
+ offlineCtx.sampleRate
+ );
+ var scaleFactorFrequency = offlineCtx.sampleRate / samplingRate;
+
+ //gets the max value in the values array
+ var scaleFactorAmplitude = Math.max(...values.map(Math.abs));
+
+ var maxIn = scaleFactorAmplitude;
+
+ var valuesLength = values.length;
+
+ // var y95 = 0;
+ // var y05 = 0;
+ // scaleFactorAmplitude = values
+ // .map(Math.abs)
+ // .reduce((a, b) => Math.max(a, b)); //that._findMeanPercentile(0.95,0.005,values, valuesLength);
+ // ////console.log(name);
+
+ // is the average of the values
+ var avg = values.reduce((a, b) => a + b) / valuesLength;
+ avg = Math.abs(avg);
+ ////console.log(avg);
+
+ // adds up the difference of the values from the average
+ var changeVal = values.reduce((a, b) => a + Math.abs(avg - b));
+
+ ////console.log(changeVal);
+
+ // //console.log(name);
+ // //console.log(scaleFactorAmplitude) ;
+
+ // scaleValueChange = Math.pow(scaleFactorAmplitude, 2);
+ var scaleValueChange = maxIn * scaleFactorAmplitude;
+
+ // checks if there are negative and positive values in the values array
+ const hasNegativeValues = values.some((v) => v <= 0);
+ const hasPositiveValues = values.some((v) => v >= 0);
+
+ // if the array has only negative or positive values, then we add/subtract the avg
+ if (!(hasNegativeValues && hasPositiveValues)) {
+ if (hasPositiveValues) {
+ values = values.map((v) => v - avg);
+ } else {
+ values = values.map((v) => v + avg);
+ }
+ }
+
+ if (scaleFactorAmplitude != 0) {
+ // //console.log(name);
+ // gets every value and divides it by the scaleFactorAmplitude, the max value in the values array
+ // console.log(name);
+ // console.log(scaleFactorAmplitude);
+
+ valuesScaled = values.map((v) => v / scaleFactorAmplitude);
+ // //console.log(valuesScaled);
+ }
+
+ // console.log(valuesScaled);
+ audioBuffer.copyToChannel(valuesScaled, 0, 0);
+
+ var scaleFault = 0;
+ if (options == 0) {
+ // if the amplitude is not scaled (default amplitude)
+ switch (name) {
+ case "F4-A1":
+ scaleFault = 1;
+ break;
+
+ case "C4-A1":
+ scaleFault = 1;
+ break;
+ case "O2-A1":
+ scaleFault = 1;
+ break;
+ case "LOC-A2":
+ scaleFault = 1;
+ break;
+ case "ROC-A1":
+ scaleFault = 1;
+ break;
+ case "Chin 1-Chin 2":
+ scaleFault = 500;
+ break;
+ // case "eeg-ch1":
+ // scaleFault = 0.05;
+ // break;
+ // case "eeg-ch2":
+ // scaleFault = 0.5;
+ // break;
+ // case "eeg-ch3":
+ // scaleFault = 0.05;
+ // break;
+ // case "eeg-ch4":
+ // scaleFault = 0.05;
+ // break;
+
+ case "ECG":
+ scaleFault = 100;
+ break;
+ case "Leg/L":
+ scaleFault = 50;
+ break;
+ case "Leg/R":
+ scaleFault = 50;
+ break;
+ case "Snore":
+ scaleFault = 600;
+ break;
+ case "Airflow":
+ scaleFault = 100;
+ break;
+ case "Nasal Pressure":
+ scaleFault = 100;
+ break;
+ case "Thor":
+ scaleFault = 500;
+ break;
+
+ case "Abdo":
+ scaleFault = 100;
+ break;
+ case "SpO2":
+ scaleFault = 1.5;
+ break;
+ case "Pleth":
+ scaleFault = 0.03;
+ break;
+ case "Accl Pitch":
+ scaleFault = 10;
+ break;
+ case "Accl Roll":
+ scaleFault = 10;
+ break;
+ case "Resp Effort":
+ scaleFault = 100;
+ break;
+ case "HR(bpm)":
+ scaleFault = 3.5;
+ break;
+ case "SpO2(%)":
+ scaleFault = 3.5;
+ break;
+ case "PI(%)":
+ scaleFault = 85;
+ break;
+ case "PAT(ms)":
+ scaleFault = 0.1;
+ break;
+ case "Chest Temp(A C)":
+ scaleFault = 10;
+ break;
+ case "Limb Temp(A C)":
+ scaleFault = 10;
+ break;
+ case "Temp":
+ scaleFault = 100;
+ break;
+ case "light":
+ scaleFault = 100;
+ break;
+ case "ENMO":
+ scaleFault = 100;
+ break;
+ case "z-angle":
+ scaleFault = 100;
+ break;
+ }
+ scaleFactorAmplitude = scaleFactorAmplitude * scaleFault;
+ sessionStorage.setItem(
+ dataId + name + "scaleFactorAmplitude",
+ scaleFault
+ );
+
+ ////console.log(name);
+ // //console.log(scaleFactorAmplitude);
+ } else if (options == 2) {
+ ////console.log(changeVal);
+ // //console.log(scaleFactorAmplitude);
+ while (
+ changeVal > 0 &&
+ scaleValueChange > 0 &&
+ changeVal < 10000 &&
+ scaleValueChange * 10 < 500
+ ) {
+ // //console.log(changeVal);
+ scaleFactorAmplitude = scaleFactorAmplitude * 3;
+ //scaleValueChange = scaleFactorAmplitude*maxIn;
+ // //console.log(scaleFactorAmplitude*maxIn);
+ changeVal = changeVal * 7;
+ }
+ // //console.log(name);
+ // //console.log(scaleFactorAmplitude);
+ sessionStorage.setItem(
+ dataId + name + "scaleFactorAmplitude",
+ scaleFactorAmplitude
+ );
+ } else if (options == 1) {
+ //if the amplitude has to be scaled
+ //requiredName = "Thor"//sessionStorage.getItem("requiredName");
+ let channelOnChange = that.vars.channelAmplitudeOnChange;
+ // //console.log(requiredName);
+ var scaleFault = sessionStorage.getItem(
+ dataId + name + "scaleFactorAmplitude"
+ );
+ var oncecheck = that.vars.increaseOnce;
+ if (
+ name === channelOnChange.name &&
+ dataId === channelOnChange.dataId &&
+ oncecheck == 1
+ ) {
+ scaleFault = scaleFault * 5;
+ that.vars.increaseOnce = 0;
+ }
+
+ sessionStorage.setItem(
+ dataId + name + "scaleFactorAmplitude",
+ scaleFault
+ );
+ //sessionStorage.setItem(("requiredName"),"");
+ scaleFactorAmplitude = scaleFactorAmplitude * scaleFault;
+ // //console.log(sessionStorage.setItem((name+"scaleFactorAmplitude"), scaleFault));
+ // //console.log(scaleFault);
+ ////console.log(scaleFactorAmplitude);
+ } else if (options == -1) {
+ //requiredName = "Thor"//sessionStorage.getItem("requiredName");
+ var scaleFault = sessionStorage.getItem(
+ dataId + name + "scaleFactorAmplitude"
+ );
+ let channelOnChange = that.vars.channelAmplitudeOnChange;
+ var oncecheck = that.vars.increaseOnce;
+ if (
+ name === channelOnChange.name &&
+ dataId === channelOnChange.dataId &&
+ oncecheck == 1
+ ) {
+ scaleFault = scaleFault / 5;
+ that.vars.increaseOnce = 0;
+ }
+ // //console.log(sessionStorage.setItem((name+"scaleFactorAmplitude"), scaleFault));
+ ////console.log(scaleFault);
+ sessionStorage.setItem(
+ dataId + name + "scaleFactorAmplitude",
+ scaleFault
+ );
+ scaleFactorAmplitude = scaleFactorAmplitude * scaleFault;
+ }
+ /*
+ if(scaleValueChange > 500 ){
+ scaleValueChange = 500/maxIn;
+ scaleFactorAmplitude = scaleValueChange;
+ }
+ */
+ if (!channelAudioRepresentations[dataId])
+ channelAudioRepresentations[dataId] = {};
+ channelAudioRepresentations[dataId][name] = {
+ buffer: audioBuffer,
+ scaleFactors: {
+ frequency: scaleFactorFrequency,
+ amplitude: scaleFactorAmplitude,
+ },
+ };
+ var numSamplesPaddedBefore = numSecondsPaddedBefore * samplingRate;
+ var numSamplesDataOfInterest = Math.min(
+ numSecondsDataOfInterest * samplingRate,
+ values.length - numSamplesPaddedBefore
+ );
- _updateChannelDataInSeries: function(series, data) {
- var that = this;
- var channels = data.channels;
- var xValues = Array.from(data.channels[0].values.map(function(value, v) {
- return that.vars.currentWindowStart + v / data.sampling_rate;
- }));
- var recordingEndInSecondsSnapped = that._getRecordingEndInSecondsSnapped();
- return channels.map(function (channel, c) {
- var flipFactor = that._getFlipFactorForChannel(channel);
- var gain = that._getGainForChannelIndex(c);
- if (gain === undefined) {
- gain = 1.0;
- }
- var flipFactorAndGain = flipFactor * gain;
- var offsetPreScale = that._getOffsetForChannelPreScale(channel);
- var offsetPostScale = that._getOffsetForChannelIndexPostScale(c);
- samplesScaledAndOffset = channel.values.map(function(value, v) {
- return (value + offsetPreScale) * flipFactorAndGain + offsetPostScale;
- });
- var seriesData = xValues.map(function(x, i) {
- return [x, samplesScaledAndOffset[i]];
- });
- seriesData.unshift([-that.options.windowSizeInSeconds, offsetPostScale]);
- seriesData.push([recordingEndInSecondsSnapped, offsetPostScale]);
- series[c].setData(seriesData, false, false, false);
- });
- },
+ var numSamplesPaddedAfter =
+ values.length - numSamplesPaddedBefore - numSamplesDataOfInterest;
+ if (!channelNumSamples[dataId]) channelNumSamples[dataId] = {};
+ channelNumSamples[dataId][name] = {
+ paddedBefore: numSamplesPaddedBefore,
+ dataOfInterest: numSamplesDataOfInterest,
+ paddedAfter: numSamplesPaddedAfter,
+ };
+ }
+ }
- _initSeries: function(data) {
- var that = this;
- var samplingRate = data.sampling_rate;
- var channels = data.channels;
- var recordingEndInSecondsSnapped = that._getRecordingEndInSecondsSnapped();
- return channels.map(function (channel, c) {
- var offset = that._getOffsetForChannelIndexPostScale(c);
- return {
- name: channel.name,
- data: [[0, offset], [recordingEndInSecondsSnapped, offset]],
- };
+ for (var i = 0; i < input.channel_order.length; ++i) {
+ var name = input.channel_order[i].name;
+ let dataId = input.channel_order[i].dataId;
+ if (channelNumSamples[dataId][name]) {
+ var channel = {
+ name: name,
+ dataId: dataId,
+ audio: channelAudioRepresentations[dataId][name],
+ numSamples: channelNumSamples[dataId][name],
+ };
+ let arrayLength = Math.max(
+ channel.audio.buffer.length - channel.numSamples.paddedBefore,
+ 1
+ );
+ channel.valuesPadded = new Float32Array(arrayLength);
+ channels.push(channel);
+ }
+ }
+ var output = {
+ channels: channels,
+ sampling_rate: input.sampling_rate,
+ };
+ return output;
+ },
+
+ _findMeanPercentile: function (top, bottom, values, thisCounting) {
+ var sortValues = values;
+ sortValues.sort();
+ var upside = top * thisCounting;
+ var downside = bottom * thisCounting;
+
+ var topValue = sortValues[Math.ceil(upside)];
+ var bottomValue = sortValues[Math.floor(downside)];
+
+ return (topValue + bottomValue) / 2, topValue, bottomValue;
+ },
+
+ _applyFrequencyFilters: function (data, callback) {
+ var that = this;
+ var numRemainingChannelsToFilter = data.channels.length;
+ var maxDetectableFrequencyInHz = data.sampling_rate / 2;
+ var frequencyFilters = that.vars.frequencyFilters || [];
+ data.channels.forEach((channel, c) => {
+ var staticFrequencyFilters =
+ that._getStaticFrequencyFiltersForChannel(channel);
+ var buffer = channel.audio.buffer;
+ var offlineCtx = new OfflineAudioContext(
+ 1,
+ buffer.length,
+ that.vars.audioContextSampleRate
+ );
+ var valuesFiltered = data.channels[c].valuesFilteredHolder;
+ var bufferSource = offlineCtx.createBufferSource();
+ bufferSource.buffer = buffer;
+ var currentNode = bufferSource;
+ const allFrequencyFilters =
+ staticFrequencyFilters.concat(frequencyFilters);
+ allFrequencyFilters.forEach((frequencyFilter) => {
+ var filterType = frequencyFilter.type;
+ var frequencyInHz = parseFloat(frequencyFilter.selectedValue);
+ if (
+ isNaN(frequencyInHz) ||
+ frequencyInHz === undefined ||
+ frequencyInHz <= 0
+ ) {
+ return;
+ }
+ if (frequencyInHz > maxDetectableFrequencyInHz) {
+ // //console.log('Not applying ' + filterType + ' filter with frequency ' + frequencyInHz + 'Hz as it exceeds the maximum detectable frequency of ' + maxDetectableFrequencyInHz + 'Hz for this data, sampled at ' + data.sampling_rate + 'Hz.');
+ return;
+ }
+ // //console.log('Applying ' + filterType + ' filter with frequency ' + frequencyInHz + 'Hz.');
+ var filterNode = offlineCtx.createBiquadFilter();
+ filterNode.type = filterType;
+ var scaleFactorFrequency = channel.audio.scaleFactors.frequency;
+ filterNode.frequency.value = frequencyInHz * scaleFactorFrequency;
+ // If filter results are not as expected,
+ // double check settings for Q factor:
+ // - https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
+ // - https://electronics.stackexchange.com/questions/221887/does-q-factor-matter-for-low-pass-and-high-pass-filters
+ // - https://stackoverflow.com/questions/33540440/bandpass-filter-which-frequency-and-q-value-to-represent-frequency-range
+ // filterNode.Q.value = 1 (default)
+ currentNode.connect(filterNode);
+ currentNode = filterNode;
+ });
+ currentNode.connect(offlineCtx.destination);
+ bufferSource.start();
+ offlineCtx
+ .startRendering()
+ .then((bufferFiltered) => {
+ bufferFiltered.copyFromChannel(
+ channel.valuesPadded,
+ 0,
+ channel.numSamples.paddedBefore
+ );
+ channel.values = channel.valuesPadded.subarray(
+ 0,
+ channel.numSamples.dataOfInterest
+ );
+ var scaleFactorAmplitude = channel.audio.scaleFactors.amplitude;
+ if (scaleFactorAmplitude != 0) {
+ channel.values = channel.values.map(
+ (v) => v * scaleFactorAmplitude
+ );
+ // //console.log(buffer);
+ // //console.log(channel.values);
+ }
+ --numRemainingChannelsToFilter;
+ if (numRemainingChannelsToFilter <= 0) {
+ callback(data);
+ }
+ })
+ .catch((error) => {
+ console.error("Rendering failed", error);
});
- },
+ });
+ },
+
+ _getIdentifierObjectForDataRequest: function (options) {
+ var options = options || {};
+ var relevantOptions = [
+ "recordings",
+ "start_time",
+ "window_length",
+ "channels_displayed",
+ ];
+ var identifierObject = {};
+ for (var i = 0; i < relevantOptions.length; ++i) {
+ identifierObject[relevantOptions[i]] = options[relevantOptions[i]];
+ }
+ return identifierObject;
+ },
+
+ _getIdentifierKeyForDataRequest: function (options) {
+ var that = this;
+ var identifierKey = JSON.stringify(
+ that._getIdentifierObjectForDataRequest(options)
+ );
+ return identifierKey;
+ },
+
+ _isDataValid: function (data) {
+ if (!data) return false;
+ if (!data.sampling_rate) return false;
+ if (!data.channel_order) return false;
+ if (!data.channel_values) return false;
+ for (let dataId in data.channel_values) {
+ if (Object.keys(data.channel_values[dataId]).length == 0) return false;
+ }
+ return true;
+ },
+
+ _populateGraph: function (data) {
+ /* plot all of the points to the chart */
+ var that = this;
+
+ // if the chart object does not yet exist, because the user is loading the page for the first time
+ // or refreshing the page, then it's necessary to initialize the plot area
+ if (!that.vars.chart) {
+ // if this is the first pageload, then we'll need to load the entire
+ console.time("_initGraph");
+ that._initGraph(data);
+ //console.log("[[time end]]");
+ console.timeEnd("_initGraph");
+ // if the plot area has already been initialized, simply update the data displayed using AJAX calls
+
+ that._updateChannelDataInSeries(that.vars.chart.series, data);
+
+ // console.log("here we scale all channels to screen");
+ that._scaleAllToScreen();
+ that.vars.chart.redraw();
+
+
+ that._addChangePointLabelFixed();
+ // see http://jsfiddle.net/ajxyuax2/1/
+ }
- _getRecordingEndInSecondsSnapped: function() {
- var that = this;
- return (Math.ceil(that.vars.recordingMetadata.LengthInSeconds / that.options.windowSizeInSeconds) + 1) * that.options.windowSizeInSeconds;
- },
+ // updates the data that will be displayed in the chart
+ // by storing the new data in this.vars.chart.series
+ that._updateChannelDataInSeries(that.vars.chart.series, data);
+
+ // sets the min and max values for the chart
+ that.vars.chart.xAxis[0].setExtremes(
+ that.vars.currentWindowStart,
+ that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds,
+ false,
+ false
+ );
+
+ that.vars.recordScalingFactors = false;
+ that.vars.recordPolarity = false;
+ that.vars.recordTranslation = false;
+
+ // checks if the object is empty
+ if (!that._objectIsEmpty(that.vars.scalingFactors)) {
+ for (const index in that.vars.scalingFactors) {
+ that._customAmplitude(
+ index,
+ 100 * (that.vars.scalingFactors[index] - 1)
+ );
+ // console.log("scaling after page change");
+ // console.log(that.vars.chart.series[index].yData);
+ }
- _getLatestPossibleWindowStartInSeconds: function() {
- var that = this;
- return Math.floor(that.vars.recordingMetadata.LengthInSeconds / that.options.windowSizeInSeconds) * that.options.windowSizeInSeconds;
- },
+ }
- _getClassificationSummaryElement: function() {
- var that = this;
- return $(that.element).parents('.annotator-edf').find('.classification-summary');
- },
+ if (!that._objectIsEmpty(that.vars.translation)) {
+ for (const index in that.vars.translation) {
+ that._customTranslation(index, that.vars.translation[index]);
+ }
+ }
+
+ if (!that._objectIsEmpty(that.vars.polarity)) {
+ for (const index in that.vars.polarity) {
+ that._reversePolarity(index);
+ }
+ }
- _initGraph: function(data) {
- /* This method is called only when the page is first loaded, it sets up the plot area, the
+ that.vars.recordPolarity = true;
+ that.vars.recordScalingFactors = true;
+ that.vars.recordTranslation = true;
+
+ that.vars.chart.redraw(); // efficiently redraw the entire window in one go
+
+ // use the chart start/end so that data and annotations can never
+ // get out of synch
+ that._refreshAnnotations();
+ that._renderChannelSelection();
+ that._updateBookmarkCurrentPageButton();
+ that.vars.currentWindowStartReactive.set(that.vars.currentWindowStart);
+
+ that._updateChangePointLabelFixed();
+ },
+
+ //checks if an object is empty
+ _objectIsEmpty: function (obj) {
+ return JSON.stringify(obj) === "{}";
+ },
+
+ _updateChannelDataInSeries: function (series, data) {
+ var that = this;
+ var channels = data.channels; // gets the channels from the data object
+
+ //gets the xValues for the graph using from the data object i.e the time values
+ var xValues = Array.from(
+ data.channels[0].values.map(function (value, index) {
+ return that.vars.currentWindowStart + index / data.sampling_rate;
+ })
+ );
+
+ // gets the recording end in seconds snapped to the nearest second
+ var recordingEndInSecondsSnapped = that._getRecordingEndInSecondsSnapped();
+
+ return channels.map(function (channel, c) {
+ // for each channel, we get the channel name (channel)
+ // and the channel index (c)
+
+ // using them, we get the flipfactor and gain
+ var flipFactor = that._getFlipFactorForChannel(channel);
+ var gain = that._getGainForChannelIndex(c);
+
+ if (gain === undefined) {
+ gain = 1.0;
+ }
+
+ var flipFactorAndGain = flipFactor * gain;
+
+ // gets some additional information needed to graph using channel and c
+ var offsetPreScale = that._getOffsetForChannelPreScale(channel);
+ var offsetPostScale = that._getOffsetForChannelIndexPostScale(c);
+
+ // gets the values
+ samplesScaledAndOffset = channel.values.map(function (value, v) {
+ return (value + offsetPreScale) * flipFactorAndGain + offsetPostScale;
+ });
+
+ // creates an array that stores all the data
+ var seriesData = xValues.map(function (x, i) {
+ return [x, samplesScaledAndOffset[i]];
+ });
+
+ // adds the offset needed to the start of the graph
+ seriesData.unshift([-that.vars.xAxisScaleInSeconds, offsetPostScale]);
+
+ // adds the offset needed to the end of the graphID
+ seriesData.push([recordingEndInSecondsSnapped, offsetPostScale]);
+
+ // stores in the series that we input into the funciton, at index c
+ series[c].setData(seriesData, false, false, false);
+ });
+ },
+
+ _initSeries: function (data) {
+ var that = this;
+ var samplingRate = data.sampling_rate;
+ var channels = data.channels;
+ var recordingEndInSecondsSnapped = that._getRecordingEndInSecondsSnapped();
+ return channels.map(function (channel, c) {
+ var offset = that._getOffsetForChannelIndexPostScale(c);
+ return {
+ name: channel.name,
+ custom: {
+ dataId: channel.dataId,
+ },
+ data: [
+ [0, offset],
+ [recordingEndInSecondsSnapped, offset],
+ ],
+ };
+ });
+ },
+
+ _getRecordingEndInSecondsSnapped: function () {
+ var that = this;
+ return (
+ (Math.ceil(
+ that.vars.recordingLengthInSeconds / that.vars.xAxisScaleInSeconds
+ ) +
+ 1) *
+ that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ _getLatestPossibleWindowStartInSeconds: function () {
+ var that = this;
+ return (
+ Math.floor(
+ that.vars.recordingLengthInSeconds / that.vars.xAxisScaleInSeconds
+ ) * that.vars.xAxisScaleInSeconds
+ );
+ },
+
+ _getClassificationSummaryElement: function () {
+ var that = this;
+ return $(that.element)
+ .parents(".annotator-edf")
+ .find(".classification-summary");
+ },
+
+ _initGraph: function (data) {
+ /* This method is called only when the page is first loaded, it sets up the plot area, the
axis, channel name labels, time formatting and everything else displayed on the plot
subsequent changes to this plot to scroll through the signal use the much computationally expensive
series update and axis update methods.
*/
- var that = this;
- var channels = data.channels;
-
- that.vars.graphID = 'time-series-graph-' + that._getUUID();
- var graph = $(that.element).find('.graph');
- graph.children().remove();
- graph.append('');
-
- var classificationSummaryContainer = that._getClassificationSummaryElement();
- if (classificationSummaryContainer.length == 0) {
- var classificationSummaryHeight = 0;
- } else {
- var classificationSummaryHeight = classificationSummaryContainer.height() + parseInt(classificationSummaryContainer.css('margin-top')) + parseInt(classificationSummaryContainer.css('margin-bottom'));
- }
- var graphHeight = $(that.element).height() - (parseInt(graph.css('padding-top')) + parseInt(graph.css('padding-bottom')) + parseInt(graph.css('margin-top')) + parseInt(graph.css('margin-bottom'))) - classificationSummaryHeight;
- var graphContainerOtherChildren = $(that.element).find('.graph_container > *').not(graph);
- graphContainerOtherChildren.each(function() {
- var child = $(this);
- graphHeight -= (child.height() + parseInt(child.css('margin-top')) + parseInt(child.css('margin-bottom')));
- });
-
- bookmarkData = [];
- const bookmarkedPages = that.options.context.preferences.annotatorConfig.bookmarkedPages;
- for (pageKey in bookmarkedPages) {
- if (bookmarkedPages[pageKey] === true) {
- bookmarkData.push(parseInt(pageKey));
- }
- }
- bookmarkData.sort((a, b) => a - b);
- bookmarkData = bookmarkData.map((pageKey) => {
- return [pageKey + that.options.windowSizeInSeconds / 2, 1];
- });
-
- that.vars.chart = new Highcharts.Chart({
- boost: {
- enabled: true,
- seriesThreshold: 1,
- },
- chart: {
- animation: false,
- renderTo: that.vars.graphID,
- width: that.options.graph.width,
- height: graphHeight,
- marginTop: that.options.graph.marginTop,
- marginBottom: that.options.graph.marginBottom,
- marginLeft: that.options.graph.marginLeft,
- marginRight: that.options.graph.marginRight,
- backgroundColor: that.options.graph.backgroundColor,
- events: {
- load: function(event) {
- that._setupLabelHighlighting();
- },
- redraw: function(event) {
- that._setupLabelHighlighting();
- that._setupYAxisLinesAndLabels();
- }
- },
+ //console.log("!!!!!!init graph");
+ var that = this;
+ var channels = data.channels;
+
+ that.vars.graphID = "time-series-graph-" + that._getUUID();
+ var graph = $(".graph");
+ graph.children().remove();
+ graph.append(
+ ''
+ );
+
+ var classificationSummaryContainer =
+ that._getClassificationSummaryElement();
+ if (classificationSummaryContainer.length == 0) {
+ var classificationSummaryHeight = 0;
+ } else {
+ var classificationSummaryHeight =
+ classificationSummaryContainer.height() +
+ parseInt(classificationSummaryContainer.css("margin-top")) +
+ parseInt(classificationSummaryContainer.css("margin-bottom"));
+ }
+ var graphHeight =
+ $(that.element).height() -
+ (parseInt(graph.css("padding-top")) +
+ parseInt(graph.css("padding-bottom")) +
+ parseInt(graph.css("margin-top")) +
+ parseInt(graph.css("margin-bottom"))) -
+ classificationSummaryHeight;
+ var graphContainerOtherChildren = $(that.element)
+ .find(".graph_container > *")
+ .not(graph);
+ graphContainerOtherChildren.each(function () {
+ var child = $(this);
+ graphHeight -=
+ child.height() +
+ parseInt(child.css("margin-top")) +
+ parseInt(child.css("margin-bottom"));
+ });
+
+ bookmarkData = [];
+ const bookmarkedPages =
+ that.options.context.preferences.annotatorConfig.bookmarkedPages;
+ for (pageKey in bookmarkedPages) {
+ if (bookmarkedPages[pageKey] === true) {
+ bookmarkData.push(parseInt(pageKey));
+ }
+ }
+ bookmarkData.sort((a, b) => a - b);
+ bookmarkData = bookmarkData.map((pageKey) => {
+ return [pageKey + that.vars.xAxisScaleInSeconds / 2, 1];
+ });
+
+ (myFunction = function () {
+ var popup = document.getElementById("myPopup");
+ popup.classList.toggle("show");
+ }),
+ (that.vars.chart = new Highcharts.chart({
+ boost: {
+ // speed up
+ enabled: true,
+ seriesThreshold: 1,
+ },
+ chart: {
+ animation: false,
+ renderTo: that.vars.graphID,
+ width: that.options.graph.width,
+ height: graphHeight,
+ marginTop: that.options.graph.marginTop,
+ marginBottom: that.options.graph.marginBottom,
+ marginLeft: that.options.graph.marginLeft,
+ marginRight: that.options.graph.marginRight,
+ backgroundColor: that.options.graph.backgroundColor,
+ events: {
+ load: function (event) {
+ that._setupLabelHighlighting();
},
- credits: {
- enabled: false
+ redraw: function (event) {
+ that._setupLabelHighlighting();
+ that._setupYAxisLinesAndLabels();
},
- title: {
- text: ''
+ },
+ //TODO: change how chart zooms, does not work well with annotations
+ // zoomType: "xy",
+
+ resetZoomButton: {
+ position: {
+ align: "left",
+ verticalAlign: "bottom",
+ x: -87.5,
+ y: 25,
},
- tooltip: {
- enabled: false
+ relativeTo: "plotBox",
+ },
+ },
+ credits: {
+ enabled: false,
+ },
+ title: {
+ text: that.options.recordingName,
+ },
+ tooltip: {
+ enabled: true,
+ formatter: function () {
+ var x = this.x;
+ try {
+ var annotation = that.vars.universalChangePointAnnotationsCache[
+ that._getUniversalAnnotationIndexByXVal(x)
+ ];
+ var label;
+ if (annotation !== undefined) {
+ label = annotation.metadata.annotationLabel;
+ }
+ // console.log(label);
+
+ return "Time Stamp: " + "" + this.x + "" + " s" + ' ' +
+ "Previous Universal Change Point:" + " " +
+ "" + label + "";
+ } catch {
+ return "Error";
+ }
+ },
+ },
+ annotations: null,
+ plotOptions: {
+ series: {
+ animation: false,
+ turboThreshold: 0,
+ boostThreshold: 1,
+ type: "line",
+ color: "black",
+ lineWidth: that.options.graph.lineWidth,
+ enableMouseTracking: that.options.graph.enableMouseTracking,
+ stickyTracking: true,
+ events: {
+ // mouseOver: function (e) {
+ // // that._selectChannel(e.target.index);
+ // },
+ // mouseOut: function (e) {
+ // // that._unselectChannels();
+ // },
},
- plotOptions: {
- series: {
- animation: false,
- turboThreshold: 0,
- type: 'line',
- color: 'black',
- lineWidth: that.options.graph.lineWidth,
- enableMouseTracking: that.options.graph.enableMouseTracking,
- stickyTracking: true,
- events: {
- mouseOver: function(e) {
- that._selectChannel(e.target.index);
- },
- mouseOut: function(e) {
- that._unselectChannels();
- },
- }
- },
- line: {
- marker: {
- enabled: false,
- }
- },
- polygon: {
+ point: {
+ events: {
+ click: function (e) {
+ var crosshairPosition = {
+ plotX: this.plotX,
+ plotY: this.plotY,
+ timeInSeconds: e.point.x,
+ channelName: e.point.series.name,
+ channelIndex: e.point.series.index,
+ dataId: e.point.series.options.custom.dataId,
+ };
+
+ that.vars.annotationCrosshairCurrPosition = ({...crosshairPosition});
+ that._setCrosshair(crosshairPosition);
},
- },
- navigator: {
- enabled: true,
- adaptToUpdatedData: true,
- height: 20,
- margin: 25,
- handles: {
- enabled: false,
- },
- xAxis: {
- labels: {
- formatter: that._formatXAxisLabel,
- style: {
- textOverflow: 'none',
- }
- },
+ // workaround to trigger click event handler on point under boost mode
+ // https://github.com/highcharts/highcharts/issues/14067
+ mouseOver: function () {
+ if (this.series.halo) {
+ this.series.halo
+ .attr({
+ class: "highcharts-tracker",
+ })
+ .toFront();
+ }
},
- series: {
- type: 'area',
- color: '#26a69a',
- fillOpacity: 1.0,
- lineWidth: 1,
- marker: {
- enabled: false
- },
- data: bookmarkData,
- }
+ },
},
- xAxis: {
- gridLineWidth: 1,
- labels: {
- enabled: that.options.showTimeLabels,
- crop: false,
- style: {
- textOverflow: 'none',
- },
- step: 5,
- formatter: that._formatXAxisLabel,
- },
- tickInterval: 1,
- minorTickInterval: 0.5,
- min: that.vars.currentWindowStart,
- max: that.vars.currentWindowStart + that.options.windowSizeInSeconds,
- unit: [
- ['second', 1]
- ],
- events: {
- setExtremes: function (e) {
- if (e.trigger == 'navigator') {
- var startTimeSnapped = Math.round(e.min / that.options.windowSizeInSeconds) * that.options.windowSizeInSeconds;
- startTimeSnapped = Math.max(0, startTimeSnapped);
- startTimeSnapped = Math.min(that._getLatestPossibleWindowStartInSeconds(), startTimeSnapped);
- that._switchToWindow(that.options.recordingName, startTimeSnapped, that.options.windowSizeInSeconds);
- return false;
- }
- }
- }
+ },
+ line: {
+ marker: {
+ enabled: false,
},
- yAxis: {
- tickInterval: 100,
- minorTickInterval: 50,
- min: -0.75 * that.options.graph.channelSpacing * 0.75,
- max: (channels.length - 0.25) * that.options.graph.channelSpacing,
- gridLineWidth: 0,
- minorGridLineWidth: 0,
- labels: {
- enabled: that.options.showChannelNames,
- step: 1,
- useHTML: true,
- formatter: function() {
- if (
- this.value < 0
- || this.value > channels.length * that.options.graph.channelSpacing
- || this.value % that.options.graph.channelSpacing !== 0
- ) {
- return null;
- };
- var index = that._getChannelIndexFromY(this.value);
- var channel = channels[index];
- var html = '' + channel.name + "";
- return html;
- },
- },
- title: {
- text: null
- }
+ },
+ polygon: {},
+ },
+ navigator: {
+ enabled: true,
+ adaptToUpdatedData: true,
+ height: 20,
+ margin: 25,
+ handles: {
+ enabled: false,
+ },
+ xAxis: {
+ labels: {
+ formatter: that._formatXAxisLabel,
+ style: {
+ textOverflow: "none",
+ },
+ },
+ },
+ series: {
+ type: "area",
+ color: "#26a69a",
+ fillOpacity: 1.0,
+ lineWidth: 1,
+ marker: {
+ enabled: false,
+ },
+ data: bookmarkData,
+ },
+ },
+ xAxis: {
+ gridLineWidth: 1,
+ labels: {
+ enabled: that.options.showTimeLabels,
+ crop: false,
+ style: {
+ textOverflow: "none",
},
- legend: {
- enabled: false
+ step: that.vars.xAxisScaleInSeconds / 6,
+ formatter: that._formatXAxisLabel,
+ },
+ tickInterval: 1,
+ minorTickInterval: 0.5,
+ min: that.vars.currentWindowStart,
+ max: that.vars.currentWindowStart + that.vars.xAxisScaleInSeconds,
+ unit: [["second", 1]],
+ events: {
+ setExtremes: function (e) {
+ if (e.trigger == "navigator") {
+ var startTimeSnapped =
+ Math.round(e.min / that.vars.xAxisScaleInSeconds) *
+ that.vars.xAxisScaleInSeconds;
+ startTimeSnapped = Math.max(0, startTimeSnapped);
+ startTimeSnapped = Math.min(
+ that._getLatestPossibleWindowStartInSeconds(),
+ startTimeSnapped
+ );
+ that._switchToWindow(
+ that.options.allRecordings,
+ startTimeSnapped,
+ that.vars.xAxisScaleInSeconds
+ );
+ return false;
+ }
},
- series: that._initSeries(data),
- annotationsOptions: {
- enabledButtons: false,
+ },
+ },
+ yAxis: {
+ tickInterval: 100,
+ minorTickInterval: 50,
+ min: -0.75 * that.options.graph.channelSpacing * 0.75,
+ max: (channels.length - 0.25) * that.options.graph.channelSpacing,
+ gridLineWidth: 0,
+ minorGridLineWidth: 0,
+ labels: {
+ enabled: that.options.showChannelNames,
+ step: 1,
+ useHTML: true,
+ formatter: function () {
+ if (
+ this.value < 0 ||
+ this.value >
+ channels.length * that.options.graph.channelSpacing ||
+ this.value % that.options.graph.channelSpacing !== 0
+ ) {
+ return null;
+ }
+
+ var index = that._getChannelIndexFromY(this.value);
+ that.vars.allChannels = channels;
+ var channel = channels[index];
+
+ //that.vars.popUpActive = 1;
+
+ var html =
+ '