Source: widgets/frequencyresponse.js

/*
 * This file is part of Toolkit.
 *
 * Toolkit is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * Toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General
 * Public License along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */
"use strict";
(function(w, TK){
function calculate_grid(range, step) {
    var min = range.get("min");
    var max = range.get("max");
    var grid = [];
    var i, cls;


    for (i = min; i <= max; i += step) {
        if (i == 0) {
            cls = "toolkit-highlight";
        } else {
            cls = "";
        }
        grid.push({
            pos:     i,
            label:   i === min ? "" : i + "dB",
            "class": cls
        });
    }

    return grid;
}
TK.FrequencyResponse = TK.class({
    /**
     * TK.FrequencyResponse is a {@link TK.Chart} drawing frequencies on the x axis and dB
     * values on the y axis. This widget automatically draws a {@link TK.Grid} depending
     * on the ranges.
     *
     * @class TK.FrequencyResponse
     * 
     * @extends TK.Chart
     * 
     * @param {Object} [options={ }] - An object containing initial options.
     * 
     * @property {Number} [options.db_grid=12] - Distance in decibels between y axis grid lines.
     * @property {Object} [options.range_x={min:20, max:20000, scale:"frequency"}] - Either a function returning a {@link TK.Range}
     *   or an object containing options for a new {@link TK.Range}
     * @property {Object} [options.range_y={min:-36, max: 36, scale: "linear"}] - Either a function returning a {@link TK.Range}
     *   or an object containing options for a new {@link TK.Range}
     * @property {Array<Object>} [options.grid_x=[{pos:    20, label: "20 Hz"}, {pos:    30}, {pos:    40}, {pos:    50}, {pos:    60}, {pos:    70}, {pos:    80}, {pos:    90}, {pos:   100, label: "100 Hz"}, {pos:   200}, {pos:   300}, {pos:   400}, {pos:   500}, {pos:   600}, {pos:   700}, {pos:   800}, {pos:   900}, {pos:  1000, label: "1000 Hz"}, {pos:  2000}, {pos:  3000}, {pos:  4000}, {pos:  5000}, {pos:  6000}, {pos:  7000}, {pos:  8000}, {pos:  9000}, {pos: 10000, label: "10000 Hz"}, {pos: 20000, label: "20000 Hz"}]] - An array containing objects with the following optional members:
     * @property {Number} [options.grid_x.pos] - The value where to draw grid line and corresponding label.
     * @property {String} [options.grid_x.color] - A valid CSS color string to colorize the elements.
     * @property {String} [options.grid_x.class] - A class name for the elements.
     * @property {String} [options.grid_x.label] - A label string.
     * @property {String} [options.scale="linear"] - The type of the decibels scale. See {@link TK.Range} for more details.
     * @property {Number} [options.depth=0] - The depth of the z axis (<code>basis</code> of options.range_z)
     */
    _class: "FrequencyResponse",
    Extends: TK.Chart,
    _options: Object.assign(Object.create(TK.Chart.prototype._options), {
        db_grid: "number",
        grid_x: "array",
        scale: "boolean",
        depth: "number",
    }),
    options: {
        db_grid: 12,                                         // dB grid distance
        range_x: {min:20, max:20000, scale:"frequency"},   // TK.Range x options
        range_y: {min:-36, max: 36, scale: "linear"}, // TK.Range y options
        range_z: {min:0.1, max:10, scale:"linear"},
        grid_x:  [
                    {pos:    20, label: "20Hz"},
                    {pos:    30},
                    {pos:    40},
                    {pos:    50},
                    {pos:    60},
                    {pos:    70},
                    {pos:    80},
                    {pos:    90},
                    {pos:   100, label: "100Hz"},
                    {pos:   200},
                    {pos:   300},
                    {pos:   400},
                    {pos:   500},
                    {pos:   600},
                    {pos:   700},
                    {pos:   800},
                    {pos:   900},
                    {pos:  1000, label: "1kHz"},
                    {pos:  2000},
                    {pos:  3000},
                    {pos:  4000},
                    {pos:  5000},
                    {pos:  6000},
                    {pos:  7000},
                    {pos:  8000},
                    {pos:  9000},
                    {pos: 10000, label: "10kHz"},
                    {pos: 20000, label: "20kHz"}],        // Frequency grid
        scale:  false,                                       // the mode of the
                                                             // dB scale
        depth: 0,   // the depth of the z axis (basis of range_z)
    },
    static_events: {
        set_scale: function(value, key) {
            this.range_y.set("scale", value);
        },
        set_db_grid: function(value) {
            this.set("grid_y", calculate_grid(this.range_y, value));
        },
    },
    initialize: function (options) {
        if (options.scale)
            this.set("scale", options.scale, true);
        TK.Chart.prototype.initialize.call(this, options);
        /**
         * @member {HTMLDivElement} TK.FrequencyResponse#element - The main DIV container.
         *   Has class <code>toolkit-frequency-response</code>.
         */
        TK.add_class(this.element, "toolkit-frequency-response");
        /** 
         * @member {SVGGroup} TK.Chart#_handles - The SVG group containing all handles.
         *      Has class <code>toolkit-response-handles</code>.
         */
        TK.add_class(this._handles, "toolkit-response-handles");
        
        // do not overwrite custom grids, please
        if (this.options.db_grid && !this.options.grid_y.length)
            this.set("db_grid", this.options.db_grid);
        this.range_y.add_event("set", function (key, value) {
            if (key === "scale")
                this.options.scale = value;
        }.bind(this));
        if (this.options.depth) this.set("depth", this.options.depth);
    },

    redraw: function() {
        var I = this.invalid;
        var O = this.options;

        if (I.scale) {
            I.scale = false;
            // tell chart to redraw
            I.ranges = true;
        }

        TK.Chart.prototype.redraw.call(this);
    },
});
})(this, this.TK);