Introduction to custom widget development in DataV

更新时间:
复制 MD 格式

This topic is for frontend developers. If the available DataV widgets and materials do not meet the requirements of your scenario, you can create your own custom widgets.

Development environment

Download and install Node.js from the official Node.js website. We recommend using a Node.js version that is 8.0.0 or later and earlier than 10.12.0. Versions outside this range are not supported. We also recommend using nvm to manage Node.js. For more information about the installation procedure, see Quick start for widget development.

Note

If you installed Node.js on Windows but cannot find or use it, your environment variable is likely not configured correctly.

After the installation is complete, run the node -v command to check the Node.js version.

Create a widget package

  1. Log on to the DataV console.

  2. On the console page, click My Assets > My Widget Packages > New Widget Package Project.

  3. Enter the English Name and Chinese Name for the widget package, and then click Create in the lower-right corner.

    Note

    The English name of the widget package must be in the `CompanyName.PackageName` or `CompanyName-PackageName` format. The Chinese name can be customized.

  4. After the widget package is created, its status is Under review. All widget packages are reviewed manually. If your widget package is not reviewed for an extended period or the review fails, contact a technical support engineer for assistance.

  5. After the widget package is approved, run the following command to download the datav-cli command-line tool.

    npm install datav-cli -g
  6. Run datav --version to check the version of the development tool.

  7. In the DataV console, locate your Username in the upper-right corner. Go to the My Widget Packages page and click Developer Access Token to copy the token. Then, run the datav login command to log on.

  8. After you log on, run the datav init command. Enter the Widget Name, Display Name, Widget Description, and Basic Text Generation Widget. After the widget is created, a widget folder is automatically generated in the current directory.

  9. Run the datav run command to preview your widget locally.

  10. After you preview the widget, you can publish it in one of the following two ways:

    • Method 1: In the widget folder, run the datav publish command. This method requires your username and developer access token. (Recommended)

    • Method 2: In the widget folder, run the datav package command. A compressed package named `WidgetName-VersionNumber.tar.gz` is generated in the parent directory of the widget folder. Upload this package on the My Widget Packages page in the DataV console.

    Note

    After you run the datav publish command, the packaging process runs on the server and may be queued. If the command indicates that the widget is published successfully but an error occurs when you pull the widget, the packaging process is likely still in the queue. In this case, wait a few moments, refresh your browser, and then retry.

    Open the widget in a development tool. The main configuration is performed in the `package.json` and `index.js` files. For information about the code settings in the `package.json` file, see the following example:

    {
      "name": "@aliyun-datav_design/datav-r",        // Must be the same as the English name of the widget package.
      "version": "0.0.9",
      "dependencies": { 
        "bcore": "0.0.18",
        "jquery": "2.1.4",
        "lodash": "4.6.1"
      },
      "datav": {
        "cn_name": "datav-r",
        "icon": "",
        "protocol": 2,
        "type": [
          "regular"
        ],
        "view": {
          "width": "400",
          "height": "600",
          "minWidth": "200",
          "minHeight": "100"
        },
        "apis": {
          "source": {
            "handler": "render",
            "description": "API description",
            "fields": {
              "value": {
                "description": "Value description"
              }
            }
          }
        },
        "config": {
          "size": {
            "name": "Font size",
            "type": "number",
            "default": 22,
            "range": [
              10,
              100
            ]
          },
          "color": {
            "name": "Font color",
            "type": "color",
            "default": "#fff"
        },"path": {
          "type": "hidden",
          "default": "./resources/img.png"
        }
        },
        "events": {
          "button-click": {
            "name": "On click",
            "description": "Description for the click event",
            "type": "string"
          }
        },
        "publicHandler": {
          "setColor": {
            "name": "Change text color",
            "type": "object",
            "fields": {
              "color": {
                "name": "Text color",
                "description": "Change the text color",
                "type": "string | number",
                "default": "red"
              }
            }
          }
        },
        "api_data": {
          "source": [
            {
              "value": "Value test"
            }
          ]
        }
      }
    }
    
  11. After the widget is published, you can view it in a visualization application.

Widget structure

`index.js` is the main program entry point, and `package.json` is the configuration file.

The main methods in the `index.js` file are as follows. For more information about other methods and configuration standards, see index.js standards.

  • `init()`: Initializes the widget.

  • `render(array: data)`: The default rendering method. This method renders the widget based on the provided data.

  • `destroy()`: Destroys the widget. This method is called when the widget is removed.

The common field standards for `package.json` are as follows. For more information about other field configuration standards, see package.json standards.

  • Widget type, name, and style definitions.

  • Interaction event standards.

  • GUI field standards.

  • Data field standards.

  • Node-based programming action field standards.

Tutorial

For information about configuring the `package.json` file, see package.json standards:

{
  "name": "@aliyun-datav_design/datav-r",        // Must be the same as the English name of the widget package.
  "version": "0.0.9",
  "dependencies": { 
    "bcore": "0.0.18",
    "jquery": "2.1.4",
    "lodash": "4.6.1"
  },
  "datav": {
    "cn_name": "datav-r",
    "icon": "",
    "protocol": 2,
    "type": [
      "regular"
    ],
    "view": {
      "width": "400",
      "height": "600",
      "minWidth": "200",
      "minHeight": "100"
    },
    "apis": {
      "source": {
        "handler": "render",
        "description": "API description",
        "fields": {
          "value": {
            "description": "Value description"
          }
        }
      }
    },
    "config": {
      "size": {
        "name": "Font size",
        "type": "number",
        "default": 22,
        "range": [
          10,
          100
        ]
      },
      "color": {
        "name": "Font color",
        "type": "color",
        "default": "#fff"
    },"path": {
      "type": "hidden",
      "default": "./resources/img.png"
    }
    },
    "events": {
      "button-click": {
        "name": "On click",
        "description": "Description for the click event",
        "type": "string"
      }
    },
    "publicHandler": {
      "setColor": {
        "name": "Change text color",
        "type": "object",
        "fields": {
          "color": {
            "name": "Text color",
            "description": "Change the text color",
            "type": "string | number",
            "default": "red"
          }
        }
      }
    },
    "api_data": {
      "source": [
        {
          "value": "Value test"
        }
      ]
    }
  }
}
Note

For more information about color configuration, see color.

For information about configuring the `index.js` file, see index.js standards:

var Event = require('bcore/event');
var $ = require('jquery');
var _ = require('lodash');
//var Chart = require('XXX');

/**
 * Basic MaLiang class
 */
module.exports = Event.extend(function Base(container, config) {
  this.config = {
    theme: {}
  }
  this.container = $(container);           // Container
  this.apis = config.apis;                 // Hooks are required.
  this._data = null;                       // Data
  this.chart = null;                       // Chart
  this.init(config);
}, {
  /**
   * Public initialization
   */
  init: function (config) {
    // 1. Initialize and merge configurations.
    this.mergeConfig(config);
    // 2. Refresh the layout. This is optional for widgets with sub-widgets.
    this.updateLayout();
    // 3. Instantiate sub-widgets.
    //this.chart = new Chart(this.container[0], this.config);
    // 4. Update the style if needed.
    this.updateStyle(); this.container.append('<div class="button">1111111</div>')
    this.button = this.container.find(".button");
//  Default style (Do not reference a global CSS style sheet in the widget. Write the style directly in JavaScript.)
      this.button.css({
        color: "#fff",
        cursor: "pointer",
      });
  },
  /**
   * Render
   * @param data
   * @param options Optional
   * !!Note: If the second parameter supports config, the updateOptions method is not required.
   */
  render: function (data, config) {
    data = this.data(data);
    var cfg = this.mergeConfig(config);
    // Update the chart.
    //this.chart.render(data, cfg);
    // this.container.html(data[0].value)
    // Update the style if needed.
    this.updateStyle(); this.button.html(_.get(data, [0, "value"]));
    // Click event (how to configure the callback ID)
    var _this = this;
    this.button.on("click", function () {
      _this.emit("button-click", {"value": $(this).html()});
      
    });
  },
  setColor: function(obj){
    this.button.css({color: obj.color})
},
  /**
   *
   * @param width
   * @param height
   */
  resize: function (width, height) {
    this.updateLayout(width, height);
    // Update the chart.
    //this.chart.render({
    //  width: width,
    //  height: height
    //})
  },
  /**
   * Each widget can obtain colors from the theme to overwrite its own configured colors as needed.
   * You can leave this empty for now.
   */
  setColors: function () {
    // For example
    //var cfg = this.config;
    //cfg.color = cfg.theme.series[0] || cfg.color;
  },
  /**
   * Data. Sets and gets data.
   * @param data
   * @returns {*|number}
   */
  data: function (data) {
    if (data) {
      this._data = data;
    }
    return this._data;
  },
  /**
   * Merge configurations.
   * Priority: config.colors > config.theme > this.config.theme > this.config.colors
   * [Note] Configurations that contain arrays must be replaced.
   * @param config
   * @private
   */
  mergeConfig: function (config) {
    if (!config) {return this.config}
    this.config.theme = _.defaultsDeep(config.theme || {}, this.config.theme);
    this.setColors();
    this.config = _.defaultsDeep(config || {}, this.config);
    return this.config;
  },
  /**
   * Update the layout.
   * Optional.
   */
  updateLayout: function () {},
  /**
   * Update the style.
   * Implement changes here that cannot be controlled by sub-widgets.
   */
  updateStyle: function () {
    var cfg = this.config;
    this.container.css({
      'font-size': cfg.size + 'px',
      'color': cfg.color || '#fff'
    });
  },
  /**
   * Update configurations.
   * !!Note: If render supports the second parameter options, updateOptions is not required.
   */
  //updateOptions: function (options) {},
  /**
   * Update certain configurations.
   * For widgets that support incremental configuration updates.
   */
  //updateXXX: function () {},
  /**
   * Destroy the widget.
   */
   destroy: function(){console.log('Implement the destroy method')}
});

FAQ

  1. How do I use CSS when developing a custom widget?

    To prevent style conflicts between widgets in a visualization application, do not create separate Cascading Style Sheets (CSS) files. Instead, modify the DOM style using JavaScript in the main program.

  2. How do I use HTML when developing a custom widget?

    You can create HTML tags in the main program by importing a separate HTML file or using a string template.

  3. How do I configure a callback ID when developing a custom widget?

    • In the `package.json` configuration file, define the events event name and parameters in the correct format under the datav field.

    • In the `index.js` main program, use the following method to send the event name and data parameters.

      this.emit(string:event_name,object: value)
      Note

      The value parameter must be an object.

    • After you enable interaction on the widget interaction panel in the visualization application, other widgets can retrieve the callback data. In the configuration of a dynamic data source for another widget, you can reference the callback data using a colon (:) followed by the parameter name.

  4. When developing a custom widget, how do I register a widget method in node-based programming?

    • In the `package.json` configuration file, define the publicHandler action name and parameters in the correct format under the datav field.

    • In the `index.js` main program, implement the code logic for the corresponding action defined in the configuration file.

  5. How do I log on to the development tool for custom widgets?

    You can log on using a username and a token. The username is your Alibaba Cloud account name, which is displayed in the upper-right corner of the DataV console. The token is the Developer Access Token.

    Note

    To obtain the developer access token, go to the DataV console homepage, choose My Assets > My Widget Packages, click Developer Access Token to copy it, and then paste it into the command line when prompted.

  6. What do I do if publishing a custom widget fails?

    Check whether the name field in the `package.json` configuration file is set to the English name of the approved widget package. This ensures that you have the required permissions to publish the widget. The correct format for the name field is @namespace/xxx. For more information about other solutions, see FAQ about custom widget development.

Video link

Video tutorial: Custom Widgets - Lesson 1.