@hpcc-js/composite
Version: 
hpcc-js - Viz Composite
1,280 lines (1,182 loc) • 112 kB
JavaScript
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@hpcc-js/common'), require('@hpcc-js/api'), require('@hpcc-js/layout'), require('@hpcc-js/form'), require('@hpcc-js/other')) :
    typeof define === 'function' && define.amd ? define(['exports', '@hpcc-js/common', '@hpcc-js/api', '@hpcc-js/layout', '@hpcc-js/form', '@hpcc-js/other'], factory) :
    (factory((global['@hpcc-js/composite'] = {}),global['@hpcc-js/common'],global['@hpcc-js/api'],global['@hpcc-js/layout'],global['@hpcc-js/form'],global['@hpcc-js/other']));
}(this, (function (exports,common,api,layout,form,other) { 'use strict';
    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation. All rights reserved.
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use
    this file except in compliance with the License. You may obtain a copy of the
    License at http://www.apache.org/licenses/LICENSE-2.0
    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
    WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
    MERCHANTABLITY OR NON-INFRINGEMENT.
    See the Apache Version 2.0 License for specific language governing permissions
    and limitations under the License.
    ***************************************************************************** */
    /* global Reflect, Promise */
    var extendStatics = function(d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    function __extends(d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    }
    var prefix = "$";
    function Map() {}
    Map.prototype = map.prototype = {
      constructor: Map,
      has: function(key) {
        return (prefix + key) in this;
      },
      get: function(key) {
        return this[prefix + key];
      },
      set: function(key, value) {
        this[prefix + key] = value;
        return this;
      },
      remove: function(key) {
        var property = prefix + key;
        return property in this && delete this[property];
      },
      clear: function() {
        for (var property in this) if (property[0] === prefix) delete this[property];
      },
      keys: function() {
        var keys = [];
        for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
        return keys;
      },
      values: function() {
        var values = [];
        for (var property in this) if (property[0] === prefix) values.push(this[property]);
        return values;
      },
      entries: function() {
        var entries = [];
        for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
        return entries;
      },
      size: function() {
        var size = 0;
        for (var property in this) if (property[0] === prefix) ++size;
        return size;
      },
      empty: function() {
        for (var property in this) if (property[0] === prefix) return false;
        return true;
      },
      each: function(f) {
        for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
      }
    };
    function map(object, f) {
      var map = new Map;
      // Copy constructor.
      if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
      // Index array by numeric index or specified key function.
      else if (Array.isArray(object)) {
        var i = -1,
            n = object.length,
            o;
        if (f == null) while (++i < n) map.set(i, object[i]);
        else while (++i < n) map.set(f(o = object[i], i, object), o);
      }
      // Convert object to map.
      else if (object) for (var key in object) map.set(key, object[key]);
      return map;
    }
    function Set() {}
    var proto = map.prototype;
    Set.prototype = set.prototype = {
      constructor: Set,
      has: proto.has,
      add: function(value) {
        value += "";
        this[prefix + value] = value;
        return this;
      },
      remove: proto.remove,
      clear: proto.clear,
      values: proto.keys,
      size: proto.size,
      empty: proto.empty,
      each: proto.each
    };
    function set(object, f) {
      var set = new Set;
      // Copy constructor.
      if (object instanceof Set) object.each(function(value) { set.add(value); });
      // Otherwise, assume it’s an array.
      else if (object) {
        var i = -1, n = object.length;
        if (f == null) while (++i < n) set.add(object[i]);
        else while (++i < n) set.add(f(object[i], i, object));
      }
      return set;
    }
    function requireWidget(classID) {
        return new Promise(function (resolve, _reject) {
            var parsedClassID = common.Utility.parseClassID(classID);
            if (require) {
                require([parsedClassID.package], function (Package) {
                    var Widget = null;
                    if (Package && Package[parsedClassID.widgetID]) {
                        Widget = Package[parsedClassID.widgetID];
                    }
                    resolve(parsedClassID.memberWidgetID ? (Widget.prototype ? Widget.prototype[parsedClassID.memberWidgetID] : Widget[parsedClassID.memberWidgetID]) : Widget);
                });
            }
        });
    }
    function requireWidgets(classIDs) {
        return Promise.all(classIDs.map(requireWidget));
    }
    var Utility = /*#__PURE__*/Object.freeze({
        requireWidget: requireWidget,
        requireWidgets: requireWidgets
    });
    var MultiChart = /** @class */ (function (_super) {
        __extends(MultiChart, _super);
        function MultiChart() {
            var _this = _super.call(this) || this;
            _this._allCharts = {};
            api.INDChart.call(_this);
            api.IGraph.call(_this);
            _this._tag = "div";
            _this._allCharts = {};
            _this._allChartTypes.forEach(function (item) {
                var newItem = JSON.parse(JSON.stringify(item));
                newItem.widget = null;
                this._allCharts[item.id] = newItem;
                this._allCharts[item.display] = newItem;
                this._allCharts[item.widgetClass] = newItem;
            }, _this);
            _this._chartTypeDefaults = {};
            _this._chartTypeProperties = {};
            return _this;
        }
        MultiChart.prototype.fields = function (_) {
            var retVal = _super.prototype.fields.apply(this, arguments);
            if (this.chart()) {
                if (!arguments.length)
                    return this.chart().fields();
                this.chart().fields(_);
            }
            return retVal;
        };
        MultiChart.prototype.columns = function (_, asDefault) {
            var retVal = common.HTMLWidget.prototype.columns.apply(this, arguments);
            if (this.chart()) {
                if (!arguments.length)
                    return this.chart().columns();
                this.chart().columns(_, asDefault);
            }
            return retVal;
        };
        MultiChart.prototype.data = function (_) {
            var retVal = common.HTMLWidget.prototype.data.apply(this, arguments);
            if (this.chart()) {
                if (!arguments.length)
                    return this.chart().data();
                this.chart().data(_);
            }
            return retVal;
        };
        MultiChart.prototype.hasOverlay = function () {
            return this.chart() && this.chart().hasOverlay();
        };
        MultiChart.prototype.visible = function (_) {
            if (!arguments.length)
                return this.chart() && this.chart().visible();
            if (this.chart()) {
                this.chart().visible(_);
            }
            return this;
        };
        MultiChart.prototype.chartTypeDefaults = function (_) {
            if (!arguments.length)
                return this._chartTypeDefaults;
            this._chartTypeDefaults = _;
            return this;
        };
        MultiChart.prototype.chartTypeProperties = function (_) {
            if (!arguments.length)
                return this._chartTypeProperties;
            this._chartTypeProperties = _;
            return this;
        };
        MultiChart.prototype.getChartDataFamily = function () {
            return this._allCharts[this.chartType()].family;
        };
        MultiChart.prototype.requireContent = function (chartType, callback) {
            var classInfo = common.Utility.parseClassID(this._allCharts[chartType].widgetClass);
            switch (classInfo.package) {
                case "@hpcc-js/chart":
                    require(["@hpcc-js/chart"], function (mod) {
                        callback(new mod[classInfo.widgetID]());
                    });
                    break;
                case "@hpcc-js/dgrid":
                    require(["@hpcc-js/dgrid"], function (mod) {
                        callback(new mod[classInfo.widgetID]());
                    });
                    break;
                default:
                    requireWidget(this._allCharts[chartType].widgetClass).then(function (WidgetClass) {
                        callback(new WidgetClass());
                    });
            }
        };
        MultiChart.prototype.switchChart = function (callback) {
            if (this._switchingTo === this.chartType()) {
                if (callback) {
                    callback(this);
                }
                return;
            }
            else if (this._switchingTo) {
                console.log("Attempting switch to:  " + this.chartType() + ", before previous switch is complete (" + this._switchingTo + ")");
            }
            this._switchingTo = this.chartType();
            var oldContent = this.chart();
            var context = this;
            this.requireContent(this.chartType(), function (newContent) {
                if (newContent !== oldContent) {
                    var size = context.size();
                    newContent
                        .fields(context.fields())
                        .data(context.data())
                        .size(size);
                    context.chart(newContent);
                    if (oldContent) {
                        oldContent
                            .size({ width: 1, height: 1 })
                            .render();
                    }
                }
                delete context._switchingTo;
                if (callback) {
                    callback(this);
                }
            });
        };
        MultiChart.prototype.update = function (domNode, element) {
            _super.prototype.update.call(this, domNode, element);
            var content = element.selectAll(".multiChart").data(this.chart() ? [this.chart()] : [], function (d) { return d._id; });
            content.enter().append("div")
                .attr("class", "multiChart")
                .each(function (d) {
                d.target(this);
            });
            var currChart = this.chart();
            if (currChart) {
                for (var key in this._chartTypeDefaults) {
                    if (currChart[key + "_default"]) {
                        try {
                            currChart[key + "_default"](this._chartTypeDefaults[key]);
                        }
                        catch (e) {
                            console.log("Exception Setting Default:  " + key);
                        }
                    }
                    else {
                        console.log("Unknown Default:  " + key);
                    }
                }
                this._chartTypeDefaults = {};
                for (var propKey in this._chartTypeProperties) {
                    if (currChart[propKey]) {
                        try {
                            currChart[propKey](this._chartTypeProperties[propKey]);
                        }
                        catch (e) {
                            console.log("Exception Setting Property:  " + propKey);
                        }
                    }
                    else {
                        console.log("Unknown Property:  " + propKey);
                    }
                }
                this._chartTypeProperties = {};
            }
            var context = this;
            content
                .each(function (d) { d.resize(context.size()); });
            content.exit().transition()
                .each(function (d) { d.target(null); })
                .remove();
        };
        MultiChart.prototype.exit = function (domNode, element) {
            if (this._chartMonitor) {
                this._chartMonitor.remove();
                delete this._chartMonitor;
            }
            if (this.chart()) {
                this.chart().target(null);
            }
            _super.prototype.exit.call(this, domNode, element);
        };
        MultiChart.prototype.render = function (_callback) {
            if (this.chartType() && (!this.chart() || (this.chart().classID() !== this._allCharts[this.chartType()].widgetClass))) {
                var context_1 = this;
                var args_1 = arguments;
                this.switchChart(function () {
                    common.HTMLWidget.prototype.render.apply(context_1, args_1);
                });
                return this;
            }
            return common.HTMLWidget.prototype.render.apply(this, arguments);
        };
        return MultiChart;
    }(common.HTMLWidget));
    MultiChart.prototype._class += " composite_MultiChart";
    MultiChart.prototype.implements(api.INDChart.prototype);
    MultiChart.prototype.implements(api.IGraph.prototype);
    MultiChart.prototype._otherChartTypes = [
        { id: "FORM", display: "Form", widgetClass: "form_FieldForm" }
    ].map(function (item) { item.family = "other"; return item; });
    MultiChart.prototype._graphChartTypes = [
        { id: "GRAPH", display: "Graph", widgetClass: "graph_Graph" },
        { id: "ADJACENCY_GRAPH", display: "Graph", widgetClass: "graph_AdjacencyGraph" },
        { id: "GRAPHC", display: "GraphC", widgetClass: "graph_GraphC" }
    ].map(function (item) { item.family = "GRAPH"; return item; });
    MultiChart.prototype._1DChartTypes = [].map(function (item) { item.family = "1D"; return item; });
    MultiChart.prototype._2DChartTypes = [
        { id: "SUMMARY", display: "Summary", widgetClass: "chart_Summary" },
        { id: "BUBBLE", display: "Bubble", widgetClass: "chart_Bubble" },
        { id: "PIE", display: "Pie", widgetClass: "chart_Pie" },
        { id: "WORD_CLOUD", display: "Word Cloud", widgetClass: "other_WordCloud" }
    ].map(function (item) { item.family = "2D"; return item; });
    MultiChart.prototype._NDChartTypes = [
        { id: "COLUMN", display: "Column", widgetClass: "chart_Column" },
        { id: "BAR", display: "Bar", widgetClass: "chart_Bar" },
        { id: "LINE", display: "Line", widgetClass: "chart_Line" },
        { id: "AREA", display: "Area", widgetClass: "chart_Area" },
        { id: "STEP", display: "Step", widgetClass: "chart_Step" },
        { id: "SCATTER", display: "Scatter", widgetClass: "chart_Scatter" },
        { id: "HEXBIN", display: "Hex Bin", widgetClass: "chart_HexBin" }
    ].map(function (item) { item.family = "ND"; return item; });
    MultiChart.prototype._mapChartTypes = [
        { id: "CHORO_USSTATES", display: "US State Choropleth", widgetClass: "map_ChoroplethStates" },
        { id: "CHORO_USCOUNTIES", display: "US County Choropleth", widgetClass: "map_ChoroplethCounties" },
        { id: "CHORO_COUNTRIES", display: "Country Choropleth", widgetClass: "map_ChoroplethCountries" },
        { id: "GMAP_CHORO_USCOUNTIES", display: "Google Map US County  Choropleth", widgetClass: "map_GMapCounties" },
        { id: "GOOGLE_MAP", display: "Google Map", widgetClass: "map_GMapLayered" },
        { id: "OPENSTREET", display: "Open Street Map", widgetClass: "map_OpenStreet" }
    ].map(function (item) { item.family = "map"; return item; });
    MultiChart.prototype._anyChartTypes = [
        { id: "TABLE", display: "Table", widgetClass: "dgrid_Table" },
        { id: "TABLE_LEGACY", display: "Table (legacy)", widgetClass: "other_Table" },
        { id: "TABLE_NESTED", display: "Nested Table", widgetClass: "other_NestedTable" },
        { id: "TABLE_CALENDAR", display: "Table driven Calendar Heat Map", widgetClass: "other_CalendarHeatMap" },
        { id: "TABLE_BULLET", display: "Table driven bullet chart", widgetClass: "chart_Bullet" },
        { id: "TABLE_SELECT", display: "Table driven select", widgetClass: "other_Select" },
        { id: "TABLE_AUTOCOMPLETE", display: "Table driven auto complete", widgetClass: "other_AutoCompleteText" },
        { id: "TABLE_OPPORTUNITY", display: "Table driven opportunity widget", widgetClass: "graph_Opportunity" },
        { id: "TABLE_TREE", display: "Table driven tree", widgetClass: "tree_Dendrogram" },
        { id: "TABLE_TREEMAP", display: "Table driven Treemap", widgetClass: "tree_Treemap" },
        { id: "TABLE_SANKEY", display: "Table driven Sankey", widgetClass: "graph_Sankey" },
        { id: "TABLE_GMAP_PIN", display: "Table driven Google Map (pins)", widgetClass: "map_GMapPin" },
        { id: "TABLE_GMAP_PINLINE", display: "Table driven Google Map (pins/lines)", widgetClass: "map_GMapPinLine" },
        { id: "TABLE_XML_TREE", display: "Table driven XML Tree", widgetClass: "tree_Indented" }
    ].map(function (item) { item.family = "any"; return item; });
    MultiChart.prototype._allChartTypes =
        MultiChart.prototype._otherChartTypes.concat(MultiChart.prototype._graphChartTypes.concat(MultiChart.prototype._1DChartTypes.concat(MultiChart.prototype._2DChartTypes.concat(MultiChart.prototype._NDChartTypes.concat(MultiChart.prototype._mapChartTypes.concat(MultiChart.prototype._anyChartTypes))))));
    MultiChart.prototype._allMap = map(MultiChart.prototype._allChartTypes, function (item) { return item.family; });
    MultiChart.prototype._allFamilies = MultiChart.prototype._allMap.keys();
    MultiChart.prototype._allChartTypesMap = {};
    MultiChart.prototype._allChartTypesByClass = {};
    MultiChart.prototype._allChartTypes.forEach(function (item) {
        item.widgetPath = common.Utility.widgetPath(item.widgetClass);
        MultiChart.prototype._allChartTypesMap[item.id] = item;
        MultiChart.prototype._allChartTypesByClass[item.widgetClass] = item;
    });
    MultiChart.prototype.publishReset();
    MultiChart.prototype.publish("chartType", "BUBBLE", "set", "Chart Type", MultiChart.prototype._allChartTypes.map(function (item) { return item.id; }), { tags: ["Basic"] });
    MultiChart.prototype.publish("chart", null, "widget", "Chart", null, { tags: ["Basic"] });
    var _origChart = MultiChart.prototype.chart;
    MultiChart.prototype.chart = function (_) {
        var retVal = _origChart.apply(this, arguments);
        if (arguments.length) {
            var context_2 = this;
            if (this._allChartTypesByClass[_.classID()]) {
                this.chartType(this._allChartTypesByClass[_.classID()].id);
            }
            else {
                console.log("Unknown Class ID:  " + _.classID());
            }
            _.click = function (_row, _column, _selected) {
                context_2.click.apply(context_2, arguments);
            };
            _.dblclick = function (_row, _column, _selected) {
                context_2.dblclick.apply(context_2, arguments);
            };
            _.vertex_click = function (row, column, selected, more) {
                context_2.vertex_click.apply(context_2, arguments);
            };
            _.vertex_dblclick = function (row, column, selected, more) {
                context_2.vertex_dblclick.apply(context_2, arguments);
            };
            _.edge_click = function (row, column, selected, more) {
                context_2.edge_click.apply(context_2, arguments);
            };
            _.edge_dblclick = function (row, column, selected, more) {
                context_2.edge_dblclick.apply(context_2, arguments);
            };
            if (this._chartMonitor) {
                this._chartMonitor.remove();
                delete this._chartMonitor;
            }
            this._chartMonitor = _.monitor(function (key, newVal, oldVal) {
                context_2.broadcast(key, newVal, oldVal, _);
            });
        }
        return retVal;
    };
    function styleInject(css, ref) {
      if ( ref === void 0 ) ref = {};
      var insertAt = ref.insertAt;
      if (!css || typeof document === 'undefined') { return; }
      var head = document.head || document.getElementsByTagName('head')[0];
      var style = document.createElement('style');
      style.type = 'text/css';
      if (insertAt === 'top') {
        if (head.firstChild) {
          head.insertBefore(style, head.firstChild);
        } else {
          head.appendChild(style);
        }
      } else {
        head.appendChild(style);
      }
      if (style.styleSheet) {
        style.styleSheet.cssText = css;
      } else {
        style.appendChild(document.createTextNode(css));
      }
    }
    var css = ".composite_ChartPanel > .body {\r\n    margin: 0;\r\n    padding: 0;\r\n    display: flex;\r\n    flex-flow: row;\r\n}\r\n\r\n.composite_ChartPanel > .body > article {\r\n    flex: 3 1 60%;\r\n    order: 2;\r\n}\r\n\r\n.composite_ChartPanel > .body > nav {\r\n    flex: 1 6 20%;\r\n    order: 1;\r\n}\r\n\r\n.composite_ChartPanel > .body > aside {\r\n    margin-left: 4px;\r\n    flex: 1 6 20%;\r\n    order: 3;\r\n}\r\n\r\nheader, footer {\r\n    display: block;\r\n}\r\n";
    styleInject(css);
    var Summary = /** @class */ (function (_super) {
        __extends(Summary, _super);
        function Summary() {
            return _super.call(this) || this;
        }
        Summary.prototype.enter = function (domNode, element) {
            _super.prototype.enter.call(this, domNode, element);
            element.append("p");
        };
        Summary.prototype.update = function (domNode, element) {
            _super.prototype.update.call(this, domNode, element);
            element.select("p").text(this.text());
        };
        return Summary;
    }(common.HTMLWidget));
    Summary.prototype.publish("text", "", "string");
    var MultiChartPanel = /** @class */ (function (_super) {
        __extends(MultiChartPanel, _super);
        function MultiChartPanel() {
            var _this = _super.call(this) || this;
            _this.widget(new MultiChart().chartType("COLUMN"));
            return _this;
        }
        MultiChartPanel.prototype.multiChart = function () {
            return this._widget;
        };
        MultiChartPanel.prototype.chartType = function (_) {
            if (!arguments.length)
                return this._widget.chartType();
            this._widget.chartType(_);
            return this;
        };
        MultiChartPanel.prototype.chart = function (_) {
            if (!arguments.length)
                return this._widget.chart();
            this._widget.chart(_);
            return this;
        };
        MultiChartPanel.prototype.chartTypeDefaults = function (_) {
            if (!arguments.length)
                return this._widget.chartTypeDefaults();
            this._widget.chartTypeDefaults(_);
            return this;
        };
        MultiChartPanel.prototype.chartTypeProperties = function (_) {
            if (!arguments.length)
                return this._widget.chartTypeProperties();
            this._widget.chartTypeProperties(_);
            return this;
        };
        MultiChartPanel.prototype.update = function (domNode, element) {
            _super.prototype.update.call(this, domNode, element);
            if (this._widget instanceof MultiChart) {
                this._legend.dataFamily(this._widget.getChartDataFamily());
            }
            _super.prototype.update.call(this, domNode, element);
        };
        return MultiChartPanel;
    }(layout.ChartPanel));
    MultiChartPanel.prototype._class += " composite_MultiChartPanel";
    var css$1 = ".composite_Dermatology {\r\n    background-color: ghostwhite;\r\n}\r\n\r\n.composite_Dermatology .common_Icon {\r\n    background-color: red;\r\n    opacity:0.75;\r\n}\r\n\r\n.composite_Dermatology .common_Icon .common_Shape {\r\n    fill: white;\r\n    stroke: darkgray;\r\n    cursor:pointer;\r\n}\r\n\r\n.composite_Dermatology .common_Icon.show .common_Shape {\r\n    fill: lightgray;\r\n}\r\n\r\n.composite_Dermatology .common_Icon .common_FAChar .common_Text {\r\n    fill: darkgray;\r\n    cursor:pointer;\r\n}\r\n\r\n.composite_Dermatology .other_PropertyEditor {\r\n    font-family: sans-serif;\r\n    font-size: 11px;\r\n}\r\n\r\n.composite_Dermatology .other_PropertyEditor input {\r\n    font-family: sans-serif;\r\n    font-size: 11px;\r\n    border:0px;\r\n}\r\n\r\n.composite_Dermatology .other_PropertyEditor .property-label {\r\n    height:unset;\r\n}\r\n";
    styleInject(css$1);
    var Dermatology = /** @class */ (function (_super) {
        __extends(Dermatology, _super);
        function Dermatology() {
            var _this = _super.call(this) || this;
            _this._toolbar = new layout.Toolbar()
                .title("Dermatology");
            _this._propEditor = new other.PropertyEditor()
                .show_settings(true);
            return _this;
        }
        Dermatology.prototype.showProperties = function (_) {
            if (!arguments.length)
                return this._showProperties;
            this._showProperties = _;
            this
                .rightPercentage(0)
                .rightSize(this._showProperties ? 360 : 0)
                .setContent("right", this._showProperties ? this._propEditor : null);
            var widget = this.widget();
            if (widget && widget.designMode) {
                widget.designMode(this._showProperties);
            }
            return this;
        };
        Dermatology.prototype.toggleProperties = function () {
            return this.showProperties(!this.showProperties());
        };
        Dermatology.prototype.enter = function (domNode, element) {
            _super.prototype.enter.call(this, domNode, element);
            this
                .topPercentage(0)
                .topSize(0)
                .setContent("top", this._toolbar);
            this.getCell("top").surfaceShadow(true);
            var context = this;
            this._propsButton = new form.OnOff()
                .id(this.id() + "_props")
                .value("Properties")
                .on("click", function () {
                context
                    .toggleProperties()
                    .render();
            });
            this._toolbar.widgets([this._propsButton]);
        };
        Dermatology.prototype.update = function (domNode, element) {
            this
                .topPercentage(0)
                .topSize(this.showToolbar() ? 32 : 0);
            _super.prototype.update.call(this, domNode, element);
            var widget = this.widget();
            element.style("background-color", widget && widget.surfaceShadow ? null : "white");
        };
        Dermatology.prototype.render = function (callback) {
            var widget = this.widget();
            if (widget !== this._prevWidget) {
                if (widget && widget.surfaceShadow) {
                    widget.surfaceBackgroundColor_default("white");
                }
                this.setContent("center", widget);
                this._propEditor.widget(widget);
                this._prevWidget = widget;
            }
            return _super.prototype.render.call(this, callback);
        };
        return Dermatology;
    }(layout.Border));
    Dermatology.prototype._class += " composite_Dermatology";
    Dermatology.prototype.publish("showToolbar", true, "boolean", "Show Toolbar");
    Dermatology.prototype.publish("widget", null, "widget", "Widget");
    var noop = {value: function() {}};
    function dispatch() {
      for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
        if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
        _[t] = [];
      }
      return new Dispatch(_);
    }
    function Dispatch(_) {
      this._ = _;
    }
    function parseTypenames(typenames, types) {
      return typenames.trim().split(/^|\s+/).map(function(t) {
        var name = "", i = t.indexOf(".");
        if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
        if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
        return {type: t, name: name};
      });
    }
    Dispatch.prototype = dispatch.prototype = {
      constructor: Dispatch,
      on: function(typename, callback) {
        var _ = this._,
            T = parseTypenames(typename + "", _),
            t,
            i = -1,
            n = T.length;
        // If no callback was specified, return the callback of the given type and name.
        if (arguments.length < 2) {
          while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
          return;
        }
        // If a type was specified, set the callback for the given type and name.
        // Otherwise, if a null callback was specified, remove callbacks of the given name.
        if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
        while (++i < n) {
          if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);
          else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null);
        }
        return this;
      },
      copy: function() {
        var copy = {}, _ = this._;
        for (var t in _) copy[t] = _[t].slice();
        return new Dispatch(copy);
      },
      call: function(type, that) {
        if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
        if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
        for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
      },
      apply: function(type, that, args) {
        if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
        for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
      }
    };
    function get(type, name) {
      for (var i = 0, n = type.length, c; i < n; ++i) {
        if ((c = type[i]).name === name) {
          return c.value;
        }
      }
    }
    function set$1(type, name, callback) {
      for (var i = 0, n = type.length; i < n; ++i) {
        if (type[i].name === name) {
          type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
          break;
        }
      }
      if (callback != null) type.push({name: name, value: callback});
      return type;
    }
    var frame = 0, // is an animation frame pending?
        timeout = 0, // is a timeout pending?
        interval = 0, // are any timers active?
        pokeDelay = 1000, // how frequently we check for clock skew
        taskHead,
        taskTail,
        clockLast = 0,
        clockNow = 0,
        clockSkew = 0,
        clock = typeof performance === "object" && performance.now ? performance : Date,
        setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); };
    function now() {
      return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
    }
    function clearNow() {
      clockNow = 0;
    }
    function Timer() {
      this._call =
      this._time =
      this._next = null;
    }
    Timer.prototype = timer.prototype = {
      constructor: Timer,
      restart: function(callback, delay, time) {
        if (typeof callback !== "function") throw new TypeError("callback is not a function");
        time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
        if (!this._next && taskTail !== this) {
          if (taskTail) taskTail._next = this;
          else taskHead = this;
          taskTail = this;
        }
        this._call = callback;
        this._time = time;
        sleep();
      },
      stop: function() {
        if (this._call) {
          this._call = null;
          this._time = Infinity;
          sleep();
        }
      }
    };
    function timer(callback, delay, time) {
      var t = new Timer;
      t.restart(callback, delay, time);
      return t;
    }
    function timerFlush() {
      now(); // Get the current time, if not already set.
      ++frame; // Pretend we’ve set an alarm, if we haven’t already.
      var t = taskHead, e;
      while (t) {
        if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
        t = t._next;
      }
      --frame;
    }
    function wake() {
      clockNow = (clockLast = clock.now()) + clockSkew;
      frame = timeout = 0;
      try {
        timerFlush();
      } finally {
        frame = 0;
        nap();
        clockNow = 0;
      }
    }
    function poke() {
      var now = clock.now(), delay = now - clockLast;
      if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
    }
    function nap() {
      var t0, t1 = taskHead, t2, time = Infinity;
      while (t1) {
        if (t1._call) {
          if (time > t1._time) time = t1._time;
          t0 = t1, t1 = t1._next;
        } else {
          t2 = t1._next, t1._next = null;
          t1 = t0 ? t0._next = t2 : taskHead = t2;
        }
      }
      taskTail = t0;
      sleep(time);
    }
    function sleep(time) {
      if (frame) return; // Soonest alarm already set, or will be.
      if (timeout) timeout = clearTimeout(timeout);
      var delay = time - clockNow;
      if (delay > 24) {
        if (time < Infinity) timeout = setTimeout(wake, delay);
        if (interval) interval = clearInterval(interval);
      } else {
        if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
        frame = 1, setFrame(wake);
      }
    }
    function timeout$1(callback, delay, time) {
      var t = new Timer;
      delay = delay == null ? 0 : +delay;
      t.restart(function(elapsed) {
        t.stop();
        callback(elapsed + delay);
      }, delay, time);
      return t;
    }
    var emptyOn = dispatch("start", "end", "interrupt");
    var emptyTween = [];
    var CREATED = 0;
    var SCHEDULED = 1;
    var STARTING = 2;
    var STARTED = 3;
    var RUNNING = 4;
    var ENDING = 5;
    var ENDED = 6;
    function schedule(node, name, id, index, group, timing) {
      var schedules = node.__transition;
      if (!schedules) node.__transition = {};
      else if (id in schedules) return;
      create(node, id, {
        name: name,
        index: index, // For context during callback.
        group: group, // For context during callback.
        on: emptyOn,
        tween: emptyTween,
        time: timing.time,
        delay: timing.delay,
        duration: timing.duration,
        ease: timing.ease,
        timer: null,
        state: CREATED
      });
    }
    function init(node, id) {
      var schedule = node.__transition;
      if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
      return schedule;
    }
    function set$2(node, id) {
      var schedule = node.__transition;
      if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
      return schedule;
    }
    function get$1(node, id) {
      var schedule = node.__transition;
      if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
      return schedule;
    }
    function create(node, id, self) {
      var schedules = node.__transition,
          tween;
      // Initialize the self timer when the transition is created.
      // Note the actual delay is not known until the first callback!
      schedules[id] = self;
      self.timer = timer(schedule, 0, self.time);
      function schedule(elapsed) {
        self.state = SCHEDULED;
        self.timer.restart(start, self.delay, self.time);
        // If the elapsed delay is less than our first sleep, start immediately.
        if (self.delay <= elapsed) start(elapsed - self.delay);
      }
      function start(elapsed) {
        var i, j, n, o;
        // If the state is not SCHEDULED, then we previously errored on start.
        if (self.state !== SCHEDULED) return stop();
        for (i in schedules) {
          o = schedules[i];
          if (o.name !== self.name) continue;
          // While this element already has a starting transition during this frame,
          // defer starting an interrupting transition until that transition has a
          // chance to tick (and possibly end); see d3/d3-transition#54!
          if (o.state === STARTED) return timeout$1(start);
          // Interrupt the active transition, if any.
          // Dispatch the interrupt event.
          if (o.state === RUNNING) {
            o.state = ENDED;
            o.timer.stop();
            o.on.call("interrupt", node, node.__data__, o.index, o.group);
            delete schedules[i];
          }
          // Cancel any pre-empted transitions. No interrupt event is dispatched
          // because the cancelled transitions never started. Note that this also
          // removes this transition from the pending list!
          else if (+i < id) {
            o.state = ENDED;
            o.timer.stop();
            delete schedules[i];
          }
        }
        // Defer the first tick to end of the current frame; see d3/d3#1576.
        // Note the transition may be canceled after start and before the first tick!
        // Note this must be scheduled before the start event; see d3/d3-transition#16!
        // Assuming this is successful, subsequent callbacks go straight to tick.
        timeout$1(function() {
          if (self.state === STARTED) {
            self.state = RUNNING;
            self.timer.restart(tick, self.delay, self.time);
            tick(elapsed);
          }
        });
        // Dispatch the start event.
        // Note this must be done before the tween are initialized.
        self.state = STARTING;
        self.on.call("start", node, node.__data__, self.index, self.group);
        if (self.state !== STARTING) return; // interrupted
        self.state = STARTED;
        // Initialize the tween, deleting null tween.
        tween = new Array(n = self.tween.length);
        for (i = 0, j = -1; i < n; ++i) {
          if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
            tween[++j] = o;
          }
        }
        tween.length = j + 1;
      }
      function tick(elapsed) {
        var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
            i = -1,
            n = tween.length;
        while (++i < n) {
          tween[i].call(null, t);
        }
        // Dispatch the end event.
        if (self.state === ENDING) {
          self.on.call("end", node, node.__data__, self.index, self.group);
          stop();
        }
      }
      function stop() {
        self.state = ENDED;
        self.timer.stop();
        delete schedules[id];
        for (var i in schedules) return; // eslint-disable-line no-unused-vars
        delete node.__transition;
      }
    }
    function interrupt(node, name) {
      var schedules = node.__transition,
          schedule$$1,
          active,
          empty = true,
          i;
      if (!schedules) return;
      name = name == null ? null : name + "";
      for (i in schedules) {
        if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; }
        active = schedule$$1.state > STARTING && schedule$$1.state < ENDING;
        schedule$$1.state = ENDED;
        schedule$$1.timer.stop();
        if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group);
        delete schedules[i];
      }
      if (empty) delete node.__transition;
    }
    function selection_interrupt(name) {
      return this.each(function() {
        interrupt(this, name);
      });
    }
    function define(constructor, factory, prototype) {
      constructor.prototype = factory.prototype = prototype;
      prototype.constructor = constructor;
    }
    function extend(parent, definition) {
      var prototype = Object.create(parent.prototype);
      for (var key in definition) prototype[key] = definition[key];
      return prototype;
    }
    function Color() {}
    var darker = 0.7;
    var brighter = 1 / darker;
    var reI = "\\s*([+-]?\\d+)\\s*",
        reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
        reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
        reHex3 = /^#([0-9a-f]{3})$/,
        reHex6 = /^#([0-9a-f]{6})$/,
        reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
        reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
        reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
        reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
        reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
        reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
    var named = {
      aliceblue: 0xf0f8ff,
      antiquewhite: 0xfaebd7,
      aqua: 0x00ffff,
      aquamarine: 0x7fffd4,
      azure: 0xf0ffff,
      beige: 0xf5f5dc,
      bisque: 0xffe4c4,
      black: 0x000000,
      blanchedalmond: 0xffebcd,
      blue: 0x0000ff,
      blueviolet: 0x8a2be2,
      brown: 0xa52a2a,
      burlywood: 0xdeb887,
      cadetblue: 0x5f9ea0,
      chartreuse: 0x7fff00,
      chocolate: 0xd2691e,
      coral: 0xff7f50,
      cornflowerblue: 0x6495ed,
      cornsilk: 0xfff8dc,
      crimson: 0xdc143c,
      cyan: 0x00ffff,
      darkblue: 0x00008b,
      darkcyan: 0x008b8b,
      darkgoldenrod: 0xb8860b,
      darkgray: 0xa9a9a9,
      darkgreen: 0x006400,
      darkgrey: 0xa9a9a9,
      darkkhaki: 0xbdb76b,
      darkmagenta: 0x8b008b,
      darkolivegreen: 0x556b2f,
      darkorange: 0xff8c00,
      darkorchid: 0x9932cc,
      darkred: 0x8b0000,
      darksalmon: 0xe9967a,
      darkseagreen: 0x8fbc8f,
      darkslateblue: 0x483d8b,
      darkslategray: 0x2f4f4f,
      darkslategrey: 0x2f4f4f,
      darkturquoise: 0x00ced1,
      darkviolet: 0x9400d3,
      deeppink: 0xff1493,
      deepskyblue: 0x00bfff,
      dimgray: 0x696969,
      dimgrey: 0x696969,
      dodgerblue: 0x1e90ff,
      firebrick: 0xb22222,
      floralwhite: 0xfffaf0,
      forestgreen: 0x228b22,
      fuchsia: 0xff00ff,
      gainsboro: 0xdcdcdc,
      ghostwhite: 0xf8f8ff,
      gold: 0xffd700,
      goldenrod: 0xdaa520,
      gray: 0x808080,
      green: 0x008000,
      greenyellow: 0xadff2f,
      grey: 0x808080,
      honeydew: 0xf0fff0,
      hotpink: 0xff69b4,
      indianred: 0xcd5c5c,
      indigo: 0x4b0082,
      ivory: 0xfffff0,
      khaki: 0xf0e68c,
      lavender: 0xe6e6fa,
      lavenderblush: 0xfff0f5,
      lawngreen: 0x7cfc00,
      lemonchiffon: 0xfffacd,
      lightblue: 0xadd8e6,
      lightcoral: 0xf08080,
      lightcyan: 0xe0ffff,
      lightgoldenrodyellow: 0xfafad2,
      lightgray: 0xd3d3d3,
      lightgreen: 0x90ee90,
      lightgrey: 0xd3d3d3,
      lightpink: 0xffb6c1,
      lightsalmon: 0xffa07a,
      lightseagreen: 0x20b2aa,
      lightskyblue: 0x87cefa,
      lightslategray: 0x778899,
      lightslategrey: 0x778899,
      lightsteelblue: 0xb0c4de,
      lightyellow: 0xffffe0,
      lime: 0x00ff00,
      limegreen: 0x32cd32,
      linen: 0xfaf0e6,
      magenta: 0xff00ff,
      maroon: 0x800000,
      mediumaquamarine: 0x66cdaa,
      mediumblue: 0x0000cd,
      mediumorchid: 0xba55d3,
      mediumpurple: 0x9370db,
      mediumseagreen: 0x3cb371,
      mediumslateblue: 0x7b68ee,
      mediumspringgreen: 0x00fa9a,
      mediumturquoise: 0x48d1cc,
      mediumvioletred: 0xc71585,
      midnightblue: 0x191970,
      mintcream: 0xf5fffa,
      mistyrose: 0xffe4e1,
      moccasin: 0xffe4b5,
      navajowhite: 0xffdead,
      navy: 0x000080,
      oldlace: 0xfdf5e6,
      olive: 0x808000,
      olivedrab: 0x6b8e23,
      orange: 0xffa500,
      orangered: 0xff4500,
      orchid: 0xda70d6,
      palegoldenrod: 0xeee8aa,
      palegreen: 0x98fb98,
      paleturquoise: 0xafeeee,
      palevioletred: 0xdb7093,
      papayawhip: 0xffefd5,
      peachpuff: 0xffdab9,
      peru: 0xcd853f,
      pink: 0xffc0cb,
      plum: 0xdda0dd,
      powderblue: 0xb0e0e6,
      purple: 0x800080,
      rebeccapurple: 0x663399,
      red: 0xff0000,
      rosybrown: 0xbc8f8f,
      royalblue: 0x4169e1,
      saddlebrown: 0x8b4513,
      salmon: 0xfa8072,
      sandybrown: 0xf4a460,
      seagreen: 0x2e8b57,
      seashell: 0xfff5ee,
      sienna: 0xa0522d,
      silver: 0xc0c0c0,
      skyblue: 0x87ceeb,
      slateblue: 0x6a5acd,
      slategray: 0x708090,
      slategrey: 0x708090,
      snow: 0xfffafa,
      springgreen: 0x00ff7f,
      steelblue: 0x4682b4,
      tan: 0xd2b48c,
      teal: 0x008080,
      thistle: 0xd8bfd8,
      tomato: 0xff6347,
      turquoise: 0x40e0d0,
      violet: 0xee82ee,
      wheat: 0xf5deb3,
      white: 0xffffff,
      whitesmoke: 0xf5f5f5,
      yellow: 0xffff00,
      yellowgreen: 0x9acd32
    };
    define(Color, color, {
      displayable: function() {
        return this.rgb().displayable();
      },
      hex: function() {
        return this.rgb().hex();
      },
      toString: function() {
        return this.rgb() + "";
      }
    });
    function color(format) {
      var m;
      format = (format + "").trim().toLowerCase();
      return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
          : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
          : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
          : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
          : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
          : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
          : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
          : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
          : named.hasOwnProperty(format) ? rgbn(named[format])
          : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
          : null;
    }
    function rgbn(n) {
      return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
    }
    function rgba(r, g, b, a) {
      if (a <= 0) r = g = b = NaN;
      return new Rgb(r, g, b, a);
    }
    function rgbConvert(o) {
      if (!(o instanceof Color)) o = color(o);
      if (!o) return new Rgb;
      o = o.rgb();
      return new Rgb(o.r, o.g, o.b, o.opacity);
    }
    function rgb(r, g, b, opacity) {
      return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
    }
    function Rgb(r, g, b, opacity) {
      this.r = +r;
      this.g = +g;
      this.b = +b;
      this.opacity = +opacity;
    }
    define(Rgb, rgb, extend(Color, {
      brighter: function(k) {
        k = k == null ? brighter : Math.pow(brighter, k);
        return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
      },
      darker: function(k) {
        k = k == null ? darker : Math.pow(darker, k);
        return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
      },
      rgb: function() {
        return this;
      },
      displayable: function() {
        return (0 <= this.r && this.r <= 255)
            && (0 <= this.g && this.g <= 255)
            && (0 <= this.b && this.b <= 255)
            && (0 <= this.opacity && this.opacity <= 1);
      },
      hex: function() {
        return "#" + hex(this.r) + hex(this.g) + hex(this.b);
      },
      toString: function() {
        var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
        return (a === 1 ? "rgb(" : "rgba(")
            + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
            + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
            + Math.max(0, Math.min(255, Math.round(this.b) || 0))
            + (a ==