%PDF- %PDF-
Direktori : /home/opti/workflow/src/public/app-assets/vendors/js/charts/echarts/zrender/graphic/ |
Current File : /home/opti/workflow/src/public/app-assets/vendors/js/charts/echarts/zrender/graphic/Path.js |
/** * Path element * @module zrender/graphic/Path */ define(function (require) { var Displayable = require('./Displayable'); var zrUtil = require('../core/util'); var PathProxy = require('../core/PathProxy'); var pathContain = require('../contain/path'); var Gradient = require('./Gradient'); function pathHasFill(style) { var fill = style.fill; return fill != null && fill !== 'none'; } function pathHasStroke(style) { var stroke = style.stroke; return stroke != null && stroke !== 'none' && style.lineWidth > 0; } var abs = Math.abs; /** * @alias module:zrender/graphic/Path * @extends module:zrender/graphic/Displayable * @constructor * @param {Object} opts */ function Path(opts) { Displayable.call(this, opts); /** * @type {module:zrender/core/PathProxy} * @readOnly */ this.path = new PathProxy(); } Path.prototype = { constructor: Path, type: 'path', __dirtyPath: true, strokeContainThreshold: 5, brush: function (ctx) { ctx.save(); var style = this.style; var path = this.path; var hasStroke = pathHasStroke(style); var hasFill = pathHasFill(style); var hasFillGradient = hasFill && !!(style.fill.colorStops); var hasStrokeGradient = hasStroke && !!(style.stroke.colorStops); style.bind(ctx, this); this.setTransform(ctx); if (this.__dirtyPath) { var rect = this.getBoundingRect(); // Update gradient because bounding rect may changed if (hasFillGradient) { this._fillGradient = style.getGradient(ctx, style.fill, rect); } if (hasStrokeGradient) { this._strokeGradient = style.getGradient(ctx, style.stroke, rect); } } // Use the gradient if (hasFillGradient) { ctx.fillStyle = this._fillGradient; } if (hasStrokeGradient) { ctx.strokeStyle = this._strokeGradient; } var lineDash = style.lineDash; var lineDashOffset = style.lineDashOffset; var ctxLineDash = !!ctx.setLineDash; // Update path sx, sy var scale = this.getGlobalScale(); path.setScale(scale[0], scale[1]); // Proxy context // Rebuild path in following 2 cases // 1. Path is dirty // 2. Path needs javascript implemented lineDash stroking. // In this case, lineDash information will not be saved in PathProxy if (this.__dirtyPath || ( lineDash && !ctxLineDash && hasStroke )) { path = this.path.beginPath(ctx); // Setting line dash before build path if (lineDash && !ctxLineDash) { path.setLineDash(lineDash); path.setLineDashOffset(lineDashOffset); } this.buildPath(path, this.shape); // Clear path dirty flag this.__dirtyPath = false; } else { // Replay path building ctx.beginPath(); this.path.rebuildPath(ctx); } hasFill && path.fill(ctx); if (lineDash && ctxLineDash) { ctx.setLineDash(lineDash); ctx.lineDashOffset = lineDashOffset; } hasStroke && path.stroke(ctx); // Draw rect text if (style.text != null) { // var rect = this.getBoundingRect(); this.drawRectText(ctx, this.getBoundingRect()); } ctx.restore(); }, buildPath: function (ctx, shapeCfg) {}, getBoundingRect: function () { var rect = this._rect; var style = this.style; var needsUpdateRect = !rect; if (needsUpdateRect) { var path = this.path; if (this.__dirtyPath) { path.beginPath(); this.buildPath(path, this.shape); } rect = path.getBoundingRect(); } this._rect = rect; if (pathHasStroke(style)) { // Needs update rect with stroke lineWidth when // 1. Element changes scale or lineWidth // 2. Shape is changed var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone()); if (this.__dirty || needsUpdateRect) { rectWithStroke.copy(rect); // FIXME Must after updateTransform var w = style.lineWidth; // PENDING, Min line width is needed when line is horizontal or vertical var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Only add extra hover lineWidth when there are no fill if (!pathHasFill(style)) { w = Math.max(w, this.strokeContainThreshold); } // Consider line width // Line scale can't be 0; if (lineScale > 1e-10) { rectWithStroke.width += w / lineScale; rectWithStroke.height += w / lineScale; rectWithStroke.x -= w / lineScale / 2; rectWithStroke.y -= w / lineScale / 2; } } // Return rect with stroke return rectWithStroke; } return rect; }, contain: function (x, y) { var localPos = this.transformCoordToLocal(x, y); var rect = this.getBoundingRect(); var style = this.style; x = localPos[0]; y = localPos[1]; if (rect.contain(x, y)) { var pathData = this.path.data; if (pathHasStroke(style)) { var lineWidth = style.lineWidth; var lineScale = style.strokeNoScale ? this.getLineScale() : 1; // Line scale can't be 0; if (lineScale > 1e-10) { // Only add extra hover lineWidth when there are no fill if (!pathHasFill(style)) { lineWidth = Math.max(lineWidth, this.strokeContainThreshold); } if (pathContain.containStroke( pathData, lineWidth / lineScale, x, y )) { return true; } } } if (pathHasFill(style)) { return pathContain.contain(pathData, x, y); } } return false; }, /** * @param {boolean} dirtyPath */ dirty: function (dirtyPath) { if (arguments.length ===0) { dirtyPath = true; } // Only mark dirty, not mark clean if (dirtyPath) { this.__dirtyPath = dirtyPath; this._rect = null; } this.__dirty = true; this.__zr && this.__zr.refresh(); // Used as a clipping path if (this.__clipTarget) { this.__clipTarget.dirty(); } }, /** * Alias for animate('shape') * @param {boolean} loop */ animateShape: function (loop) { return this.animate('shape', loop); }, // Overwrite attrKV attrKV: function (key, value) { // FIXME if (key === 'shape') { this.setShape(value); } else { Displayable.prototype.attrKV.call(this, key, value); } }, /** * @param {Object|string} key * @param {*} value */ setShape: function (key, value) { var shape = this.shape; // Path from string may not have shape if (shape) { if (zrUtil.isObject(key)) { for (var name in key) { shape[name] = key[name]; } } else { shape[key] = value; } this.dirty(true); } return this; }, getLineScale: function () { var m = this.transform; // Get the line scale. // Determinant of `m` means how much the area is enlarged by the // transformation. So its square root can be used as a scale factor // for width. return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1; } }; /** * 扩展一个 Path element, 比如星形,圆等。 * Extend a path element * @param {Object} props * @param {string} props.type Path type * @param {Function} props.init Initialize * @param {Function} props.buildPath Overwrite buildPath method * @param {Object} [props.style] Extended default style config * @param {Object} [props.shape] Extended default shape config */ Path.extend = function (defaults) { var Sub = function (opts) { Path.call(this, opts); if (defaults.style) { // Extend default style this.style.extendFrom(defaults.style, false); } // Extend default shape var defaultShape = defaults.shape; if (defaultShape) { this.shape = this.shape || {}; var thisShape = this.shape; for (var name in defaultShape) { if ( ! thisShape.hasOwnProperty(name) && defaultShape.hasOwnProperty(name) ) { thisShape[name] = defaultShape[name]; } } } defaults.init && defaults.init.call(this, opts); }; zrUtil.inherits(Sub, Path); // FIXME 不能 extend position, rotation 等引用对象 for (var name in defaults) { // Extending prototype values and methods if (name !== 'style' && name !== 'shape') { Sub.prototype[name] = defaults[name]; } } return Sub; }; zrUtil.inherits(Path, Displayable); return Path; });