上文提到计划开发的一个支持用户扩展的开放设计器平台,它基于Html5,纯JS,考虑到方便用户进行引用和扩展,定义成一个单独的js组件的形式,本文重点就如何设计JS组件做一个详细说明。

设计组件前,我们先要思考组件如何初始化,首先既然是图形化的,那就必须用到HTML5的Canvas元素,开发人员先在页面上建一个canvas作为设计器组件的宿主,在组件$(function(){...})执行时,调用组件的初始化方法(init),然后依据初始化显示的内容再在画布上面进行渲染(render)。

第一种组件写法:全局Javascript 对象法

我们知道Javascript里所有对象定义是以大括号来定义的{}的,那我们visualDesigner.1.0可以定义为:

var visualDesigner = {
    mode:1, //设计时/运行时
    container: "", //容器id
    content: {}, //内容
    init: function (config) {
        this.container = config.id;
        this.mode = config.runMode;
        if (config.content)
            this.content = JSON.parse(config.content); //默认初始化时加载的内容
        this.render();
    },
    render: function () {
        if (this.content && this.content.text)
        {
            $("#" + this.container).html(this.content.text);
        }
    },
    save: function () {
        //保存content
    },
    open: function (content) {
        //通常保存到本地或数据库时以字符串形式存在的,故需转成对象。
        if (content) 
            this.content = JSON.parse(content);
        else
            console.log("open方法打开的content不能为空");
        this.render();
    }
}
var runMode = { designTime: 1, runTime: 2 };

可以这样调用:

    $(function () {
        visualDesigner.init({ id: "designView", runMode: runMode.designTime, content: "{\"text\":\"hello world\"}" });
    })

这种方法最大的问题是所有的属性或方法都是公有的,如果代码方法和属性比较多时,比较难以维护,面向对象设计时一个重要的原则是开放-封闭原则,而这样的设计完全违背了这个原则。

第二种组件写法:JQuery组件写法

jquery组件的写法第一种是通过标记的形式,比如在容器上标记 data-toggle=“designerView",然后在document.ready时组件函数自动调用初始化(init)

另一种写法是通过在组件里document.ready或等价的(fucntion(){...})(jQuery)函数里手动调用对象的init初始化,一些jquery插件如bootstrap的组件、jquery.validator等都是基于这种方法。

    $(function () {
        $("#designView").visualDesigner("init", { model: runMode.designTime, content: "{\"text\":\"hello world\"}" });
    })

以下为visualDesigner.2.0定义:

+function ($) {
    "use strict";

    // VisualDesigner 公共类定义
    // ===============================
    var VisualDesigner = function (element, options) {
        this.init(element, options)
    }
    if (!paper) throw new Error('VisualDesigner requires paper.js')
    VisualDesigner.DEFAULTS = $.extend({},{
        content: '',
        color: "red",
        font_color: "yellow",
        opacity:0.5
    })
    VisualDesigner.prototype.init = function (element, options) {
        this.enabled = true
        this.$element = $(element)
        this.htmlCanvas = element instanceof jQuery? element[0] : element;
        this.options = this.getOptions(options)
        //初始化设计器代码
        this.canvas = paper.setup(this.htmlCanvas.id);
        //this.canvas.project.view.viewSize = new paper.Size(this.options.width, this.options.height);
        this.options = $.extend({ 'raster': 0 }, this.options || {});
        this.originalPoint = this.canvas.project.view.center;//保留中心
        this.centerPoint = { x: 0, y: 0 };

        this.group = new paper.Group();
        var fillColor = this.options.color;
        var fontColor = this.options.font_color;
        var rect = new paper.Path.Rectangle({
            point: [50,50],
            size: [100,100],
            radius: 5,
            strokeWidth: 1,
            strokeColor: this.options.color,
            fillColor: this.options.color,
            opacity: this.node_opacity
        });
        this.group.addChild(rect);
    }

    // NOTE: VisualDesigner 原型定义
    // ================================
    VisualDesigner.prototype.constructor = VisualDesigner
    VisualDesigner.prototype.getDefaults = function () {
        return VisualDesigner.DEFAULTS
    }
    VisualDesigner.prototype.getOptions = function (options) {
        options = $.extend({}, this.getDefaults(), this.$element.data(), options)
        return options;
    }
    VisualDesigner.prototype.render = function (content) {
        //此处为渲染内容的代码
    }
    VisualDesigner.prototype.open = function (content) {
        //此处打开操作:清除原来内容,并渲染新内容的代码
        this.render(content);
    }
    VisualDesigner.prototype.save = function (saveFunc) {
        //此处获取当前内容,并回调保存代码,回调的参数包含了当前内容
        saveFunc(this.getContent());
    }
    VisualDesigner.prototype.hasContent = function () {
        return this.getTitle() || this.getContent()
    }
    VisualDesigner.prototype.getContent = function () {
        var $e = this.$element
        var o = this.options

        return $e.attr('data-content')
            || (typeof o.content == 'function' ?
                o.content.call($e[0]) :
                o.content)
    }
    debugger;
    var old = $.fn.visualDesigner
    // VisualDesigner 插件定义,扩展jquery函数
    // =========================
    $.fn.visualDesigner = function (option) {
        debugger;
        return new VisualDesigner(this, option);
    }
    $.fn.visualDesigner.Constructor = VisualDesigner
    // visualDesigner 非冲突
    // ===================
    $.fn.visualDesigner.noConflict = function () {
        $.fn.visualDesigner = old
        return this
    }

}($);


var runMode = { designTime: 1, runTime: 2 };

 

注意上面代码的几个知识点

  • +function($){...}($);的写法和(funtion ($) {}) ($);是一致的,即先定义一个匿名函数,并调用,和var a=function($){}; a($);是等价的。
  • jquery通过$.fn来扩展方法,可以通过$.fn.extend({funcName:function(){}});的形式或者$.fn.funcName=function(){};的方法直接赋值。

一旦定义好了方法jquery组件,我们可以通过以下方法实例化:

    //html:    

     <canvas style="height:300px;width:300px;background-color:gray" id="designView"></canvas>

    //script:
    var view = $("#designView").visualDesigner({ model: runMode.designTime, content: "{\"text\":\"hello world\"}" }); view.open("");

页面呈现的效果如图(初始化时画了一个圆角矩形):

本节js组件就到这里,后续会对javascript的封装和继承等再做示例,欢迎继续关注。

源代码:visualDesigner1.0.rar

直接运行查看

(本文为原创,在引用代码和文字时请注明出处)

 
关键字
:设计器源代码,Web设计器,工作流设计器,jQuery插件,组态设计器,SCADA系统设计器,流程图设计,表单设计建模,报表设计,可视化,设计时,运行时,轻量级开放平台。