/** * zrender * * @author Kener (@Kener-林峰, kener.linfeng@gmail.com) * Yi Shen(https://github.com/pissang) * * shape类:标线 */ /** * @typedef {Object} IMarkLineStyle * @property {number} xStart 起点x坐标 * @property {number} yStart 起点y坐标 * @property {number} xEnd 终止点x坐标 * @property {number} yEnd 终止点y坐标 * @property {number} cpX1 控制点x坐标,可以使用updatePoints自动根据curveness计算 * @property {number} cpY1 控制点y坐标,可以使用updatePoints自动根据curveness计算 * @property {number} curveness 曲度 * @property {Array.} symbol * @property {Array.} symbolRotate */ define(function (require) { var Base = require('zrender/shape/Base'); var IconShape = require('./Icon'); var LineShape = require('zrender/shape/Line'); var lineInstance = new LineShape({}); var CurveShape = require('zrender/shape/BezierCurve'); var curveInstance = new CurveShape({}); var area = require('zrender/tool/area'); var dashedLineTo = require('zrender/shape/util/dashedLineTo'); var zrUtil = require('zrender/tool/util'); var curveTool = require('zrender/tool/curve'); function MarkLine(options) { Base.call(this, options); if (this.style.curveness > 0) { this.updatePoints(this.style); } if (this.highlightStyle.curveness > 0) { this.updatePoints(this.highlightStyle); } } MarkLine.prototype = { type : 'mark-line', /** * 画刷 * @param ctx 画布句柄 * @param isHighlight 是否为高亮状态 * @param updateCallback 让painter更新视图,base.brush没用,需要的话重载brush */ brush : function (ctx, isHighlight) { var style = this.style; if (isHighlight) { // 根据style扩展默认高亮样式 style = this.getHighlightStyle( style, this.highlightStyle || {} ); } ctx.save(); this.setContext(ctx, style); // 设置transform this.setTransform(ctx); ctx.save(); ctx.beginPath(); this.buildPath(ctx, style); ctx.stroke(); ctx.restore(); this.brushSymbol(ctx, style, 0); this.brushSymbol(ctx, style, 1); this.drawText(ctx, style, this.style); ctx.restore(); }, /** * 创建线条路径 * @param {Context2D} ctx Canvas 2D上下文 * @param {Object} style 样式 */ buildPath : function (ctx, style) { var lineType = style.lineType || 'solid'; ctx.moveTo(style.xStart, style.yStart); if (style.curveness > 0) { // FIXME Bezier 在少部分浏览器上暂时不支持虚线 var lineDash = null; switch (lineType) { case 'dashed': lineDash = [5, 5]; break; case'dotted': lineDash = [1, 1]; break; } if (lineDash && ctx.setLineDash) { ctx.setLineDash(lineDash); } ctx.quadraticCurveTo( style.cpX1, style.cpY1, style.xEnd, style.yEnd ); } else { if (lineType == 'solid') { ctx.lineTo(style.xEnd, style.yEnd); } else { var dashLength = (style.lineWidth || 1) * (style.lineType == 'dashed' ? 5 : 1); dashedLineTo( ctx, style.xStart, style.yStart, style.xEnd, style.yEnd, dashLength ); } } }, /** * Update cpX1 and cpY1 according to curveniss * @param {Object} style */ updatePoints: function (style) { var curveness = style.curveness || 0; var inv = 1; var x0 = style.xStart; var y0 = style.yStart; var x2 = style.xEnd; var y2 = style.yEnd; var x1 = (x0 + x2) / 2 - inv * (y0 - y2) * curveness; var y1 =(y0 + y2) / 2 - inv * (x2 - x0) * curveness; style.cpX1 = x1; style.cpY1 = y1; }, /** * 标线始末标注 */ brushSymbol : function (ctx, style, idx) { if (style.symbol[idx] == 'none') { return; } ctx.save(); ctx.beginPath(); ctx.lineWidth = style.symbolBorder; ctx.strokeStyle = style.symbolBorderColor; // symbol var symbol = style.symbol[idx].replace('empty', '') .toLowerCase(); if (style.symbol[idx].match('empty')) { ctx.fillStyle = '#fff'; //'rgba(0, 0, 0, 0)'; } // symbolRotate var x0 = style.xStart; var y0 = style.yStart; var x2 = style.xEnd; var y2 = style.yEnd; var x = idx === 0 ? x0 : x2; var y = idx === 0 ? y0 : y2; var curveness = style.curveness || 0; var rotate = style.symbolRotate[idx] != null ? (style.symbolRotate[idx] - 0) : 0; rotate = rotate / 180 * Math.PI; if (symbol == 'arrow' && rotate === 0) { if (curveness === 0) { var sign = idx === 0 ? -1 : 1; rotate = Math.PI / 2 + Math.atan2( sign * (y2 - y0), sign * (x2 - x0) ); } else { var x1 = style.cpX1; var y1 = style.cpY1; var quadraticDerivativeAt = curveTool.quadraticDerivativeAt; var dx = quadraticDerivativeAt(x0, x1, x2, idx); var dy = quadraticDerivativeAt(y0, y1, y2, idx); rotate = Math.PI / 2 + Math.atan2(dy, dx); } } ctx.translate(x, y); if (rotate !== 0) { ctx.rotate(rotate); } // symbolSize var symbolSize = style.symbolSize[idx]; IconShape.prototype.buildPath(ctx, { x: -symbolSize, y: -symbolSize, width: symbolSize * 2, height: symbolSize * 2, iconType: symbol }); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.restore(); }, /** * 返回矩形区域,用于局部刷新和文字定位 * @param {Object} style */ getRect : function (style) { style.curveness > 0 ? curveInstance.getRect(style) : lineInstance.getRect(style); return style.__rect; }, isCover : function (x, y) { var originPos = this.transformCoordToLocal(x, y); x = originPos[0]; y = originPos[1]; // 快速预判并保留判断矩形 if (this.isCoverRect(x, y)) { // 矩形内 return this.style.curveness > 0 ? area.isInside(curveInstance, this.style, x, y) : area.isInside(lineInstance, this.style, x, y); } return false; } }; zrUtil.inherits(MarkLine, Base); return MarkLine; });