Canvas 可拖動的波形顯示

Javascript 代碼: javascript

/*
 * Canvas line
 * Author:SongYi
 * Date:2015-06-29
 * Version:0.1
 */
(function() {
	/* ****************************************************************************
	 * Handle the options                                                         *
	 *****************************************************************************/
	var defaultOptions = {
		colors: ['#00A600', '#D94600', '#921AFF', '#E800E8', '#C6A300', '#f7a35c',
			'#8085e9', '#f15c80', '#e4d354', '#91e8e1'
		],
		datas: [],
		global: {
			width: 630,
			height: 275,
			border: true,
			borderStyle: "1px solid #000"
		},
		chart: {
			marginLeft: 80,
			marginRight: 10,
			marginTop: 5,
			marginBottom: 30,
			lineWidth: 1,
			yStep: 40,
			xStep: 60,
			yRatio: 0,
			xRatio: 0,
			yMax: 10000,
			yMin: 0,
			xMax: 0,
			xMin: 0,
			yRealMax: 0,
			yRealMin: 0
		},
		title: {
			textY: '',
			textX: '(s)',
			style: {
				color: '#000000',
				font: '11pt Arial'
			}
		},
		labels: {
			marginLeft: 25,
			marginTop: 5,
			style: {
				color: '#000000',
				font: '9pt Arial'
			}
		}
	};

	function Canvasy(userOptions) {
		var options = extend(defaultOptions, userOptions);
		this.get = function(n) {
			return options[n];
		}
		this.set = function(n, v) {
			options[n] = v;
		}
		this.init();
		this.bindEvent();
	}

	Canvasy.prototype = {
			/**
			 * Initialize the chart
			 */
			init: function() {
				var ctx = this.get("ctx");
				var global = this.get("global");
				ctx.setAttribute('width', global.width);
				ctx.setAttribute('height', global.height);
				ctx = ctx.getContext("2d");
				ctx.clearRect(0, 0, global.width, global.height);
				this.initOption();
				this.setTitleY();
				this.drawAxis();
				this.drawGridlinesX();
				this.drawGridlinesY();
				this.setAxisLabelX();
				this.setAxisLabelY();
				this.drawLines();
			},
			initOption: function() {
				var global = this.get("global");
				var chart = this.get("chart");
				var lines = this.get("datas");
				chart.baseY = global.height - chart.marginBottom;
				chart.baseX = global.width - chart.marginRight;
				chart.yStep = (global.height - chart.marginTop - chart.marginBottom) / 6;
				chart.xStep = (global.width - chart.marginLeft - chart.marginRight) / 9;
				chart.yRatio = (chart.baseY - chart.marginTop) / (chart.yMax - chart.yMin);
				chart.xRatio = (chart.baseX - chart.marginLeft) / (chart.xMax - chart.xMin);
				this.set("chart", chart);
			},
			setTitleY: function() {
				var ctx = this.get("ctx").getContext("2d");
				var chart = this.get("chart");
				ctx.save();
				ctx.rotate(-90 * Math.PI / 180);
				ctx.font = this.get("title").style.font;
				ctx.fillStyle = this.get("title").style.color;
				ctx.textAlign = 'center';
				ctx.fillText(this.get("title").textY, -80, 20);
				ctx.restore();
			},
			drawAxis: function() {
				// X axis
				var ctx = this.get("ctx").getContext("2d");
				var global = this.get("global");
				var chart = this.get("chart");
				ctx.beginPath();
				ctx.lineWidth = 2;
				ctx.strokeStyle = "#000000";
				ctx.moveTo(chart.marginLeft, global.height - chart.marginBottom);
				ctx.lineTo(global.width - chart.marginRight, global.height - chart.marginBottom);
				ctx.stroke();

				ctx.beginPath();
				ctx.lineWidth = 2;
				ctx.strokeStyle = "#000000";
				ctx.moveTo(chart.marginLeft, chart.marginTop);
				ctx.lineTo(chart.marginLeft, global.height - chart.marginBottom);
				ctx.stroke();
			},
			drawGridlinesX: function() {

				var ctx = this.get("ctx").getContext("2d");
				var height = this.get("global").height;
				var lines = this.get("datas");
				var chart = this.get("chart");
				if (typeof lines !== 'undefined' && lines.length > 0) {
					if (chart.xMax < 10 || isInteger(chart.xMax)) {
						for (var i = 2; i <= 10; i++) {
							ctx.beginPath();
							ctx.lineWidth = 1;
							ctx.strokeStyle = "#D7D7D7";
							ctx.moveTo((i - 1) * chart.xStep + chart.marginLeft, chart.marginTop);
							ctx.lineTo((i - 1) * chart.xStep + chart.marginLeft, height - chart.marginBottom);
							ctx.stroke();
						}
					} else {
						var xAxisMax = Math.floor(chart.xMax);
						for (var i = 0; i < 9; i++) {
							ctx.beginPath();
							ctx.lineWidth = 1;
							ctx.strokeStyle = "#D7D7D7";
							ctx.moveTo(chart.baseX - ((chart.xMax - xAxisMax) + i) * chart.xStep, chart.marginTop);
							ctx.lineTo(chart.baseX - ((chart.xMax - xAxisMax) + i) * chart.xStep, height - chart.marginBottom);
							ctx.stroke();
						}
					}
				}
			},
			drawGridlinesY: function() {
				var ctx = this.get("ctx").getContext("2d");
				var width = this.get("global").width;
				var chart = this.get("chart");
				for (var i = 0; i <= 5; i++) {
					ctx.beginPath();
					ctx.lineWidth = 1;
					ctx.strokeStyle = "#D7D7D7";
					ctx.moveTo(chart.marginLeft, i * chart.yStep + 5);
					ctx.lineTo(width - chart.marginRight, i * chart.yStep + 5);
					ctx.stroke();
				}

			},
			drawLines: function() {
				var ctx = this.get("ctx").getContext("2d");
				var lines = this.get("datas");
				var colors = this.get("colors");
				var chart = this.get("chart");
				var global = this.get("global");
				ctx.save();
				ctx.rect(chart.marginLeft, chart.marginTop, global.width - chart.marginLeft - chart.marginRight, global.height - chart.marginBottom - chart.marginTop);
				ctx.stroke();
				ctx.clip();
				ctx.lineCap = "round";
				if (lines !== null && typeof lines !== 'undefined') {
					for (var i = 0; i < lines.length; i++) {
						var line = lines[i];
						ctx.beginPath();
						ctx.strokeStyle = colors[i];
						for (var j = 1; j < line.data.length; j++) {
							var xPoint = line.data[j - 1];
							var point = line.data[j];
							if (line.focus) {
								ctx.lineWidth = 4 * chart.lineWidth;
							} else {
								ctx.lineWidth = chart.lineWidth;
							}

							ctx.moveTo(chart.baseX - round((chart.xMax - xPoint.x) * chart.xRatio) + line.p.X, chart.baseY - round((xPoint.y - chart.yMin) * chart.yRatio) + line.p.Y);
							ctx.lineTo(chart.baseX - round((chart.xMax - point.x) * chart.xRatio) + line.p.X, chart.baseY - round((point.y - chart.yMin) * chart.yRatio) + line.p.Y);

						}
						ctx.stroke();
					}
				}
				ctx.restore();
			},
			setAxisLabelY: function() {
				var ctx = this.get("ctx").getContext("2d");
				var chart = this.get("chart");
				var global = this.get("global");
				var labels = this.get("labels");
				ctx.font = labels.style.font;
				ctx.fillStyle = labels.style.color;
				for (var i = 0; i <= 6; i++) {
					ctx.fillText(round(chart.yRealMin + round((chart.yRealMax - chart.yRealMin) * i / 6)), labels.marginLeft, chart.baseY - i * chart.yStep + labels.marginTop);
				}
			},
			setAxisLabelX: function() {
				var ctx = this.get("ctx").getContext("2d");
				var lines = this.get("datas");
				var chart = this.get("chart");
				var labels = this.get("labels");
				var height = this.get("global").height;
				ctx.font = labels.style.font;
				ctx.fillStyle = labels.style.color;
				if (typeof lines !== 'undefined' && lines.length > 0) {
					if (chart.xMax < 10) {
						for (var i = 0; i < 10; i++) {
							ctx.fillText(i, i * chart.xStep + chart.marginLeft, height - 18);
						}
						chart.xMax = 9;
					} else {
						var xAxisMax = Math.floor(chart.xMax);
						for (var i = 0; i < 9; i++) {
							ctx.fillText(Math.floor(xAxisMax - (xAxisMax / 10) * i), chart.baseX - ((chart.xMax - xAxisMax) + i) * chart.xStep - 10, height - 18);
						}
					}
				}
				ctx.font = this.get("title").style.font;
				ctx.fillStyle = this.get("title").style.color;
				ctx.fillText(this.get("title").textX, chart.baseX - 30, height - 5);
			},
			setOptions: function(options) {
				for (var p in options) {
					this.set(p, options[p]);
				}

				this.init();
			},
			setDatas: function(datas) {
				var lines = this.get("datas");
				for (var i = 0; i < lines.length; i++) {
					lines[i].focus = datas[i].focus;
					lines[i].data = datas[i].data;
				}
				this.set("datas", lines);
				this.init();
			},
			addPoint: function(points) {
				if (points == null || points == 'undefined') {
					return;
				}
				var lines = this.get("datas");
				for (var i = 0; i < lines.length; i++) {
					if (isArray(points)) {
						for (var j = 0; j < points.length; j++) {
							if (points[j].name == lines[i].name) {
								lines[i].data.push(points[j].data);
							}
						}
					} else {
						if (points.name == lines[i].name) {
							lines[i].data.push(points.data);
						}
					}
				}
				this.set("datas", lines);

				this.init();
			},
			resize: function(width, height, drawFlag) {
				var ctx = this.get("ctx");
				var global = this.get("global");
				global.width = width;
				global.height = height;
				ctx.setAttribute('width', width);
				ctx.setAttribute('height', height);
				if (drawFlag) {
					this.init();
				} else {
					ctx = ctx.getContext("2d");
					ctx.clearRect(0, 0, width, height);
				}
			},
			setLineOffset: function(_p) {
				var lines = this.get("datas");
				for (var i = 0; i < lines.length; i++) {
					if (lines[i].focus) {
						lines[i].p = _p;
					}
				}
				this.set("datas", lines);
			},
			OnMouseDown: function(evt) {
				var X = evt.layerX;
				var Y = evt.layerY;
				if (!this.lineOffset) {
					this.lineOffset = {
						isDown: true,
						sx: X,
						sx: Y
					};
				} else {
					this.lineOffset.isDown = true;
					this.lineOffset.sx = X;
					this.lineOffset.sy = Y;
				}

			},
			OnMouseMove: function(evt) {
				if (this.lineOffset && this.lineOffset.isDown) {
					var X = evt.layerX - this.lineOffset.sx;
					var Y = evt.layerY - this.lineOffset.sy;
					this.setLineOffset({
						X: X,
						Y: Y
					});
				}
			},
			OnMouseUp: function(evt) {
				this.lineOffset.isDown = false;
				this.lineOffset.sx = 0;
				this.lineOffset.sy = 0;
			},
			OnTouchStart: function(evt) {
				var touch = event.targetTouches[0];
				if (!this.lineOffset) {
					this.lineOffset = {
						isDown: true,
						sx: touch.pageX,
						sx: touch.pageY
					};
				} else {
					this.lineOffset.isDown = true;
					this.lineOffset.sx = touch.pageX;
					this.lineOffset.sy = touch.pageY;
				}
			},
			OnTouchMove: function(evt) {
				var touch = event.targetTouches[0];
				if (this.lineOffset && this.lineOffset.isDown) {
					var X = touch.pageX - this.lineOffset.sx;
					var Y = touch.pageY - this.lineOffset.sy;
					this.setLineOffset({
						X: X,
						Y: Y
					});
				}
			},
			OnTouchEnd: function(evt) {
				this.lineOffset.isDown = false;
				this.lineOffset.sx = 0;
				this.lineOffset.sy = 0;
			},
			bindEvent: function() {
				var ctx = this.get("ctx");
				if (isMobile()) {
					ctx.addEventListener("touchstart", this.OnTouchStart.bind(this), false);
					ctx.addEventListener("touchmove", this.OnTouchMove.bind(this), false);
					ctx.addEventListener("touchend", this.OnTouchEnd.bind(this), false);
				} else {
					ctx.addEventListener("mousedown", this.OnMouseDown.bind(this), false);
					ctx.addEventListener("mousemove", this.OnMouseMove.bind(this), false);
					ctx.addEventListener("mouseup", this.OnMouseUp.bind(this), false);
				}

			}
		}
		// The Highcharts namespace
	window.Canvasy = window.Canvasy || Canvasy;

	/**
	 * Extend an object with the members of another
	 * @param {Object} a The object to be extended
	 * @param {Object} b The object to add to the first one
	 */
	var extend = Canvasy.extend = function(a, b) {
		var n;
		if (!a) {
			a = {};
		}
		for (n in b) {
			a[n] = b[n];
		}
		return a;
	};
	/**
	 * Check for string
	 * @param {Object} s
	 */
	function isString(s) {
		return typeof s === 'string';
	}
	/**
	 * Check for object
	 * @param {Object} obj
	 */
	function isObject(obj) {
		return obj && typeof obj === 'object';
	}

	function isInteger(obj) {
		return Math.floor(obj) === obj
	}
	/**
	 * Check for array
	 * @param {Object} obj
	 */
	function isArray(obj) {
		return Object.prototype.toString.call(obj) === '[object Array]';
	}
	/**
	 * Check for number
	 * @param {Object} n
	 */
	function isNumber(n) {
		return typeof n === 'number';
	}

	function round(n) {
		return Math.round(n * 100) / 100;
	}

	/**
	 * Non-recursive method to find the lowest member of an array. Math.min raises a maximum
	 * call stack size exceeded error in Chrome when trying to apply more than 150.000 points.
	 * This method is slightly slower, but safe.
	 */
	function arrayMin(data) {
		if (data == null || data.length == 0) {
			return 0;
		}
		var i = data.length,
			min = data[0];

		while (i--) {
			if (data[i] < min) {
				min = data[i];
			}
		}
		return min;
	}

	function arrayMax(data) {
		if (data == null || data.length == 0) {
			return 0;
		}
		var i = data.length,
			max = data[0];

		while (i--) {
			if (data[i] > max) {
				max = data[i];
			}
		}
		return max;
	}
	/**
	 * Provide error messages for debugging, with links to online explanation
	 */
	function error(code, stop) {
		var msg = 'Canvasy error #' + code + ': ' + code;
		if (stop) {
			throw msg;
		}
		// else ...
		if (window.console) {
			console.log(msg);
		}
	}

	function isMobile() {
		var sUserAgent = navigator.userAgent.toLowerCase();

		var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";

		var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";

		var bIsMidp = sUserAgent.match(/midp/i) == "midp";

		var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";

		var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";

		var bIsAndroid = sUserAgent.match(/android/i) == "android";

		var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";

		var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";

		if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {

			return true;

		} else {

			return false;

		}
	}

})()



Html 代碼:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>canvas</title>
    <script src="js/canvasy1.js" charset="utf-8"></script>
    <script type="text/javascript" src="js/stats.min.js"></script>
    <style media="screen">
      body{
        margin: 0 0;
        width: 100%;
      }
      input[type="checkbox"]{
        visibility: hidden;
      }
      .checkbox {
        display: inline-table;
      	width: 40px;
      	height: 40px;
      	background: #ddd;
      	margin: 10px 20px;

      	border-radius: 100%;
      	position: relative;
      	-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,0.5);
      	-moz-box-shadow: 0px 1px 3px rgba(0,0,0,0.5);
      	box-shadow: 0px 1px 3px rgba(0,0,0,0.5);
      }
      .checkbox label {
      	display: block;
      	width: 30px;
      	height: 30px;
      	border-radius: 100px;
        line-height: 30px;
        vertical-align: middle;
        color: #fff;

      	-webkit-transition: all .5s ease;
      	-moz-transition: all .5s ease;
      	-o-transition: all .5s ease;
      	-ms-transition: all .5s ease;
      	transition: all .5s ease;
      	cursor: pointer;
      	position: absolute;
      	top: 5px;
      	left: 5px;
      	z-index: 1;

      	background: #333;

      	-webkit-box-shadow:inset 0px 1px 3px rgba(0,0,0,0.5);
      	-moz-box-shadow:inset 0px 1px 3px rgba(0,0,0,0.5);
      	box-shadow:inset 0px 1px 3px rgba(0,0,0,0.5);
      }

      .checkbox input[type=checkbox]:checked + label {
      	background: #26ca28;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" width="800" height="400"></canvas>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="0" checked="checked">
      <label for="">CH1</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="1" >
      <label for="">CH2</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="2" >
      <label for="">CH3</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="3" >
      <label for="">CH4</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="4" >
      <label for="">CH5</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="5" >
      <label for="">CH6</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="6" >
      <label for="">CH7</label>
    </div>
    <div class="checkbox" onclick="checkHandle(this);">
      <input type="checkbox" name="name" value="7" >
      <label for="">CH8</label>
    </div>
    <script type="text/javascript">
    var selected = 0;
    function checkHandle(obj) {
      var items = document.getElementsByTagName("input");
      for(var i=0;items && items.length >0 && i < items.length;i++){
        items[i].checked = false;
      }
      var chb=obj.children[0];
      chb.checked = "checked";
      selected = chb.value;
    }
    var stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.right = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild(stats.domElement);

    function getDatas() {
      var data = [];
      for (i = 1; i <= 400; i++) {
        data.push({
          x: i/10,
          y: Math.random()
        });
      }
      return data;
    }

    var waveOptions = {
      ctx: document.getElementById("canvas"),
      global: {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight-100,
        border: true,
        borderStyle: "1px solid #000"
      },
      chart: {
        marginLeft: 80,
        marginRight: 10,
        marginTop: 5,
        marginBottom: 30,
        lineWidth: 1,
        yStep: 40,
        xStep: 60,
        yRatio: 0,
        xRatio: 0,
        yMax: 3,
        yMin: -3,
        xMax: 40,
        xMin: 0,
        yRealMax: 3,
        yRealMin: -3
      },
      title: {
        textY: 'wave',
        textX: '(s)',
        style: {
          color: '#000000',
          font: '12pt Arial'
        }
      },
      datas: [{
        p:{X:0,Y:0},
        focus:true,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }, {
        p:{X:0,Y:0},
        focus:false,
        data: getDatas()
      }]
    };
    waveChart = new Canvasy(waveOptions);

    setInterval(function(){
      stats.begin();
      var datas = [];
      for (var i = 0; i < waveOptions.datas.length; i++) {
        if(i == selected){
          datas.push({
            p:{X:0,Y:0},
            focus:true,
            data: getDatas()
          });
        }else{
          datas.push({
            p:{X:0,Y:0},
            focus:false,
            data: getDatas()
          });
        }
      }
      waveChart.setDatas(datas);
      stats.end();
    },40);

    </script>
  </body>
</html>



stats.js是一個JavaScript性能監控器。

這個類提供了一個簡單的信息框,幫助您監控代碼的性能。 html

  • FPS幀渲染的最後一秒。數字越高越好。 
  • MS 渲染一幀須要毫秒。數字越低就越好。

項目主頁:http://www.open-open.com/lib/view/home/1414374727419 java

源碼:https://github.com/mrdoob/stats.js android

相關文章
相關標籤/搜索