tupali/librerias/gantt/code/es-modules/modules/sonification/pointSonify.js
2020-05-23 15:45:54 -05:00

322 lines
13 KiB
JavaScript

/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Code for sonifying single points.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../parts/Globals.js';
import U from '../../parts/Utilities.js';
var error = U.error, merge = U.merge, pick = U.pick;
/**
* Define the parameter mapping for an instrument.
*
* @requires module:modules/sonification
*
* @interface Highcharts.PointInstrumentMappingObject
*/ /**
* Define the volume of the instrument. This can be a string with a data
* property name, e.g. `'y'`, in which case this data property is used to define
* the volume relative to the `y`-values of the other points. A higher `y` value
* would then result in a higher volume. This option can also be a fixed number
* or a function. If it is a function, this function is called in regular
* intervals while the note is playing. It receives three arguments: The point,
* the dataExtremes, and the current relative time - where 0 is the beginning of
* the note and 1 is the end. The function should return the volume of the note
* as a number between 0 and 1.
* @name Highcharts.PointInstrumentMappingObject#volume
* @type {string|number|Function}
*/ /**
* Define the duration of the notes for this instrument. This can be a string
* with a data property name, e.g. `'y'`, in which case this data property is
* used to define the duration relative to the `y`-values of the other points. A
* higher `y` value would then result in a longer duration. This option can also
* be a fixed number or a function. If it is a function, this function is called
* once before the note starts playing, and should return the duration in
* milliseconds. It receives two arguments: The point, and the dataExtremes.
* @name Highcharts.PointInstrumentMappingObject#duration
* @type {string|number|Function}
*/ /**
* Define the panning of the instrument. This can be a string with a data
* property name, e.g. `'x'`, in which case this data property is used to define
* the panning relative to the `x`-values of the other points. A higher `x`
* value would then result in a higher panning value (panned further to the
* right). This option can also be a fixed number or a function. If it is a
* function, this function is called in regular intervals while the note is
* playing. It receives three arguments: The point, the dataExtremes, and the
* current relative time - where 0 is the beginning of the note and 1 is the
* end. The function should return the panning of the note as a number between
* -1 and 1.
* @name Highcharts.PointInstrumentMappingObject#pan
* @type {string|number|Function|undefined}
*/ /**
* Define the frequency of the instrument. This can be a string with a data
* property name, e.g. `'y'`, in which case this data property is used to define
* the frequency relative to the `y`-values of the other points. A higher `y`
* value would then result in a higher frequency. This option can also be a
* fixed number or a function. If it is a function, this function is called in
* regular intervals while the note is playing. It receives three arguments:
* The point, the dataExtremes, and the current relative time - where 0 is the
* beginning of the note and 1 is the end. The function should return the
* frequency of the note as a number (in Hz).
* @name Highcharts.PointInstrumentMappingObject#frequency
* @type {string|number|Function}
*/
/**
* @requires module:modules/sonification
*
* @interface Highcharts.PointInstrumentOptionsObject
*/ /**
* The minimum duration for a note when using a data property for duration. Can
* be overridden by using either a fixed number or a function for
* instrumentMapping.duration. Defaults to 20.
* @name Highcharts.PointInstrumentOptionsObject#minDuration
* @type {number|undefined}
*/ /**
* The maximum duration for a note when using a data property for duration. Can
* be overridden by using either a fixed number or a function for
* instrumentMapping.duration. Defaults to 2000.
* @name Highcharts.PointInstrumentOptionsObject#maxDuration
* @type {number|undefined}
*/ /**
* The minimum pan value for a note when using a data property for panning. Can
* be overridden by using either a fixed number or a function for
* instrumentMapping.pan. Defaults to -1 (fully left).
* @name Highcharts.PointInstrumentOptionsObject#minPan
* @type {number|undefined}
*/ /**
* The maximum pan value for a note when using a data property for panning. Can
* be overridden by using either a fixed number or a function for
* instrumentMapping.pan. Defaults to 1 (fully right).
* @name Highcharts.PointInstrumentOptionsObject#maxPan
* @type {number|undefined}
*/ /**
* The minimum volume for a note when using a data property for volume. Can be
* overridden by using either a fixed number or a function for
* instrumentMapping.volume. Defaults to 0.1.
* @name Highcharts.PointInstrumentOptionsObject#minVolume
* @type {number|undefined}
*/ /**
* The maximum volume for a note when using a data property for volume. Can be
* overridden by using either a fixed number or a function for
* instrumentMapping.volume. Defaults to 1.
* @name Highcharts.PointInstrumentOptionsObject#maxVolume
* @type {number|undefined}
*/ /**
* The minimum frequency for a note when using a data property for frequency.
* Can be overridden by using either a fixed number or a function for
* instrumentMapping.frequency. Defaults to 220.
* @name Highcharts.PointInstrumentOptionsObject#minFrequency
* @type {number|undefined}
*/ /**
* The maximum frequency for a note when using a data property for frequency.
* Can be overridden by using either a fixed number or a function for
* instrumentMapping.frequency. Defaults to 2200.
* @name Highcharts.PointInstrumentOptionsObject#maxFrequency
* @type {number|undefined}
*/
/**
* An instrument definition for a point, specifying the instrument to play and
* how to play it.
*
* @interface Highcharts.PointInstrumentObject
*/ /**
* An Instrument instance or the name of the instrument in the
* Highcharts.sonification.instruments map.
* @name Highcharts.PointInstrumentObject#instrument
* @type {Highcharts.Instrument|string}
*/ /**
* Mapping of instrument parameters for this instrument.
* @name Highcharts.PointInstrumentObject#instrumentMapping
* @type {Highcharts.PointInstrumentMappingObject}
*/ /**
* Options for this instrument.
* @name Highcharts.PointInstrumentObject#instrumentOptions
* @type {Highcharts.PointInstrumentOptionsObject|undefined}
*/ /**
* Callback to call when the instrument has stopped playing.
* @name Highcharts.PointInstrumentObject#onEnd
* @type {Function|undefined}
*/
/**
* Options for sonifying a point.
* @interface Highcharts.PointSonifyOptionsObject
*/ /**
* The instrument definitions for this point.
* @name Highcharts.PointSonifyOptionsObject#instruments
* @type {Array<Highcharts.PointInstrumentObject>}
*/ /**
* Optionally provide the minimum/maximum values for the points. If this is not
* supplied, it is calculated from the points in the chart on demand. This
* option is supplied in the following format, as a map of point data properties
* to objects with min/max values:
* ```js
* dataExtremes: {
* y: {
* min: 0,
* max: 100
* },
* z: {
* min: -10,
* max: 10
* }
* // Properties used and not provided are calculated on demand
* }
* ```
* @name Highcharts.PointSonifyOptionsObject#dataExtremes
* @type {object|undefined}
*/ /**
* Callback called when the sonification has finished.
* @name Highcharts.PointSonifyOptionsObject#onEnd
* @type {Function|undefined}
*/
import utilities from './utilities.js';
// Defaults for the instrument options
// NOTE: Also change defaults in Highcharts.PointInstrumentOptionsObject if
// making changes here.
var defaultInstrumentOptions = {
minDuration: 20,
maxDuration: 2000,
minVolume: 0.1,
maxVolume: 1,
minPan: -1,
maxPan: 1,
minFrequency: 220,
maxFrequency: 2200
};
/* eslint-disable no-invalid-this, valid-jsdoc */
/**
* Sonify a single point.
*
* @sample highcharts/sonification/point-basic/
* Click on points to sonify
* @sample highcharts/sonification/point-advanced/
* Sonify bubbles
*
* @requires module:modules/sonification
*
* @function Highcharts.Point#sonify
*
* @param {Highcharts.PointSonifyOptionsObject} options
* Options for the sonification of the point.
*
* @return {void}
*/
function pointSonify(options) {
var point = this, chart = point.series.chart, dataExtremes = options.dataExtremes || {},
// Get the value to pass to instrument.play from the mapping value
// passed in.
getMappingValue = function (value, makeFunction, allowedExtremes) {
// Function. Return new function if we try to use callback,
// otherwise call it now and return result.
if (typeof value === 'function') {
return makeFunction ?
function (time) {
return value(point, dataExtremes, time);
} :
value(point, dataExtremes);
}
// String, this is a data prop.
if (typeof value === 'string') {
// Find data extremes if we don't have them
dataExtremes[value] = dataExtremes[value] ||
utilities.calculateDataExtremes(point.series.chart, value);
// Find the value
return utilities.virtualAxisTranslate(pick(point[value], point.options[value]), dataExtremes[value], allowedExtremes);
}
// Fixed number or something else weird, just use that
return value;
};
// Register playing point on chart
chart.sonification.currentlyPlayingPoint = point;
// Keep track of instruments playing
point.sonification = point.sonification || {};
point.sonification.instrumentsPlaying =
point.sonification.instrumentsPlaying || {};
// Register signal handler for the point
var signalHandler = point.sonification.signalHandler =
point.sonification.signalHandler ||
new utilities.SignalHandler(['onEnd']);
signalHandler.clearSignalCallbacks();
signalHandler.registerSignalCallbacks({ onEnd: options.onEnd });
// If we have a null point or invisible point, just return
if (point.isNull || !point.visible || !point.series.visible) {
signalHandler.emitSignal('onEnd');
return;
}
// Go through instruments and play them
options.instruments.forEach(function (instrumentDefinition) {
var instrument = typeof instrumentDefinition.instrument === 'string' ?
H.sonification.instruments[instrumentDefinition.instrument] :
instrumentDefinition.instrument, mapping = instrumentDefinition.instrumentMapping || {}, extremes = merge(defaultInstrumentOptions, instrumentDefinition.instrumentOptions), id = instrument.id, onEnd = function (cancelled) {
// Instrument on end
if (instrumentDefinition.onEnd) {
instrumentDefinition.onEnd.apply(this, arguments);
}
// Remove currently playing point reference on chart
if (chart.sonification &&
chart.sonification.currentlyPlayingPoint) {
delete chart.sonification.currentlyPlayingPoint;
}
// Remove reference from instruments playing
if (point.sonification && point.sonification.instrumentsPlaying) {
delete point.sonification.instrumentsPlaying[id];
// This was the last instrument?
if (!Object.keys(point.sonification.instrumentsPlaying).length) {
signalHandler.emitSignal('onEnd', cancelled);
}
}
};
// Play the note on the instrument
if (instrument && instrument.play) {
point.sonification.instrumentsPlaying[instrument.id] =
instrument;
instrument.play({
frequency: getMappingValue(mapping.frequency, true, { min: extremes.minFrequency, max: extremes.maxFrequency }),
duration: getMappingValue(mapping.duration, false, { min: extremes.minDuration, max: extremes.maxDuration }),
pan: getMappingValue(mapping.pan, true, { min: extremes.minPan, max: extremes.maxPan }),
volume: getMappingValue(mapping.volume, true, { min: extremes.minVolume, max: extremes.maxVolume }),
onEnd: onEnd,
minFrequency: extremes.minFrequency,
maxFrequency: extremes.maxFrequency
});
}
else {
error(30);
}
});
}
/**
* Cancel sonification of a point. Calls onEnd functions.
*
* @requires module:modules/sonification
*
* @function Highcharts.Point#cancelSonify
*
* @param {boolean} [fadeOut=false]
* Whether or not to fade out as we stop. If false, the points are
* cancelled synchronously.
*
* @return {void}
*/
function pointCancelSonify(fadeOut) {
var playing = this.sonification && this.sonification.instrumentsPlaying, instrIds = playing && Object.keys(playing);
if (instrIds && instrIds.length) {
instrIds.forEach(function (instr) {
playing[instr].stop(!fadeOut, null, 'cancelled');
});
this.sonification.instrumentsPlaying = {};
this.sonification.signalHandler.emitSignal('onEnd', 'cancelled');
}
}
var pointSonifyFunctions = {
pointSonify: pointSonify,
pointCancelSonify: pointCancelSonify
};
export default pointSonifyFunctions;