zoukankan      html  css  js  c++  java
  • 微信图片上添加昵称等信息拖动移动位置

    调用 

    var oImg = document.getElementById("cropPosterImg");
    fnImageCropRot(oImg);
    

      

    下载地址:http://www.zhangxinxu.com/study/down/jquery_jcrop_zh.zip

    crop_rotation/zxx.crop_rotation.js

    // zxx.crop_rotation.js by zhangxinxu  welcome to visit my personal website http://www.zhangxinxu.com/
    // 2010-05-06 v1.0 beta
    // 图片剪裁旋转前端展示
    /*一些说明:
    * 1. 旋转效果查看需通过在角度文本框中输入数值
    * 2. 后台处理图片需要5个参数,剪裁起始点,以及剪裁的高宽,这5个参数均可以通过id获取。其中角度值即旋转角度输入框的值,id为zxxRotAngle,坐标及高宽参数分别藏在4个隐藏的文本框中,id分别是:cropPosX, cropPosY, cropImageWidth, cropImageHeight
    * 3. 自动对比当前图片与原始图片尺寸比例,计算实际的剪裁值,对于高度及位置溢出也做了处理
    * 4. 如果出现由于图片旋转而发生遮挡的现象,设置遮挡元素的position属性为relative,z-index为1,可修复此问题
    * 5. 经我测试,excanvas.js需在头部加载以支持IE浏览器的canvas
    */
    var fnImageCropRot = function(o){
    	//o为图片对象
    	if(typeof(o) === "object" && o.nodeName.toLowerCase() === "img"){//检测是否是图片类型的DOM对象
    		//当前显示图片的高度和宽度
    		var iCurWidth = o.width, iCurHeight = o.height;
    		o.height = iCurHeight;
    		//获取实际图片的高宽
    		var oCreateImg = new Image();
    		oCreateImg.src = o.src;
    		var iOrigWidth = oCreateImg.width, iOrigHeight = oCreateImg.height;
    
    		if(iCurWidth && iOrigWidth){//如果宽度为不为0 - 意味着加载成功
    			//计算当前与实际的纵横比
    			var scaleX = iCurWidth / iOrigWidth;
    			var scaleY = iCurHeight / iOrigHeight;
    			//实现图片对象的包裹
    			//创建包裹div
    			var oRelDiv = document.createElement("div");
    			oRelDiv.style.position = "relative";
    			oRelDiv.style.width = iCurWidth + "px";
    			oRelDiv.style.height = iCurHeight + 30 + "px";
    			oRelDiv.style.top = "30px";
    			//定义ID方法
    			var ID = function(id){
    				return document.getElementById(id);
    			};
    			//插入到当前图片对象之前
    			o.parentNode.insertBefore(oRelDiv, o);
    			//初始化坐标与剪裁高宽
    			var cropW = ID("ncropImageWidth").value;
    			var cropH = ID("ncropImageHeight").value;
    			var posX = ID("ncropPosX").value;
    			var posY = ID("ncropPosY").value;
    			var qrimg = ID("ncropQrcodeimg").value;
    			var nameTextX = ID("label_name_x").value;
    			var nameTexty = ID("label_name_y").value;
    			var nameTextSize = ID("label_name_fsize").value;
    			var addressTextx = ID("label_address_x").value;
    			var addressTexty = ID("label_address_y").value;
    			var addressTextSize = ID("label_address_fsize").value;
    			var avatarImg = ID("avatarImg").value;
    			var avatarx = ID("label_avatar_x").value;
    			var avatary = ID("label_avatar_y").value;
    			//剪裁需要的HTML元素
    			var sInnerHtml = '<div style="font-size:12px; position:absolute; top:-24px; right:0;"><input id="zxxRotAngle" type="hidden" value="0" style="38px; height:15px; border:1px solid #a0b3d6; font-size:100%; padding:2px 0 1px 2px; margin-right:3px; color:#333333;" /><a scr="javascript:;" id="fnRefresh">刷新</a></div>'
    			+'<canvas id="zxxImageCanvas" style="position:absolute;"></canvas>'
    			+'<div id="zxxCropBox" style="height:'+cropH+'px; '+cropW+'px; position:absolute; left:'+posX+'px; top:'+posY+'px; border:1px solid black;">'
    				+'<div id="zxxDragBg" style="height:100%;background: #ebedf0 url('+qrimg+') no-repeat;background-size:100%; cursor:move;"></div>'
    				+'<div id="dragLeftTop" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; top:-3px; cursor:nw-resize;"></div>'
    				+'<div id="dragLeftBot" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; bottom:-3px; cursor:sw-resize;"></div>'
    				+'<div id="dragRightTop" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; top:-3px; cursor:ne-resize;"></div>'
    				+'<div id="dragRightBot" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; bottom:-3px; cursor:se-resize;"></div>'
    				+'<div id="dragTopCenter" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; top:-3px; left:50%; margin-left:-3px; cursor:n-resize;"></div>'
    				+'<div id="dragBotCenter" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; bottom:-3px; left:50%; margin-left:-3px; cursor:s-resize;"></div>'
    				+'<div id="dragRightCenter" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; top:50%; margin-top:-3px; cursor:e-resize;"></div>'
    				+'<div id="dragLeftCenter" style="position:absolute; 4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; top:50%; margin-top:-3px; cursor:w-resize;"></div>'
    			+'</div>'
    			+'<div id="labelName" style="position:absolute; left:'+nameTextX+'px; top:'+nameTexty+'px; font-size: '+nameTextSize+'px;font-family: simhei;"><div id="labelNameDrag" style="cursor:move;">昵称拖动试试</div></div>'
    			+'<span id="labelAddress" style="position:absolute; left:'+addressTextx+'px; top:'+addressTexty+'px; font-size: '+addressTextSize+'px;color: #666666;font-family: simhei;"><span id="labelAddressDrag" style="cursor:move;color:#999">江苏 徐州</span></span>'
    			+'<span id="labelAvatar" style="position:absolute; left:'+avatarx+'px; top:'+avatary+'px;"><img id="labelAvatarDrag" style="cursor:move;-moz-border-radius: 300px; -webkit-border-radius: 300px; 110px;" src="'+avatarImg+'"/></span>';
    			//嵌入HTML元素
    			oRelDiv.innerHTML = sInnerHtml;
    			//图片重新插入
    			var oCanvas = ID("zxxImageCanvas");
    			if(window.ActiveXObject){
    				//IE
    				oCanvas = window.G_vmlCanvasManager.initElement(oCanvas); //使IE支持动态创建的canvas元素
    			}
    			oRelDiv.insertBefore(o, oCanvas);
    			//---------------------------图片包裹装载完毕-----------------------
    
    			var fnCanvasRotate = function(canvas,img,rot){//canvas旋转角度的方法
    				//获取图片的高宽
    				var w = iCurWidth;
    				var h = iCurHeight;
    				//角度转为弧度
    				if(!rot){
    					rot = 0;	
    				}
    				var rotation = Math.PI * rot / 180;
    				var c = Math.round(Math.cos(rotation) * 1000) / 1000;
    				var s = Math.round(Math.sin(rotation) * 1000) / 1000;
    				//旋转后canvas标签的大小
    				canvas.height = Math.abs(c*h) + Math.abs(s*w);
    				canvas.width = Math.abs(c*w) + Math.abs(s*h);
    				//绘图开始
    				var context = canvas.getContext("2d");
    				context.save();
    				//改变中心点
    				if (rotation <= Math.PI/2) {
    					context.translate(s*h,0);
    				} else if (rotation <= Math.PI) {
    					context.translate(canvas.width,-c*h);
    				} else if (rotation <= 1.5*Math.PI) {
    					context.translate(-c*w,canvas.height);
    				} else {
    					context.translate(0,-s*w);
    				}
    				//旋转90°
    				context.rotate(rotation);
    				//绘制
    				context.drawImage(img, 0, 0, w, h);
    				context.restore();
    				img.style.display = "none";	
    			};
    			//侦听旋转角度输入框
    			ID("zxxRotAngle").onkeyup = function(){
    				var v = parseInt(this.value, 10);
    				if(!v){
    					v = 0;
    				}
    				//执行角度旋转
    				fnCanvasRotate(oCanvas, o, v);
    			};
    
    			//拖拽与拉伸方法
    			//拖拽拉伸所需参数
    			var params = {
    				left: 0,
    				top: 0,
    				0,
    				height:0,
    				currentX: 0,
    				currentY: 0,
    				flag: false,
    				kind: "drag",
    				activePoint: false
    			};
    
    			//获取相关CSS属性方法
    			var getCss = function(o,key){
    				return o.currentStyle? o.currentStyle[key] : document.defaultView.getComputedStyle(o,false)[key]; 	
    			};
    			var startDrag = function(point, target, kind){	
    				//point是拉伸点,target是被拉伸的目标,其高度及位置会发生改变
    				//此处的target与上面拖拽的target是同一目标,故其params.left,params.top可以共用,也必须共用
    				//初始化宽高
    				params.width = getCss(target, "width");
    				params.height = getCss(target, "height");
    				//初始化坐标
    				if(getCss(target, "left") !== "auto"){
    					params.left = getCss(target, "left");
    				}
    				if(getCss(target, "top") !== "auto"){
    					params.top = getCss(target, "top");
    				}
    				//target是移动对象
    				point.onmousedown = function(event){
    					params.kind = kind;
    					params.flag = true;
    					if(!event){
    						event = window.event;
    					}
    					var e = event;
    
    					//焦点放到当前拖拽的对象
    					params.activePoint = target;
    					params.left = getCss(target, "left");
    					params.top = getCss(target, "top");
    
    					params.currentX = e.clientX;
    					params.currentY = e.clientY;
    					//防止IE文字选中,有助于拖拽平滑
    					point.onselectstart = function(){
    						return false;
    					}
    				};
    				document.onmouseup = function(){
    					params.flag = false;
    					if(getCss(params.activePoint, "left") !== "auto"){
    						params.left = getCss(params.activePoint, "left");
    					}
    					if(getCss(params.activePoint, "top") !== "auto"){
    						params.top = getCss(params.activePoint, "top");
    					}
    
    					if(params.activePoint.id=="labelName"){
    						//给隐藏文本框赋值
    						posX = parseInt(params.activePoint.style.left);
    						posY = parseInt(params.activePoint.style.top);
    						ID("label_name_x").value = posX;
    						ID("label_name_y").value = posY;
    						return;
    					}else if(params.activePoint.id=="labelAddress"){
    						//给隐藏文本框赋值
    						posX = parseInt(params.activePoint.style.left);
    						posY = parseInt(params.activePoint.style.top);
    						ID("label_address_x").value = posX;
    						ID("label_address_y").value = posY;
    						return;
    					}else if(params.activePoint.id=="labelAvatar"){
    						//给隐藏文本框赋值
    						posX = parseInt(params.activePoint.style.left);
    						posY = parseInt(params.activePoint.style.top);
    						ID("label_avatar_x").value = posX;
    						ID("label_avatar_y").value = posY;
    						return;
    					}
    
    					params.width = getCss(params.activePoint, "width");
    					params.height = getCss(params.activePoint, "height");
    
    					//给隐藏文本框赋值
    					posX = parseInt(params.activePoint.style.left);
    					posY = parseInt(params.activePoint.style.top);
    					cropW = parseInt(params.activePoint.style.width);
    					cropH = parseInt(params.activePoint.style.height);
    					if(posX < 0){
    						posX = 0;	
    					}
    					if(posY < 0){
    						posY = 0;
    					}
    					if((posX + cropW) > iCurWidth){
    						cropW = iCurWidth - posX;	
    					}
    					if((posY + cropH) > iCurHeight){
    						cropH = iCurHeight - posY;	
    					}
    					//比例计算
    					posX = posX / scaleX;
    					posY /= scaleY;
    					cropW /= scaleX;
    					cropH /= scaleY;
    					//赋值
    					ID("ncropPosX").value = posX;
    					ID("ncropPosY").value = posY;
    					ID("ncropImageWidth").value = cropW;
    					ID("ncropImageHeight").value = cropH;
    				};
    				document.onmousemove = function(event){
    					var e = event ? event: window.event;
    					if(params.flag){
    						var nowX = e.clientX, nowY = e.clientY;
    						var disX = nowX - params.currentX, disY = nowY - params.currentY;
    						if(params.kind === "n"){
    							//上拉伸
    							//高度增加或减小,位置上下移动
    							target.style.height = parseInt(params.height) - disY + "px";
    							target.style.width = parseInt(params.width) - disY + "px";
    						}else if(params.kind === "w"){//左拉伸
    							target.style.left = parseInt(params.left) + disX + "px";
    							target.style.width = parseInt(params.width) - disX + "px";
    							target.style.height = parseInt(params.height) - disX + "px";
    						}else if(params.kind === "e"){//右拉伸
    							target.style.width = parseInt(params.width) + disX + "px";
    							target.style.height = parseInt(params.height) + disX + "px";
    						}else if(params.kind === "s"){//下拉伸
    							target.style.height = parseInt(params.height) + disY + "px";
    							target.style.width = parseInt(params.width) + disY + "px";
    						}else if(params.kind === "nw"){//左上拉伸
    							target.style.left = parseInt(params.left) + disX + "px";
    							target.style.width = parseInt(params.width) - disX + "px";
    							target.style.top = parseInt(params.top) + disX + "px";
    							target.style.height = parseInt(params.height) - disX + "px";
    						}else if(params.kind === "ne"){//右上拉伸
    							target.style.top = parseInt(params.top) + disY + "px";
    							target.style.height = parseInt(params.height) - disY + "px";
    							//右
    							target.style.width = parseInt(params.width) - disY + "px";
    						}else if(params.kind === "sw"){//左下拉伸
    							target.style.left = parseInt(params.left) + disX + "px";
    							target.style.width = parseInt(params.width) - disX + "px";
    							//下
    							target.style.height = parseInt(params.height) - disX + "px";
    						}else if(params.kind === "se"){//右下拉伸
    							target.style.width = parseInt(params.width) + disX + "px";
    							target.style.height = parseInt(params.height) + disX + "px";
    						}else{//移动
    							params.activePoint.style.left = parseInt(params.left) + disX + "px";
    							params.activePoint.style.top = parseInt(params.top) + disY + "px";
    						}
    					}
    				}
    			};
    
    			//绑定拖拽
    			startDrag(ID("zxxDragBg"),ID("zxxCropBox"),"drag");
    			startDrag(ID("labelNameDrag"),ID("labelName"),"drag");
    			startDrag(ID("labelAddressDrag"),ID("labelAddress"),"drag");
    			startDrag(ID("labelAvatarDrag"),ID("labelAvatar"),"drag");
    			//绑定拉伸
    			startDrag(ID("dragLeftTop"),ID("zxxCropBox"),"nw");
    			startDrag(ID("dragLeftBot"),ID("zxxCropBox"),"sw");
    			startDrag(ID("dragRightTop"),ID("zxxCropBox"),"ne");
    			startDrag(ID("dragRightBot"),ID("zxxCropBox"),"se");
    			startDrag(ID("dragTopCenter"),ID("zxxCropBox"),"n");
    			startDrag(ID("dragBotCenter"),ID("zxxCropBox"),"s");
    			startDrag(ID("dragRightCenter"),ID("zxxCropBox"),"e");
    			startDrag(ID("dragLeftCenter"),ID("zxxCropBox"),"w");
    
    			//图片不能被选中,目的在于使拖拽顺滑
    			ID("zxxImageCanvas").onselectstart = function(){
    				return false;
    			};
    			o.onselectstart = function(){
    				return false;
    			};
    		}//if end
    	}//if end
    };
    

      excanvas.js

    // Copyright 2006 Google Inc.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    
    // Known Issues:
    //
    // * Patterns are not implemented.
    // * Radial gradient are not implemented. The VML version of these look very
    //   different from the canvas one.
    // * Clipping paths are not implemented.
    // * Coordsize. The width and height attribute have higher priority than the
    //   width and height style values which isn't correct.
    // * Painting mode isn't implemented.
    // * Canvas width/height should is using content-box by default. IE in
    //   Quirks mode will draw the canvas using border-box. Either change your
    //   doctype to HTML5
    //   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
    //   or use Box Sizing Behavior from WebFX
    //   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
    // * Non uniform scaling does not correctly scale strokes.
    // * Optimize. There is always room for speed improvements.
    
    // Only add this code if we do not already have a canvas implementation
    if (!document.createElement('canvas').getContext) {
    
    (function() {
    
      // alias some functions to make (compiled) code shorter
      var m = Math;
      var mr = m.round;
      var ms = m.sin;
      var mc = m.cos;
      var abs = m.abs;
      var sqrt = m.sqrt;
    
      // this is used for sub pixel precision
      var Z = 10;
      var Z2 = Z / 2;
    
      /**
       * This funtion is assigned to the <canvas> elements as element.getContext().
       * @this {HTMLElement}
       * @return {CanvasRenderingContext2D_}
       */
      function getContext() {
        return this.context_ ||
            (this.context_ = new CanvasRenderingContext2D_(this));
      }
    
      var slice = Array.prototype.slice;
    
      /**
       * Binds a function to an object. The returned function will always use the
       * passed in {@code obj} as {@code this}.
       *
       * Example:
       *
       *   g = bind(f, obj, a, b)
       *   g(c, d) // will do f.call(obj, a, b, c, d)
       *
       * @param {Function} f The function to bind the object to
       * @param {Object} obj The object that should act as this when the function
       *     is called
       * @param {*} var_args Rest arguments that will be used as the initial
       *     arguments when the function is called
       * @return {Function} A new function that has bound this
       */
      function bind(f, obj, var_args) {
        var a = slice.call(arguments, 2);
        return function() {
          return f.apply(obj, a.concat(slice.call(arguments)));
        };
      }
    
      var G_vmlCanvasManager_ = {
        init: function(opt_doc) {
          if (/MSIE/.test(navigator.userAgent) && !window.opera) {
            var doc = opt_doc || document;
            // Create a dummy element so that IE will allow canvas elements to be
            // recognized.
            doc.createElement('canvas');
            doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
          }
        },
    
        init_: function(doc) {
          // create xmlns
          if (!doc.namespaces['g_vml_']) {
            doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
                               '#default#VML');
    
          }
          if (!doc.namespaces['g_o_']) {
            doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
                               '#default#VML');
          }
    
          // Setup default CSS.  Only add one style sheet per document
          if (!doc.styleSheets['ex_canvas_']) {
            var ss = doc.createStyleSheet();
            ss.owningElement.id = 'ex_canvas_';
            ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
                // default size is 300x150 in Gecko and Opera
                'text-align:left;300px;height:150px}' +
                'g_vml_\\:*{behavior:url(#default#VML)}' +
                'g_o_\\:*{behavior:url(#default#VML)}';
    
          }
    
          // find all canvas elements
          var els = doc.getElementsByTagName('canvas');
          for (var i = 0; i < els.length; i++) {
            this.initElement(els[i]);
          }
        },
    
        /**
         * Public initializes a canvas element so that it can be used as canvas
         * element from now on. This is called automatically before the page is
         * loaded but if you are creating elements using createElement you need to
         * make sure this is called on the element.
         * @param {HTMLElement} el The canvas element to initialize.
         * @return {HTMLElement} the element that was created.
         */
        initElement: function(el) {
          if (!el.getContext) {
    
            el.getContext = getContext;
    
            // Remove fallback content. There is no way to hide text nodes so we
            // just remove all childNodes. We could hide all elements and remove
            // text nodes but who really cares about the fallback content.
            el.innerHTML = '';
    
            // do not use inline function because that will leak memory
            el.attachEvent('onpropertychange', onPropertyChange);
            el.attachEvent('onresize', onResize);
    
            var attrs = el.attributes;
            if (attrs.width && attrs.width.specified) {
              // TODO: use runtimeStyle and coordsize
              // el.getContext().setWidth_(attrs.width.nodeValue);
              el.style.width = attrs.width.nodeValue + 'px';
            } else {
              el.width = el.clientWidth;
            }
            if (attrs.height && attrs.height.specified) {
              // TODO: use runtimeStyle and coordsize
              // el.getContext().setHeight_(attrs.height.nodeValue);
              el.style.height = attrs.height.nodeValue + 'px';
            } else {
              el.height = el.clientHeight;
            }
            //el.getContext().setCoordsize_()
          }
          return el;
        }
      };
    
      function onPropertyChange(e) {
        var el = e.srcElement;
    
        switch (e.propertyName) {
          case 'width':
            el.style.width = el.attributes.width.nodeValue + 'px';
            el.getContext().clearRect();
            break;
          case 'height':
            el.style.height = el.attributes.height.nodeValue + 'px';
            el.getContext().clearRect();
            break;
        }
      }
    
      function onResize(e) {
        var el = e.srcElement;
        if (el.firstChild) {
          el.firstChild.style.width =  el.clientWidth + 'px';
          el.firstChild.style.height = el.clientHeight + 'px';
        }
      }
    
      G_vmlCanvasManager_.init();
    
      // precompute "00" to "FF"
      var dec2hex = [];
      for (var i = 0; i < 16; i++) {
        for (var j = 0; j < 16; j++) {
          dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
        }
      }
    
      function createMatrixIdentity() {
        return [
          [1, 0, 0],
          [0, 1, 0],
          [0, 0, 1]
        ];
      }
    
      function matrixMultiply(m1, m2) {
        var result = createMatrixIdentity();
    
        for (var x = 0; x < 3; x++) {
          for (var y = 0; y < 3; y++) {
            var sum = 0;
    
            for (var z = 0; z < 3; z++) {
              sum += m1[x][z] * m2[z][y];
            }
    
            result[x][y] = sum;
          }
        }
        return result;
      }
    
      function copyState(o1, o2) {
        o2.fillStyle     = o1.fillStyle;
        o2.lineCap       = o1.lineCap;
        o2.lineJoin      = o1.lineJoin;
        o2.lineWidth     = o1.lineWidth;
        o2.miterLimit    = o1.miterLimit;
        o2.shadowBlur    = o1.shadowBlur;
        o2.shadowColor   = o1.shadowColor;
        o2.shadowOffsetX = o1.shadowOffsetX;
        o2.shadowOffsetY = o1.shadowOffsetY;
        o2.strokeStyle   = o1.strokeStyle;
        o2.globalAlpha   = o1.globalAlpha;
        o2.arcScaleX_    = o1.arcScaleX_;
        o2.arcScaleY_    = o1.arcScaleY_;
        o2.lineScale_    = o1.lineScale_;
      }
    
      function processStyle(styleString) {
        var str, alpha = 1;
    
        styleString = String(styleString);
        if (styleString.substring(0, 3) == 'rgb') {
          var start = styleString.indexOf('(', 3);
          var end = styleString.indexOf(')', start + 1);
          var guts = styleString.substring(start + 1, end).split(',');
    
          str = '#';
          for (var i = 0; i < 3; i++) {
            str += dec2hex[Number(guts[i])];
          }
    
          if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
            alpha = guts[3];
          }
        } else {
          str = styleString;
        }
    
        return {color: str, alpha: alpha};
      }
    
      function processLineCap(lineCap) {
        switch (lineCap) {
          case 'butt':
            return 'flat';
          case 'round':
            return 'round';
          case 'square':
          default:
            return 'square';
        }
      }
    
      /**
       * This class implements CanvasRenderingContext2D interface as described by
       * the WHATWG.
       * @param {HTMLElement} surfaceElement The element that the 2D context should
       * be associated with
       */
      function CanvasRenderingContext2D_(surfaceElement) {
        this.m_ = createMatrixIdentity();
    
        this.mStack_ = [];
        this.aStack_ = [];
        this.currentPath_ = [];
    
        // Canvas context properties
        this.strokeStyle = '#000';
        this.fillStyle = '#000';
    
        this.lineWidth = 1;
        this.lineJoin = 'miter';
        this.lineCap = 'butt';
        this.miterLimit = Z * 1;
        this.globalAlpha = 1;
        this.canvas = surfaceElement;
    
        var el = surfaceElement.ownerDocument.createElement('div');
        el.style.width =  surfaceElement.clientWidth + 'px';
        el.style.height = surfaceElement.clientHeight + 'px';
        el.style.overflow = 'hidden';
        el.style.position = 'absolute';
        surfaceElement.appendChild(el);
    
        this.element_ = el;
        this.arcScaleX_ = 1;
        this.arcScaleY_ = 1;
        this.lineScale_ = 1;
      }
    
      var contextPrototype = CanvasRenderingContext2D_.prototype;
      contextPrototype.clearRect = function() {
        this.element_.innerHTML = '';
      };
    
      contextPrototype.beginPath = function() {
        // TODO: Branch current matrix so that save/restore has no effect
        //       as per safari docs.
        this.currentPath_ = [];
      };
    
      contextPrototype.moveTo = function(aX, aY) {
        var p = this.getCoords_(aX, aY);
        this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
        this.currentX_ = p.x;
        this.currentY_ = p.y;
      };
    
      contextPrototype.lineTo = function(aX, aY) {
        var p = this.getCoords_(aX, aY);
        this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
    
        this.currentX_ = p.x;
        this.currentY_ = p.y;
      };
    
      contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
                                                aCP2x, aCP2y,
                                                aX, aY) {
        var p = this.getCoords_(aX, aY);
        var cp1 = this.getCoords_(aCP1x, aCP1y);
        var cp2 = this.getCoords_(aCP2x, aCP2y);
        bezierCurveTo(this, cp1, cp2, p);
      };
    
      // Helper function that takes the already fixed cordinates.
      function bezierCurveTo(self, cp1, cp2, p) {
        self.currentPath_.push({
          type: 'bezierCurveTo',
          cp1x: cp1.x,
          cp1y: cp1.y,
          cp2x: cp2.x,
          cp2y: cp2.y,
          x: p.x,
          y: p.y
        });
        self.currentX_ = p.x;
        self.currentY_ = p.y;
      }
    
      contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
        // the following is lifted almost directly from
        // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
    
        var cp = this.getCoords_(aCPx, aCPy);
        var p = this.getCoords_(aX, aY);
    
        var cp1 = {
          x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
          y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
        };
        var cp2 = {
          x: cp1.x + (p.x - this.currentX_) / 3.0,
          y: cp1.y + (p.y - this.currentY_) / 3.0
        };
    
        bezierCurveTo(this, cp1, cp2, p);
      };
    
      contextPrototype.arc = function(aX, aY, aRadius,
                                      aStartAngle, aEndAngle, aClockwise) {
        aRadius *= Z;
        var arcType = aClockwise ? 'at' : 'wa';
    
        var xStart = aX + mc(aStartAngle) * aRadius - Z2;
        var yStart = aY + ms(aStartAngle) * aRadius - Z2;
    
        var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
        var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
    
        // IE won't render arches drawn counter clockwise if xStart == xEnd.
        if (xStart == xEnd && !aClockwise) {
          xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
                           // that can be represented in binary
        }
    
        var p = this.getCoords_(aX, aY);
        var pStart = this.getCoords_(xStart, yStart);
        var pEnd = this.getCoords_(xEnd, yEnd);
    
        this.currentPath_.push({type: arcType,
                               x: p.x,
                               y: p.y,
                               radius: aRadius,
                               xStart: pStart.x,
                               yStart: pStart.y,
                               xEnd: pEnd.x,
                               yEnd: pEnd.y});
    
      };
    
      contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
        this.moveTo(aX, aY);
        this.lineTo(aX + aWidth, aY);
        this.lineTo(aX + aWidth, aY + aHeight);
        this.lineTo(aX, aY + aHeight);
        this.closePath();
      };
    
      contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
        var oldPath = this.currentPath_;
        this.beginPath();
    
        this.moveTo(aX, aY);
        this.lineTo(aX + aWidth, aY);
        this.lineTo(aX + aWidth, aY + aHeight);
        this.lineTo(aX, aY + aHeight);
        this.closePath();
        this.stroke();
    
        this.currentPath_ = oldPath;
      };
    
      contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
        var oldPath = this.currentPath_;
        this.beginPath();
    
        this.moveTo(aX, aY);
        this.lineTo(aX + aWidth, aY);
        this.lineTo(aX + aWidth, aY + aHeight);
        this.lineTo(aX, aY + aHeight);
        this.closePath();
        this.fill();
    
        this.currentPath_ = oldPath;
      };
    
      contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
        var gradient = new CanvasGradient_('gradient');
        gradient.x0_ = aX0;
        gradient.y0_ = aY0;
        gradient.x1_ = aX1;
        gradient.y1_ = aY1;
        return gradient;
      };
    
      contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
                                                       aX1, aY1, aR1) {
        var gradient = new CanvasGradient_('gradientradial');
        gradient.x0_ = aX0;
        gradient.y0_ = aY0;
        gradient.r0_ = aR0;
        gradient.x1_ = aX1;
        gradient.y1_ = aY1;
        gradient.r1_ = aR1;
        return gradient;
      };
    
      contextPrototype.drawImage = function(image, var_args) {
        var dx, dy, dw, dh, sx, sy, sw, sh;
    
        // to find the original width we overide the width and height
        var oldRuntimeWidth = image.runtimeStyle.width;
        var oldRuntimeHeight = image.runtimeStyle.height;
        image.runtimeStyle.width = 'auto';
        image.runtimeStyle.height = 'auto';
    
        // get the original size
        var w = image.width;
        var h = image.height;
    
        // and remove overides
        image.runtimeStyle.width = oldRuntimeWidth;
        image.runtimeStyle.height = oldRuntimeHeight;
    
        if (arguments.length == 3) {
          dx = arguments[1];
          dy = arguments[2];
          sx = sy = 0;
          sw = dw = w;
          sh = dh = h;
        } else if (arguments.length == 5) {
          dx = arguments[1];
          dy = arguments[2];
          dw = arguments[3];
          dh = arguments[4];
          sx = sy = 0;
          sw = w;
          sh = h;
        } else if (arguments.length == 9) {
          sx = arguments[1];
          sy = arguments[2];
          sw = arguments[3];
          sh = arguments[4];
          dx = arguments[5];
          dy = arguments[6];
          dw = arguments[7];
          dh = arguments[8];
        } else {
          throw Error('Invalid number of arguments');
        }
    
        var d = this.getCoords_(dx, dy);
    
        var w2 = sw / 2;
        var h2 = sh / 2;
    
        var vmlStr = [];
    
        var W = 10;
        var H = 10;
    
        // For some reason that I've now forgotten, using divs didn't work
        vmlStr.push(' <g_vml_:group',
                    ' coordsize="', Z * W, ',', Z * H, '"',
                    ' coordorigin="0,0"' ,
                    ' style="', W, 'px;height:', H, 'px;position:absolute;');
    
        // If filters are necessary (rotation exists), create them
        // filters are bog-slow, so only create them if abbsolutely necessary
        // The following check doesn't account for skews (which don't exist
        // in the canvas spec (yet) anyway.
    
        if (this.m_[0][0] != 1 || this.m_[0][1]) {
          var filter = [];
    
          // Note the 12/21 reversal
          filter.push('M11=', this.m_[0][0], ',',
                      'M12=', this.m_[1][0], ',',
                      'M21=', this.m_[0][1], ',',
                      'M22=', this.m_[1][1], ',',
                      'Dx=', mr(d.x / Z), ',',
                      'Dy=', mr(d.y / Z), '');
    
          // Bounding box calculation (need to minimize displayed area so that
          // filters don't waste time on unused pixels.
          var max = d;
          var c2 = this.getCoords_(dx + dw, dy);
          var c3 = this.getCoords_(dx, dy + dh);
          var c4 = this.getCoords_(dx + dw, dy + dh);
    
          max.x = m.max(max.x, c2.x, c3.x, c4.x);
          max.y = m.max(max.y, c2.y, c3.y, c4.y);
    
          vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
                      'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
                      filter.join(''), ", sizingmethod='clip');")
        } else {
          vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
        }
    
        vmlStr.push(' ">' ,
                    '<g_vml_:image src="', image.src, '"',
                    ' style="', Z * dw, 'px;',
                    ' height:', Z * dh, 'px;"',
                    ' cropleft="', sx / w, '"',
                    ' croptop="', sy / h, '"',
                    ' cropright="', (w - sx - sw) / w, '"',
                    ' cropbottom="', (h - sy - sh) / h, '"',
                    ' />',
                    '</g_vml_:group>');
    
        this.element_.insertAdjacentHTML('BeforeEnd',
                                        vmlStr.join(''));
      };
    
      contextPrototype.stroke = function(aFill) {
        var lineStr = [];
        var lineOpen = false;
        var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
        var color = a.color;
        var opacity = a.alpha * this.globalAlpha;
    
        var W = 10;
        var H = 10;
    
        lineStr.push('<g_vml_:shape',
                     ' filled="', !!aFill, '"',
                     ' style="position:absolute;', W, 'px;height:', H, 'px;"',
                     ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
                     ' stroked="', !aFill, '"',
                     ' path="');
    
        var newSeq = false;
        var min = {x: null, y: null};
        var max = {x: null, y: null};
    
        for (var i = 0; i < this.currentPath_.length; i++) {
          var p = this.currentPath_[i];
          var c;
    
          switch (p.type) {
            case 'moveTo':
              c = p;
              lineStr.push(' m ', mr(p.x), ',', mr(p.y));
              break;
            case 'lineTo':
              lineStr.push(' l ', mr(p.x), ',', mr(p.y));
              break;
            case 'close':
              lineStr.push(' x ');
              p = null;
              break;
            case 'bezierCurveTo':
              lineStr.push(' c ',
                           mr(p.cp1x), ',', mr(p.cp1y), ',',
                           mr(p.cp2x), ',', mr(p.cp2y), ',',
                           mr(p.x), ',', mr(p.y));
              break;
            case 'at':
            case 'wa':
              lineStr.push(' ', p.type, ' ',
                           mr(p.x - this.arcScaleX_ * p.radius), ',',
                           mr(p.y - this.arcScaleY_ * p.radius), ' ',
                           mr(p.x + this.arcScaleX_ * p.radius), ',',
                           mr(p.y + this.arcScaleY_ * p.radius), ' ',
                           mr(p.xStart), ',', mr(p.yStart), ' ',
                           mr(p.xEnd), ',', mr(p.yEnd));
              break;
          }
    
    
          // TODO: Following is broken for curves due to
          //       move to proper paths.
    
          // Figure out dimensions so we can do gradient fills
          // properly
          if (p) {
            if (min.x == null || p.x < min.x) {
              min.x = p.x;
            }
            if (max.x == null || p.x > max.x) {
              max.x = p.x;
            }
            if (min.y == null || p.y < min.y) {
              min.y = p.y;
            }
            if (max.y == null || p.y > max.y) {
              max.y = p.y;
            }
          }
        }
        lineStr.push(' ">');
    
        if (!aFill) {
          var lineWidth = this.lineScale_ * this.lineWidth;
    
          // VML cannot correctly render a line if the width is less than 1px.
          // In that case, we dilute the color to make the line look thinner.
          if (lineWidth < 1) {
            opacity *= lineWidth;
          }
    
          lineStr.push(
            '<g_vml_:stroke',
            ' opacity="', opacity, '"',
            ' joinstyle="', this.lineJoin, '"',
            ' miterlimit="', this.miterLimit, '"',
            ' endcap="', processLineCap(this.lineCap), '"',
            ' weight="', lineWidth, 'px"',
            ' color="', color, '" />'
          );
        } else if (typeof this.fillStyle == 'object') {
          var fillStyle = this.fillStyle;
          var angle = 0;
          var focus = {x: 0, y: 0};
    
          // additional offset
          var shift = 0;
          // scale factor for offset
          var expansion = 1;
    
          if (fillStyle.type_ == 'gradient') {
            var x0 = fillStyle.x0_ / this.arcScaleX_;
            var y0 = fillStyle.y0_ / this.arcScaleY_;
            var x1 = fillStyle.x1_ / this.arcScaleX_;
            var y1 = fillStyle.y1_ / this.arcScaleY_;
            var p0 = this.getCoords_(x0, y0);
            var p1 = this.getCoords_(x1, y1);
            var dx = p1.x - p0.x;
            var dy = p1.y - p0.y;
            angle = Math.atan2(dx, dy) * 180 / Math.PI;
    
            // The angle should be a non-negative number.
            if (angle < 0) {
              angle += 360;
            }
    
            // Very small angles produce an unexpected result because they are
            // converted to a scientific notation string.
            if (angle < 1e-6) {
              angle = 0;
            }
          } else {
            var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
            var width  = max.x - min.x;
            var height = max.y - min.y;
            focus = {
              x: (p0.x - min.x) / width,
              y: (p0.y - min.y) / height
            };
    
            width  /= this.arcScaleX_ * Z;
            height /= this.arcScaleY_ * Z;
            var dimension = m.max(width, height);
            shift = 2 * fillStyle.r0_ / dimension;
            expansion = 2 * fillStyle.r1_ / dimension - shift;
          }
    
          // We need to sort the color stops in ascending order by offset,
          // otherwise IE won't interpret it correctly.
          var stops = fillStyle.colors_;
          stops.sort(function(cs1, cs2) {
            return cs1.offset - cs2.offset;
          });
    
          var length = stops.length;
          var color1 = stops[0].color;
          var color2 = stops[length - 1].color;
          var opacity1 = stops[0].alpha * this.globalAlpha;
          var opacity2 = stops[length - 1].alpha * this.globalAlpha;
    
          var colors = [];
          for (var i = 0; i < length; i++) {
            var stop = stops[i];
            colors.push(stop.offset * expansion + shift + ' ' + stop.color);
          }
    
          // When colors attribute is used, the meanings of opacity and o:opacity2
          // are reversed.
          lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
                       ' method="none" focus="100%"',
                       ' color="', color1, '"',
                       ' color2="', color2, '"',
                       ' colors="', colors.join(','), '"',
                       ' opacity="', opacity2, '"',
                       ' g_o_:opacity2="', opacity1, '"',
                       ' angle="', angle, '"',
                       ' focusposition="', focus.x, ',', focus.y, '" />');
        } else {
          lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
                       '" />');
        }
    
        lineStr.push('</g_vml_:shape>');
    
        this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
      };
    
      contextPrototype.fill = function() {
        this.stroke(true);
      }
    
      contextPrototype.closePath = function() {
        this.currentPath_.push({type: 'close'});
      };
    
      /**
       * @private
       */
      contextPrototype.getCoords_ = function(aX, aY) {
        var m = this.m_;
        return {
          x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
          y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
        }
      };
    
      contextPrototype.save = function() {
        var o = {};
        copyState(this, o);
        this.aStack_.push(o);
        this.mStack_.push(this.m_);
        this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
      };
    
      contextPrototype.restore = function() {
        copyState(this.aStack_.pop(), this);
        this.m_ = this.mStack_.pop();
      };
    
      function matrixIsFinite(m) {
        for (var j = 0; j < 3; j++) {
          for (var k = 0; k < 2; k++) {
            if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
              return false;
            }
          }
        }
        return true;
      }
    
      function setM(ctx, m, updateLineScale) {
        if (!matrixIsFinite(m)) {
          return;
        }
        ctx.m_ = m;
    
        if (updateLineScale) {
          // Get the line scale.
          // Determinant of this.m_ means how much the area is enlarged by the
          // transformation. So its square root can be used as a scale factor
          // for width.
          var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
          ctx.lineScale_ = sqrt(abs(det));
        }
      }
    
      contextPrototype.translate = function(aX, aY) {
        var m1 = [
          [1,  0,  0],
          [0,  1,  0],
          [aX, aY, 1]
        ];
    
        setM(this, matrixMultiply(m1, this.m_), false);
      };
    
      contextPrototype.rotate = function(aRot) {
        var c = mc(aRot);
        var s = ms(aRot);
    
        var m1 = [
          [c,  s, 0],
          [-s, c, 0],
          [0,  0, 1]
        ];
    
        setM(this, matrixMultiply(m1, this.m_), false);
      };
    
      contextPrototype.scale = function(aX, aY) {
        this.arcScaleX_ *= aX;
        this.arcScaleY_ *= aY;
        var m1 = [
          [aX, 0,  0],
          [0,  aY, 0],
          [0,  0,  1]
        ];
    
        setM(this, matrixMultiply(m1, this.m_), true);
      };
    
      contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
        var m1 = [
          [m11, m12, 0],
          [m21, m22, 0],
          [dx,  dy,  1]
        ];
    
        setM(this, matrixMultiply(m1, this.m_), true);
      };
    
      contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
        var m = [
          [m11, m12, 0],
          [m21, m22, 0],
          [dx,  dy,  1]
        ];
    
        setM(this, m, true);
      };
    
      /******** STUBS ********/
      contextPrototype.clip = function() {
        // TODO: Implement
      };
    
      contextPrototype.arcTo = function() {
        // TODO: Implement
      };
    
      contextPrototype.createPattern = function() {
        return new CanvasPattern_;
      };
    
      // Gradient / Pattern Stubs
      function CanvasGradient_(aType) {
        this.type_ = aType;
        this.x0_ = 0;
        this.y0_ = 0;
        this.r0_ = 0;
        this.x1_ = 0;
        this.y1_ = 0;
        this.r1_ = 0;
        this.colors_ = [];
      }
    
      CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
        aColor = processStyle(aColor);
        this.colors_.push({offset: aOffset,
                           color: aColor.color,
                           alpha: aColor.alpha});
      };
    
      function CanvasPattern_() {}
    
      // set up externs
      G_vmlCanvasManager = G_vmlCanvasManager_;
      CanvasRenderingContext2D = CanvasRenderingContext2D_;
      CanvasGradient = CanvasGradient_;
      CanvasPattern = CanvasPattern_;
    
    })();
    
    } // if
    

      

  • 相关阅读:
    SCAU 9504 面试
    SCAU 9503 懒人选座位
    SCAU 8628 相亲
    SCAU 10691 ACM 光环
    SCAU 8626 原子量计数
    SCAU 10674 等差对
    HDU ACM 1048 The Hardest Problem Ever (水题)
    SCAU 9502 ARDF
    SCAU 10686 DeathGod不知道的事情
    SCAU 8629 热身游戏(高精度)
  • 原文地址:https://www.cnblogs.com/verylove/p/5302891.html
Copyright © 2011-2022 走看看