How to use cacheContext method in Playwright Internal

Best JavaScript code snippet using playwright-internal

stockgraph.js

Source:stockgraph.js Github

copy

Full Screen

1/**2 * Created by yuhk18757 on 2017/3/22.3 */4(function(){5 var KPainter,requestDispatcher,pageControl,Config,StockGraph;6 //避免marketDetail请求过大而设置的本地变量7 Config={8 tradeSectionGrp:{9 SS:{10 trade_section_grp:[{open_time:930,close_time:1130},{open_time:1300,close_time:1500}]11 },12 SZ:{13 trade_section_grp:[{open_time:930,close_time:1130},{open_time:1300,close_time:1500}]14 },15 HKM:{16 trade_section_grp:[{open_time:930,close_time:1200},{open_time:1300,close_time:1600}]17 }18 },19 AmericanStockList:["A","CBOT","COMEX","N","NYMEX","O","XBUS"]20 };21 /*22 * K线绘图器。本身作为总控制器,内部有多个绘图器23 */24 KPainter=(function(){25 //dom元素26 var container,realCanvas,cacheCanvas,realContext,cacheContext,pixel,27 realCursorCanvas,cacheCursorCanvas,realCursorContext,cacheCursorContext,28 textContainer,canvasContainer,maxRate,gridExpand;29 //配置变量30 var rawData,process,speed,totalTime,painterStack,kColor,kWidth,gapWidth,31 fontSize,maColor,gapOccupy,dayCount,loading,cursorIndex,cursorX;32 //方法&对象33 var init,draw,resize,refreshCache,candlePainter,kBarPainter,trendBarPainter,34 kControl,trendControl,refreshCursorCache,trendPainter,initDom,initCanvas,35 animate,painterTool,eventControl,currControl,triggerControl,showLoading,36 extraPainterCollection,textPainter;37 //初始化dom元素,仅需执行一次38 initDom=function(){39 //pixel=window.devicePixelRatio;40 pixel=2;41 //固定配置项42 painterStack=[];43 //[跌,涨]44 kColor=["#32a647","#fa5d5d"];45 //MA图线颜色46 maColor={5:"#f5a623",10:"#2e84e6",20:"#bd10e0"};47 //ma指标48 dayCount=[5,10,20];49 //柱图间隙占比50 gapOccupy=0.4;51 //文字大小52 fontSize=24;53 //最大值扩大比例54 maxRate=1;55 //边框扩大值56 gridExpand=pixel*3;57 //线性动画下动画总时长58 totalTime=800;59 //线性动画下递增速度(渐变动画时无效)60 speed=16/totalTime;61 //递增标志62 process=speed;63 //dom64 container=document.getElementById("k-container");65 canvasContainer=document.createElement("div");66 canvasContainer.style.float="left";67 canvasContainer.style.width="100%";68 canvasContainer.style.height="100%";69 container.appendChild(canvasContainer);70 realCanvas=canvasContainer.realCanvas || document.createElement("canvas");71 cacheCanvas=canvasContainer.cacheCanvas || document.createElement("canvas");72 realContext=realCanvas.getContext("2d");73 cacheContext=cacheCanvas.getContext("2d");74 realCanvas.style.position="absolute";75 canvasContainer.appendChild(realCanvas);76 //十字光标画布77 realCursorCanvas=canvasContainer.realCursorCanvas || document.createElement("canvas");78 cacheCursorCanvas=canvasContainer.cacheCursorCanvas || document.createElement("canvas");79 realCursorContext=realCursorCanvas.getContext("2d");80 cacheCursorContext=cacheCursorCanvas.getContext("2d");81 realCursorCanvas.style.position="absolute";82 realCursorCanvas.style.zIndex=1;83 canvasContainer.appendChild(realCursorCanvas);84 };85 initDom();86 //初始化画布长宽,在页面resize时需要重新执行87 initCanvas=function(){88 //避免移动设备screenPixel模糊问题89 cacheCanvas.width=canvasContainer.clientWidth*pixel;90 cacheCanvas.height=canvasContainer.clientHeight*pixel;91 realCanvas.width=canvasContainer.clientWidth*pixel;92 realCanvas.height=canvasContainer.clientHeight*pixel;93 realCanvas.style.width=canvasContainer.clientWidth+"px";94 realCanvas.style.height=canvasContainer.clientHeight+"px";95 //十字光标画布96 cacheCursorCanvas.width=canvasContainer.clientWidth*pixel;97 cacheCursorCanvas.height=canvasContainer.clientHeight*pixel;98 realCursorCanvas.width=canvasContainer.clientWidth*pixel;99 realCursorCanvas.height=canvasContainer.clientHeight*pixel;100 realCursorCanvas.style.width=canvasContainer.clientWidth+"px";101 realCursorCanvas.style.height=canvasContainer.clientHeight+"px";102 };103 /*------------------------工具方法---------------------------*/104 painterTool={105 //传入两个坐标点对象,绘制连接这两个点的虚线106 drawDashed:function(start,end){107 var gap=0.004,length=0.006,position=0,x,y,108 gapX,gapY,lengthX,lengthY,step;109 cacheContext.beginPath();110 cacheContext.strokeStyle="#ccc";111 cacheContext.lineWidth=2;112 gapX=(end.x-start.x)*gap;113 gapY=(end.y-start.y)*gap;114 lengthX=(end.x-start.x)*length;115 lengthY=(end.y-start.y)*length;116 step=gap+length;117 x=start.x;118 y=start.y;119 cacheContext.moveTo(x,y);120 for(;position+length<1;position+=step){121 x+=lengthX;122 y+=lengthY;123 cacheContext.lineTo(x,y);124 x+=gapX;125 y+=gapY;126 cacheContext.moveTo(x,y);127 }128 cacheContext.lineTo(end.x,end.y);129 cacheContext.stroke();130 },131 //数字为参数,返回奇数132 getOdd:function(value,add){133 var result;134 if(add){135 result=value%2==0 ? value-1:value;136 }else{137 result=value%2==0 ? value-1:value;138 }139 return result;140 },141 //美国时间转中国时间142 transferAmericaTime:function(time){143 var hour,minute;144 hour=time.substring(time.length-4,time.length-2);145 minute=time.substring(time.length-2,time.length);146 hour=hour-13;147 hour=hour<0 ? hour+24:hour;148 hour=hour<10 ? "0"+hour:hour;149 return time.substring(0,time.length-4)+hour+minute;150 }151 };152 /*------------------------工具方法end---------------------------*/153 /*------------------------绘图器---------------------------*/154 /*155 * 补充绘图器156 * 包含:MACD指标绘图器157 */158 extraPainterCollection=(function(){159 //配置变量160 var data,layout,width,height,leftX,rightX,topY,bottomY;161 //方法162 var initSize,initValue,drawGrid,insideOf,MACDPainter;163 //为固定配置变量赋值164 layout={a:0.79,b:0.01,c:0.01,d:0.01};165 //设置布局属性,画布长宽会在resize时重新计算166 initValue=function(){167 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);168 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);169 topY=painterTool.getOdd(realCanvas.height*layout.a,false);170 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);171 width=rightX-leftX;172 height=bottomY-topY;173 };174 //绘制补充绘图器的边框网格175 drawGrid=function(){176 var y;177 cacheContext.beginPath();178 cacheContext.strokeStyle="#000";179 cacheContext.lineWidth=1;180 //绘制实线181 cacheContext.moveTo(leftX,topY);182 cacheContext.lineTo(rightX,topY);183 cacheContext.lineTo(rightX,bottomY);184 cacheContext.lineTo(leftX,bottomY);185 cacheContext.closePath();186 cacheContext.stroke();187 //绘制虚线188 y=painterTool.getOdd(topY+height/2);189 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});190 };191 /*192 * 初始化基本配置193 * 数据不在init方法中被传入,否则触控事件就要多次不必要的调用init方法194 */195 initSize=function(){196 initValue();197 };198 //判断x,y是否在绘制区域内199 insideOf=function(x,y){200 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){201 return true;202 }else{203 return false;204 }205 };206 /*207 * MACD绘图器208 * EMA(12) = 前一日EMA(12) X 11/13 + 今日收盘 价 X 2/13209 * EMA(26) = 前一日EMA(26) X 25/27 + 今日收盘价 X 2/27210 * DIF = EMA(12) - EMA(26)211 * DEA = (前一日DEA X 8/10 + 今日DIF X 2/10)212 * (DIF-DEA)*2为MACD柱状图213 */214 MACDPainter=(function(){215 //变量216 var data,start,end,ema12,ema26,dif,dea,macd,217 max,min,range,macdX,middleY,macdColor;218 //方法219 var drawReady,resizeDraw,drawFrame,showCursor,drawCursor,handleData,220 calcData,calcAxis,drawMACD,drawLine,drawText,drawCursorTip;221 macdColor={222 dif:"#f5a623",223 dea:"#2e84e6"224 };225 //计算坐标点226 calcAxis=function(){227 var i;228 middleY=topY+height/2;229 max=min=0;230 for(i=start;i<end;i++){231 if(max<dif[i].data){232 max=dif[i].data;233 }234 if(max<dea[i].data){235 max=dea[i].data;236 }237 if(max<macd[i].data){238 max=macd[i].data;239 }240 if(min>dif[i].data){241 min=dif[i].data;242 }243 if(min>dea[i].data){244 min=dea[i].data;245 }246 if(min>macd[i].data){247 min=macd[i].data;248 }249 }250 max=Math.max(max,Math.abs(min))*maxRate;251 min=-max;252 range=max*2;253 for(i=start;i<end;i++){254 dif[i].axis=topY+height*(max-dif[i].data)/range;255 dea[i].axis=topY+height*(max-dea[i].data)/range;256 macd[i].height=height*macd[i].data/range;257 macd[i].color=macd[i].data<0 ? 0:1;258 }259 };260 //计算MACD各项指标261 calcData=function(){262 ema12=[];263 ema26=[];264 dif=[];265 dea=[];266 macd=[];267 ema12.push(data[0][4]);268 ema26.push(data[0][4]);269 dif.push({data:0});270 dea.push({data:0});271 macd.push({data:0});272 for(var i=1,l=data.length;i<l;i++){273 ema12.push(ema12[i-1]*11/13+data[i][4]*2/13);274 ema26.push(ema26[i-1]*25/27+data[i][4]*2/27);275 dif.push({data:ema12[i]-ema26[i]});276 dea.push({data:dea[i-1].data*8/10+dif[i].data*2/10});277 macd.push({data:(dif[i].data-dea[i].data)*2});278 }279 };280 //处理MACD数据281 handleData=function(){282 if(data.MACD){283 return ;284 }285 data.MACD=true;286 calcData();287 };288 //绘制MACD柱289 drawMACD=function(x,data){290 var y;291 cacheContext.beginPath();292 cacheContext.fillStyle=kColor[data.color];293 cacheContext.moveTo(x,middleY);294 cacheContext.lineTo(x+kWidth,middleY);295 y=middleY-data.height*process;296 cacheContext.lineTo(x+kWidth,y);297 cacheContext.lineTo(x,y);298 cacheContext.closePath();299 cacheContext.fill();300 };301 //绘制DIF,DEA线302 drawLine=function(){303 var x,l,i;304 //DIF305 x=leftX+gapWidth+kWidth/2;306 l=start+Math.floor((end-start)*process);307 cacheContext.beginPath();308 cacheContext.strokeStyle=macdColor.dif;309 cacheContext.lineWidth=1;310 //补足头部图形311 if(start>0){312 cacheContext.moveTo(leftX,(dif[start].axis+topY+height*(max-dif[start-1].data)/range)/2);313 }314 for(i=start;i<l;i++){315 cacheContext.lineTo(x,dif[i].axis);316 x+=gapWidth+kWidth;317 }318 //补足尾部图形319 if(i==end){320 if(end<dif.length-1){321 cacheContext.lineTo(rightX,(dif[i-1].axis+dif[i].axis)/2);322 }323 }324 cacheContext.stroke();325 //DEA326 x=leftX+gapWidth+kWidth/2;327 cacheContext.beginPath();328 cacheContext.strokeStyle=macdColor.dea;329 cacheContext.lineWidth=1;330 //补足头部图形331 if(start>0){332 cacheContext.moveTo(leftX,(dea[start].axis+topY+height*(max-dea[start-1].data)/range)/2);333 }334 for(i=start;i<l;i++){335 cacheContext.lineTo(x,dea[i].axis);336 x+=gapWidth+kWidth;337 }338 //补足尾部图形339 if(i==end){340 if(end<dea.length-1){341 cacheContext.lineTo(rightX,(dea[i-1].axis+dea[i].axis)/2);342 }343 }344 cacheContext.stroke();345 };346 //绘制MACDy轴max,min文字347 drawText=function(){348 cacheContext.fillStyle="#999";349 cacheContext.font=fontSize+"px Arial";350 cacheContext.textAlign="left";351 cacheContext.textBaseline="top";352 cacheContext.fillText(max.toFixed(2),leftX,topY);353 cacheContext.textBaseline="middle";354 cacheContext.fillText("0.00",leftX,middleY);355 cacheContext.textBaseline="bottom";356 cacheContext.fillText(min.toFixed(2),leftX,bottomY);357 };358 //绘制MACD帧359 drawFrame=function(){360 drawGrid();361 macdX=leftX+gapWidth;362 for(var i=start;i<end;i++){363 drawMACD(macdX,macd[i]);364 macdX+=gapWidth+kWidth;365 }366 drawLine();367 drawText();368 };369 //右上角显示MACD指标值370 drawCursorTip=function(){371 var content,gap,x;372 gap=1.2*cacheCursorContext.measureText("MACD:+"+max.toFixed(2)).width;373 x=rightX;374 cacheCursorContext.font=fontSize+"px Arial";375 cacheCursorContext.textBaseline="top";376 cacheCursorContext.textAlign="left";377 //macd378 content="MACD:"+macd[cursorIndex].data.toFixed(2);379 x-=gap;380 cacheCursorContext.fillStyle=kColor[macd[cursorIndex].data<0 ? 0:1];381 cacheCursorContext.fillText(content,x,topY);382 //dea383 content="DEA:"+dea[cursorIndex].data.toFixed(2);384 x-=gap;385 cacheCursorContext.fillStyle=macdColor.dea;386 cacheCursorContext.fillText(content,x,topY);387 //dif388 content="DIF:"+dif[cursorIndex].data.toFixed(2);389 x-=gap;390 cacheCursorContext.fillStyle=macdColor.dif;391 cacheCursorContext.fillText(content,x,topY);392 };393 //绘制MACD图十字光标394 drawCursor=function(x,y){395 cacheCursorContext.beginPath();396 cacheCursorContext.strokeStyle="#000";397 cacheCursorContext.moveTo(cursorX,topY);398 cacheCursorContext.lineTo(cursorX,bottomY);399 cacheCursorContext.stroke();400 drawCursorTip();401 };402 //绘制MACD图十字光标403 showCursor=function(x,y){404 drawCursor(x,y);405 };406 /*407 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化408 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];409 * candleData本身为数组,包含maData指针指向均线数组,axis属性指向坐标数组410 */411 drawReady=function(kData,startPosition,endPosition){412 if(!kData || kData.length==0){413 return ;414 }415 data=kData;416 start=startPosition;417 end=endPosition;418 handleData();419 calcAxis();420 };421 //onresize重绘422 resizeDraw=function(){423 initValue();424 calcAxis();425 drawFrame();426 };427 return {428 initSize:initSize,429 drawReady:drawReady,430 drawFrame:drawFrame,431 resizeDraw:resizeDraw,432 showCursor:showCursor,433 insideOf:insideOf434 }435 })();436 return {437 initSize:initSize,438 MACDPainter:MACDPainter439 };440 })();441 /*442 * K线蜡烛绘图器,子绘图器操作在缓冲画布中,不影响显示443 */444 candlePainter=(function(){445 //配置变量446 var data,layout,width,height,leftX,rightX,topY,bottomY,447 max,min,candleY,candleX,amount,range,middleX,448 middleY,start,end;449 //方法450 var initSize,drawReady,resizeDraw,initValue,drawGrid,handleData,451 drawFrame,drawUpCandle,drawDownCandle,calcAxis,insideOf,drawMA,452 drawMAText,showCursor,drawCursor,drawXTip,drawYTip,showMAText,453 drawRoundRect;454 //为固定配置变量赋值455 layout={a:0.01,b:0.01,c:0.46,d:0.01};456 //设置布局属性,画布长宽会在resize时重新计算457 initValue=function(){458 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);459 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);460 topY=painterTool.getOdd(realCanvas.height*layout.a,false);461 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);462 width=rightX-leftX;463 height=bottomY-topY;464 };465 //计算y坐标值466 calcAxis=function(){467 var i,j,k;468 kWidth=width*(1-gapOccupy)/amount;469 gapWidth=width*gapOccupy/(amount+1);470 for(i=start;i<end;i++){471 //蜡烛坐标计算,[开盘价,最高价,最低价,收盘价,中点]y坐标472 data[i].axis=[];473 for(j=1;j<5;j++){474 data[i].axis.push(topY+height*(max-data[i][j])/range);475 }476 data[i].axis.push((data[i].axis[3]+data[i].axis[0])/2);477 for(k in data.maData){478 data.maData[k][i].maAxis=topY+height*(max-data.maData[k][i][0])/range;479 }480 }481 };482 /*483 * 为可变配置赋值484 * 计算数据展示总数485 * 计算蜡烛宽度、间距宽度486 * 计算y坐标轴的最大值,最小值487 * 计算每个数据的颜色标记:1-涨,0-跌488 */489 handleData=function(){490 var i,j,temp;491 //处理ma头尾补图形引起的作用于变化问题492 max=data[start][2];493 min=data[start][3];494 for(i=start;i<end;i++){495 if(max<data[i][2]){496 max=data[i][2];497 }498 for(j in data.maData){499 if(max<data.maData[j][i][0]){500 max=data.maData[j][i][0];501 }502 }503 if(min>data[i][3]){504 min=data[i][3];505 }506 for(j in data.maData){507 if(min>data.maData[j][i][0]){508 min=data.maData[j][i][0];509 }510 }511 }512 //和头尾的均线值比较513 if(start>0){514 temp=start-1;515 for(j in data.maData){516 if(max<data.maData[j][temp][0]){517 max=data.maData[j][temp][0];518 }519 }520 for(j in data.maData){521 if(min>data.maData[j][temp][0]){522 min=data.maData[j][temp][0];523 }524 }525 }526 if(end<data.length){527 temp=end+1;528 for(j in data.maData){529 if(max<data.maData[j][temp][0]){530 max=data.maData[j][temp][0];531 }532 }533 for(j in data.maData){534 if(min>data.maData[j][temp][0]){535 min=data.maData[j][temp][0];536 }537 }538 }539 max*=maxRate;540 range=max-min;541 calcAxis();542 };543 //绘制蜡烛图ma文字544 drawMAText=function(index){545 var maTips,i,wordWidth,word,gapWidth,wordX,count;546 count=0;547 wordWidth=0;548 maTips={};549 for(i in data.maData){550 word=data.maData[i][index][0]=="-" ? "-":(data.maData[i][index][0].toFixed(2));551 word="MA"+i+":"+word;552 maTips[i]=word;553 wordWidth+=cacheCursorContext.measureText(word).width;554 count++;555 }556 gapWidth=(width-wordWidth)/(count+1);557 cacheCursorContext.font=fontSize+"px Arial";558 cacheCursorContext.textBaseline="top";559 cacheCursorContext.textAlign="left";560 wordX=leftX+gapWidth;561 wordWidth/=count;562 for(i in data.maData){563 cacheCursorContext.fillStyle=maColor[i];564 cacheCursorContext.fillText(maTips[i],wordX,topY);565 wordX+=wordWidth+gapWidth;566 }567 };568 //显示最后一条ma值569 showMAText=function(){570 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);571 drawMAText(end-1);572 refreshCursorCache();573 };574 //绘制坐标轴网格575 drawGrid=function(){576 var stepY;577 cacheContext.beginPath();578 cacheContext.strokeStyle="#000";579 cacheContext.lineWidth=1;580 //绘制实线581 cacheContext.moveTo(leftX,topY);582 cacheContext.lineTo(rightX,topY);583 cacheContext.lineTo(rightX,bottomY);584 cacheContext.lineTo(leftX,bottomY);585 cacheContext.closePath();586 cacheContext.stroke();587 //绘制虚线588 stepY=height/4;589 for(var i=1;i<4;i++){590 painterTool.drawDashed({x:painterTool.getOdd(leftX),y:painterTool.getOdd(topY+i*stepY)},{x:painterTool.getOdd(rightX),y:painterTool.getOdd(topY+i*stepY)});591 }592 //绘制y轴数字593 cacheContext.fillStyle="#999";594 cacheContext.font=fontSize+"px Arial";595 cacheContext.textAlign="left";596 cacheContext.textBaseline="top";597 cacheContext.fillText(max.toFixed(2),leftX,topY);598 cacheContext.textBaseline="middle";599 cacheContext.fillText(((max+min)/2).toFixed(2),leftX,topY+height/2);600 cacheContext.textBaseline="bottom";601 cacheContext.fillText(min.toFixed(2),leftX,bottomY);602 //绘制x轴日期603 cacheContext.textBaseline="top";604 cacheContext.fillText(data[start][0],leftX,bottomY);605 cacheContext.textAlign="right";606 cacheContext.fillText(data[end-1][0],rightX,bottomY);607 showMAText();608 };609 /*610 * 红色K线,从下往上画611 * 传入蜡烛左侧x坐标和K线数据[日期,开盘价,最高价,最低价,收盘价,成交量]为参数612 */613 drawUpCandle=function(x,value){614 middleX=painterTool.getOdd(x+kWidth/2);615 middleY=value.axis[4];616 cacheContext.beginPath();617 cacheContext.fillStyle=kColor[value.color];618 cacheContext.strokeStyle=kColor[value.color];619 cacheContext.lineWidth=2;620 candleY=middleY+(value.axis[0]-middleY)*process;621 cacheContext.moveTo(x,candleY);622 cacheContext.lineTo(middleX,candleY);623 cacheContext.moveTo(middleX,middleY+(value.axis[2]-middleY)*process);624 cacheContext.lineTo(middleX,candleY);625 cacheContext.lineTo(x+kWidth,candleY);626 candleY=middleY+(value.axis[3]-middleY)*process;627 cacheContext.lineTo(x+kWidth,candleY);628 cacheContext.lineTo(middleX,candleY);629 cacheContext.moveTo(middleX,middleY+(value.axis[1]-middleY)*process);630 cacheContext.lineTo(middleX,candleY);631 cacheContext.lineTo(x,candleY);632 cacheContext.lineTo(x,middleY+(value.axis[0]-middleY)*process);633 cacheContext.stroke();634 };635 /*636 * 绿色K线,从上往下画637 * 传入蜡烛左侧x坐标和K线数据[日期,开盘价,最高价,最低价,收盘价,成交量]为参数638 */639 drawDownCandle=function(x,value){640 middleX=painterTool.getOdd(x+kWidth/2);641 middleY=value.axis[4];642 cacheContext.beginPath();643 cacheContext.fillStyle=kColor[value.color];644 cacheContext.strokeStyle=kColor[value.color];645 cacheContext.lineWidth=2;646 candleY=middleY+(value.axis[0]-middleY)*process;647 cacheContext.moveTo(x,candleY);648 cacheContext.lineTo(x+kWidth,candleY);649 candleY=middleY+(value.axis[3]-middleY)*process;650 cacheContext.lineTo(x+kWidth,candleY);651 cacheContext.lineTo(x,candleY);652 cacheContext.closePath();653 cacheContext.fill();654 cacheContext.stroke();655 cacheContext.beginPath();656 cacheContext.moveTo(middleX,middleY+(value.axis[1]-middleY)*process);657 cacheContext.lineTo(middleX,middleY+(value.axis[2]-middleY)*process);658 cacheContext.stroke();659 };660 /*661 * 绘制ma均线662 * 传入索引,表示绘制哪一个均线663 */664 drawMA=function(index){665 var value,x,l;666 value=data.maData[index];667 x=leftX+gapWidth+kWidth/2;668 l=start+Math.floor((end-start)*process);669 cacheContext.beginPath();670 cacheContext.strokeStyle=maColor[index];671 cacheContext.lineWidth=1;672 //为ma补足头部图形673 if(start>0){674 cacheContext.moveTo(leftX,(value[start].maAxis+topY+height*(max-value[start-1][0])/range)/2);675 }676 for(var i=start;i<l;i++){677 cacheContext.lineTo(x,value[i].maAxis);678 x+=gapWidth+kWidth;679 }680 //为ma补足尾部图形681 if(i==end){682 if(value[i]!="-"){683 cacheContext.lineTo(rightX,(value[i-1].maAxis+value[i].maAxis)/2);684 }685 }686 cacheContext.stroke();687 };688 //根据process进度情况,绘制K线蜡烛图图形帧689 drawFrame=function(){690 var width=gapWidth+kWidth;691 drawGrid();692 candleX=leftX+gapWidth;693 for(var i=start;i<end;i++){694 if(data[i].color==1){695 drawUpCandle(candleX,data[i]);696 }else{697 drawDownCandle(candleX,data[i]);698 }699 candleX+=width;700 }701 for(i in data.maData){702 drawMA(i);703 }704 };705 //绘制圆角矩形706 drawRoundRect=function(x,y,w,h){707 var r,change;708 r=h/4;709 change=2;710 x-=change;711 y-=change;712 w+=change*2;713 h+=change*2;714 if(x<leftX){715 x=leftX;716 }else if((x+w)>rightX){717 x=rightX-w;718 }719 if(y<topY){720 y=topY;721 }else if(y+h>bottomY){722 y=bottomY-h;723 }724 cacheCursorContext.beginPath();725 cacheCursorContext.strokeStyle="#999";726 cacheCursorContext.fillStyle="#ddd";727 cacheCursorContext.moveTo(x+r,y);728 cacheCursorContext.arcTo(x+w,y,x+w,y+h,r);729 cacheCursorContext.arcTo(x+w,y+h,x,y+h,r);730 cacheCursorContext.arcTo(x,y+h,x,y,r);731 cacheCursorContext.arcTo(x,y,x+r,y,r);732 cacheCursorContext.stroke();733 cacheCursorContext.fill();734 };735 //绘制日Kx轴tip736 drawXTip=function(x,data){737 var content,contentLength;738 //线739 cacheCursorContext.beginPath();740 cacheCursorContext.strokeStyle="#000";741 cacheCursorContext.moveTo(x,topY);742 cacheCursorContext.lineTo(x,bottomY);743 cacheCursorContext.stroke();744 //背景745 content=data[0];746 contentLength=cacheCursorContext.measureText(content).width/2;747 drawRoundRect(x-contentLength,bottomY-fontSize,contentLength*2,fontSize);748 //文字749 cacheCursorContext.fillStyle="#999";750 cacheCursorContext.font=fontSize+"px Arial";751 cacheCursorContext.textBaseline="bottom";752 if(x+contentLength>rightX){753 cacheCursorContext.textAlign="right";754 cacheCursorContext.fillText(content,rightX,bottomY);755 }else if(x-contentLength<leftX){756 cacheCursorContext.textAlign="left";757 cacheCursorContext.fillText(content,leftX,bottomY);758 }else{759 cacheCursorContext.textAlign="center";760 cacheCursorContext.fillText(content,x,bottomY);761 }762 };763 //绘制日Ky轴tip764 drawYTip=function(y,data){765 var content,contentLength;766 if(y>bottomY){767 y=bottomY;768 }769 //线770 cacheCursorContext.beginPath();771 cacheCursorContext.strokeStyle="#000";772 cacheCursorContext.moveTo(leftX,y);773 cacheCursorContext.lineTo(rightX,y);774 cacheCursorContext.stroke();775 //背景776 content=(max-range*(y-topY)/height).toFixed(2);777 contentLength=cacheCursorContext.measureText(content).width;778 drawRoundRect(leftX,y-fontSize/2,contentLength,fontSize);779 //文字780 cacheCursorContext.fillStyle="#999";781 cacheCursorContext.font=fontSize+"px Arial";782 cacheCursorContext.textAlign="left";783 if(y+fontSize/2>bottomY){784 cacheCursorContext.textBaseline="bottom";785 y=bottomY;786 }else if(y-fontSize/2<topY){787 cacheCursorContext.textBaseline="top";788 y=topY;789 }else{790 cacheCursorContext.textBaseline="middle";791 }792 cacheCursorContext.fillText(content,leftX,y);793 };794 //显示蜡烛图十字光标795 drawCursor=function(x,y){796 var width=gapWidth+kWidth;797 /*-------------公式计算找坐标---------------*/798 //计算触控事件所在的K线数据索引799 cursorIndex=Math.ceil((x-leftX-gapWidth/2-width)/width)+1;800 //光标头部越界801 cursorIndex=cursorIndex<1 ? 1:cursorIndex;802 //光标尾部越界803 cursorIndex=cursorIndex<end-start ? cursorIndex:end-start;804 //计算柱中心坐标805 cursorX=painterTool.getOdd(leftX+gapWidth/2+cursorIndex*width-width/2);806 /*-------------遍历找坐标---------------*/807 /*cursorX=leftX+width+gapWidth/2;808 cursorIndex=1;809 while(cursorX<x){810 cursorIndex++;811 cursorX+=width;812 }813 cursorX=painterTool.getOdd(cursorX-width/2);*/814 //尾部取数据数组越界815 cursorIndex+=start-1;816 drawXTip(cursorX,data[cursorIndex]);817 drawYTip(painterTool.getOdd(y),data[cursorIndex]);818 drawMAText(cursorIndex);819 };820 /*821 * 初始化基本配置822 * 数据不在init方法中被传入,否则触控事件就要多次不必要的调用init方法823 */824 initSize=function(){825 initValue();826 };827 /*828 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化829 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];830 * candleData本身为数组,包含maData指针指向均线数组,axis属性指向坐标数组831 */832 drawReady=function(candleData,startPosition,endPosition,candleAmount){833 if(!candleData || candleData.length==0){834 return ;835 }836 data=candleData;837 start=startPosition;838 end=endPosition;839 amount=candleAmount;840 handleData();841 };842 //onresize重绘843 resizeDraw=function(){844 initValue();845 calcAxis();846 drawFrame();847 };848 //判断x,y是否在绘制区域内849 insideOf=function(x,y){850 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){851 return true;852 }else{853 return false;854 }855 };856 //绘制蜡烛图十字光标857 showCursor=function(x,y){858 drawCursor(x,y);859 };860 return {861 initSize:initSize,862 drawReady:drawReady,863 drawFrame:drawFrame,864 resizeDraw:resizeDraw,865 showCursor:showCursor,866 insideOf:insideOf,867 showMAText:showMAText868 };869 })();870 /*871 * K线交易量柱状图绘图器,子绘图器操作在缓冲画布中,不影响显示872 */873 kBarPainter=(function(){874 //数据875 var data,initValue,max,width,height,leftX,rightX,topY,876 bottomY,barX,layout,start,end;877 //方法878 var initSize,drawReady,resizeDraw,drawFrame,handleData,drawGrid,879 drawBar,calcAxis,insideOf,drawMA,showCursor,drawCursor,880 drawCursorTip;881 //固定配置882 layout={a:0.57,b:0.01,c:0.23,d:0.01};883 initValue=function(){884 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);885 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);886 topY=painterTool.getOdd(realCanvas.height*layout.a,false);887 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);888 width=rightX-leftX;889 height=bottomY-topY;890 };891 //计算交易量柱的高度892 calcAxis=function(){893 var i,k;894 for(i=start;i<end;i++){895 data[i].baHeight=data[i][5]/max*height;896 for(k in data.maData){897 data.maData[k][i].maBaAxis=bottomY-height*data.maData[k][i][1]/max;898 }899 }900 };901 //计算成交量的最大值902 handleData=function(){903 var i,j,temp;904 max=data[start][5];905 for(i=start;i<end;i++){906 if(max<data[i][5]){907 max=data[i][5];908 }909 for(j in data.maData){910 if(max<data.maData[j][i][1]){911 max=data.maData[j][i][1];912 }913 }914 }915 //比较均线值头尾数据916 if(start>0){917 temp=start-1;918 for(j in data.maData){919 if(max<data.maData[j][temp][1]){920 max=data.maData[j][temp][1];921 }922 }923 }924 if(end<data.length){925 temp=end+1;926 for(j in data.maData){927 if(max<data.maData[j][temp][1]){928 max=data.maData[j][temp][1];929 }930 }931 }932 max*=maxRate;933 calcAxis();934 };935 //绘制边框虚线936 drawGrid=function(){937 var y;938 cacheContext.beginPath();939 cacheContext.strokeStyle="#000";940 cacheContext.lineWidth=1;941 //绘制实线942 cacheContext.moveTo(leftX,topY);943 cacheContext.lineTo(rightX,topY);944 cacheContext.lineTo(rightX,bottomY);945 cacheContext.lineTo(leftX,bottomY);946 cacheContext.closePath();947 cacheContext.stroke();948 //绘制虚线949 y=painterTool.getOdd(topY+height/2);950 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});951 //绘制y轴文字952 cacheContext.fillStyle="#999";953 cacheContext.font=fontSize+"px Arial";954 cacheContext.textAlign="left";955 cacheContext.textBaseline="top";956 cacheContext.fillText("成交量:"+max,leftX,topY);957 };958 //绘制成交量柱959 drawBar=function(x,data){960 var y;961 cacheContext.beginPath();962 cacheContext.fillStyle=kColor[data.color];963 cacheContext.moveTo(x,bottomY);964 cacheContext.lineTo(x+kWidth,bottomY);965 y=bottomY-data.baHeight*process;966 cacheContext.lineTo(x+kWidth,y);967 cacheContext.lineTo(x,y);968 cacheContext.closePath();969 cacheContext.fill();970 };971 //绘制成交量ma均线972 drawMA=function(index){973 var value,x,l;974 value=data.maData[index];975 x=leftX+gapWidth+kWidth/2;976 l=start+Math.floor((end-start)*process);977 cacheContext.beginPath();978 cacheContext.strokeStyle=maColor[index];979 cacheContext.lineWidth=1;980 //为ma补足头部图形981 if(start>0){982 cacheContext.moveTo(leftX,(value[start].maBaAxis+bottomY-height*value[start-1][1]/max)/2);983 }984 for(var i=start;i<l;i++){985 cacheContext.lineTo(x,value[i].maBaAxis);986 x+=gapWidth+kWidth;987 }988 //为ma补足尾部图形989 if(i==end){990 if(value[i]!="-"){991 cacheContext.lineTo(rightX,(value[i-1].maBaAxis+value[i].maBaAxis)/2);992 }993 }994 cacheContext.stroke();995 };996 //根据process进度情况,绘制交易量图形帧997 drawFrame=function(){998 drawGrid();999 barX=leftX+gapWidth;1000 for(var i=start;i<end;i++){1001 drawBar(barX,data[i]);1002 barX+=gapWidth+kWidth;1003 }1004 for(i in data.maData){1005 drawMA(i);1006 }1007 };1008 //右上角显示交易量指标值1009 drawCursorTip=function(){1010 var content,gap,x;1011 gap=1.2*cacheCursorContext.measureText("成交量:"+max).width;1012 x=rightX;1013 cacheCursorContext.font=fontSize+"px Arial";1014 cacheCursorContext.textBaseline="top";1015 cacheCursorContext.textAlign="left";1016 //成交量1017 content="成交量:"+data[cursorIndex][5];1018 x-=gap;1019 cacheCursorContext.fillStyle=kColor[data[cursorIndex].color];1020 cacheCursorContext.fillText(content,x,topY);1021 //ma1022 x-=gap*4;1023 for(var i in data.maData){1024 content=parseInt(data.maData[i][cursorIndex][1]);1025 content=isNaN(content) ? "-":content;1026 content="MA"+i+":"+content;1027 x+=gap;1028 cacheCursorContext.fillStyle=maColor[i];1029 cacheCursorContext.fillText(content,x,topY);1030 }1031 };1032 //显示日K交易量图十字光标1033 drawCursor=function(x,y){1034 cacheCursorContext.beginPath();1035 cacheCursorContext.strokeStyle="#000";1036 cacheCursorContext.moveTo(cursorX,topY);1037 cacheCursorContext.lineTo(cursorX,bottomY);1038 cacheCursorContext.stroke();1039 drawCursorTip();1040 };1041 /*1042 * 初始化基本配置1043 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1044 */1045 initSize=function(){1046 initValue();1047 };1048 /*1049 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1050 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];1051 */1052 drawReady=function(barData,startPosition,endPosition){1053 if(!barData || barData.length==0){1054 return ;1055 }1056 data=barData;1057 start=startPosition;1058 end=endPosition;1059 handleData();1060 };1061 //onresize重绘1062 resizeDraw=function(){1063 initValue();1064 calcAxis();1065 drawFrame();1066 };1067 //判断x,y是否在绘制区域内1068 insideOf=function(x,y){1069 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1070 return true;1071 }else{1072 return false;1073 }1074 };1075 //绘制日K线交易量图十字光标1076 showCursor=function(x,y){1077 drawCursor(x,y);1078 };1079 return {1080 initSize:initSize,1081 drawReady:drawReady,1082 drawFrame:drawFrame,1083 resizeDraw:resizeDraw,1084 showCursor:showCursor,1085 insideOf:insideOf1086 };1087 })();1088 /*1089 * 分时图绘图器1090 */1091 trendPainter=(function(){1092 //变量1093 var data,layout,width,height,leftX,rightX,topY,bottomY,1094 middle,max,min,range,amount,range,start,end,1095 marketDetail,trendX,valueMax;1096 //方法1097 var initSize,drawReady,resizeDraw,initValue,draw1Grid,handleData,1098 draw1Frame,calcAxis,insideOf,draw1Trend,draw1Text,draw5Frame,1099 draw5Grid,draw5Trend,draw5Text,drawFrame,showCursor,drawCursor,1100 drawXTip,drawYTip,drawRoundRect,drawBall,flash,cursorShowed,1101 cursorPositionX,cursorPositionY,turnOffCursor;1102 //为固定配置变量赋值1103 layout={a:0.01,b:0.01,c:0.3,d:0.01};1104 //设置布局属性,画布长宽会在resize时重新计算1105 initValue=function(){1106 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);1107 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);1108 topY=painterTool.getOdd(realCanvas.height*layout.a,false);1109 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);1110 width=rightX-leftX;1111 height=bottomY-topY;1112 };1113 //计算分时图坐标点1114 calcAxis=function(){1115 var i,j,k;1116 //分时图的成交量图头尾都为半根1117 kWidth=width*(1-gapOccupy)/amount;1118 gapWidth=width*gapOccupy/amount;1119 for(i=start;i<end;i++){1120 data[i].axis=topY+height*(max-data[i][1])/range;1121 data[i].avgAxis=topY+height*(max-data[i][2])/range;1122 }1123 };1124 //处理数据,计算最大值最小值1125 handleData=function(){1126 var i,l;1127 amount=marketDetail.amount;1128 middle=data.preclosePx;1129 max=min=middle;1130 for(i=0,l=data.length;i<l;i++){1131 //for(i=start;i<end;i++){1132 if(max<data[i][1]){1133 max=data[i][1];1134 }1135 if(min>data[i][1]){1136 min=data[i][1];1137 }1138 }1139 //记录数据最大值(不一定是y轴最大值),后面设置渐变用1140 valueMax=max;1141 max=Math.max(max-middle,Math.abs(min-middle))*maxRate;1142 max=middle+max;1143 min=middle-(max-middle);1144 range=max-min;1145 calcAxis();1146 };1147 //头部球闪烁,会被十字光标影响1148 flash=function(x,y){1149 cacheCursorContext.beginPath();1150 cacheCursorContext.fillStyle="rgba(255,255,240,0.30)";1151 cacheCursorContext.arc(x,y,kWidth*3,0,2*Math.PI,false);1152 cacheCursorContext.fill();1153 cacheCursorContext.beginPath();1154 cacheCursorContext.fillStyle="rgba(76,143,254,0.5)";1155 cacheCursorContext.arc(x,y,kWidth*1.6,0,2*Math.PI,false);1156 cacheCursorContext.fill();1157 refreshCursorCache();1158 setTimeout(function(){1159 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);1160 if(cursorShowed){1161 drawCursor(cursorPositionX,cursorPositionY);1162 }1163 refreshCursorCache();1164 },200);1165 };1166 //绘制头部球1167 drawBall=function(x,y){1168 cacheContext.beginPath();1169 cacheContext.fillStyle="rgba(59,126,237,0.30)";1170 cacheContext.arc(x,y,kWidth*2.6,0,2*Math.PI,false);1171 cacheContext.fill();1172 cacheContext.beginPath();1173 cacheContext.fillStyle="#3b7fed";1174 cacheContext.arc(x,y,kWidth*1.4,0,2*Math.PI,false);1175 cacheContext.fill();1176 if(data.append){1177 flash(x,y);1178 }1179 };1180 //绘制分时图边框1181 draw1Grid=function(){1182 var stepY,avg,i,l,x,position,date,gridTop,gridBottom;1183 cacheContext.beginPath();1184 cacheContext.strokeStyle="#000";1185 cacheContext.lineWidth=1;1186 //绘制实线1187 gridTop=topY-gridExpand;1188 gridBottom=bottomY+gridExpand;1189 cacheContext.moveTo(leftX,gridTop);1190 cacheContext.lineTo(rightX,gridTop);1191 cacheContext.lineTo(rightX,gridBottom);1192 cacheContext.lineTo(leftX,gridBottom);1193 cacheContext.closePath();1194 cacheContext.stroke();1195 //绘制虚线1196 stepY=height/4;1197 for(i=1;i<4;i++){1198 painterTool.drawDashed(1199 {x:painterTool.getOdd(leftX),y:painterTool.getOdd(gridTop+i*stepY)},1200 {x:painterTool.getOdd(rightX),y:painterTool.getOdd(gridTop+i*stepY)}1201 );1202 }1203 //绘制分时时间1204 avg=marketDetail.singleDay/marketDetail.length;1205 cacheContext.font=fontSize+"px Arial";1206 cacheContext.textAlign="center";1207 cacheContext.textBaseline="top";1208 cacheContext.fillStyle="#999";1209 for(i=1,l=marketDetail.length;i<l;i++){1210 position=i*avg;1211 if(position>=start && position<start+amount){1212 x=leftX+(position-start)*(gapWidth+kWidth);1213 painterTool.drawDashed(1214 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridTop)},1215 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridBottom)}1216 );1217 cacheContext.fillText(marketDetail[i-1].close_time+"/"+marketDetail[i].open_time,x,gridTop);1218 }1219 }1220 //绘制头尾x轴时间1221 cacheContext.textAlign="left";1222 if(data[start]){1223 if(data.marketDetail.inAmerica){1224 date=painterTool.transferAmericaTime(data[start][0]+"");1225 }else{1226 date=data[start][0]+"";1227 }1228 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1229 }else{1230 date="--";1231 }1232 cacheContext.fillText(date,leftX,gridBottom);1233 cacheContext.textAlign="right";1234 if(end>=data.length){1235 //marketDetail的时间已经转换过了1236 date=data.marketDetail[data.marketDetail.length-1].close_time+"";1237 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1238 }else{1239 if(data.marketDetail.inAmerica){1240 date=painterTool.transferAmericaTime(data[end-1][0]+"");1241 }else{1242 date=data[end-1][0]+"";1243 }1244 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1245 }1246 cacheContext.fillText(date,rightX,gridBottom);1247 };1248 //绘制坐标轴文字1249 draw1Text=function(){1250 var middleY;1251 middleY=topY+height/2;1252 //绘制y轴数字1253 cacheContext.font=fontSize+"px Arial";1254 cacheContext.textAlign="left";1255 cacheContext.textBaseline="top";1256 cacheContext.fillStyle=kColor[1];1257 cacheContext.fillText(max.toFixed(2),leftX,topY);1258 cacheContext.textAlign="right";1259 cacheContext.fillText((100*(max-middle)/middle).toFixed(2)+"%",rightX,topY);1260 cacheContext.textAlign="left";1261 cacheContext.textBaseline="bottom";1262 cacheContext.fillStyle=kColor[0];1263 cacheContext.fillText(min.toFixed(2),leftX,bottomY);1264 cacheContext.textAlign="right";1265 cacheContext.fillText((100*(middle-min)/middle).toFixed(2)+"%",rightX,bottomY);1266 cacheContext.textAlign="left";1267 cacheContext.textBaseline="middle";1268 cacheContext.fillStyle="#999";1269 cacheContext.fillText(middle.toFixed(2),leftX,middleY);1270 cacheContext.textAlign="right";1271 cacheContext.fillText("0.00%",rightX,middleY);1272 };1273 //绘制分时图折线图&渐变阴影图1274 draw1Trend=function(){1275 var i,l,gradient,ballY;1276 //避免出现卡顿动画1277 if(end-start<40){1278 process=1;1279 }1280 trendX=leftX;1281 l=start+Math.floor((end-start)*process);1282 //---绘制折线图1283 cacheContext.beginPath();1284 cacheContext.strokeStyle="#3b7fed";1285 cacheContext.moveTo(trendX,data[start].axis);1286 for(i=start+1;i<l-1;i++){1287 trendX+=gapWidth+kWidth;1288 cacheContext.lineTo(trendX,data[i].axis);1289 }1290 //为避免最后一个数据超出grid,单独处理1291 trendX+=gapWidth+kWidth;1292 if(trendX>rightX){1293 trendX=rightX;1294 }1295 if(i<data.length){1296 cacheContext.lineTo(trendX,data[i].axis);1297 cacheContext.stroke();1298 }1299 //---绘制渐变阴影1300 cacheContext.beginPath();1301 try{1302 gradient=cacheContext.createLinearGradient(leftX,topY+height*(max-valueMax)/range,leftX,bottomY);1303 gradient.addColorStop(0.45,"#c2deff");1304 gradient.addColorStop(1,"rgba(255,255,255,0)");1305 }catch(e){1306 console.info("openapiError:",e);1307 }1308 cacheContext.fillStyle=gradient;1309 cacheContext.moveTo(leftX,bottomY);1310 trendX=leftX;1311 for(i=start;i<l-1;i++){1312 cacheContext.lineTo(trendX,data[i].axis);1313 trendX+=gapWidth+kWidth;1314 }1315 //为避免最后一个数据超出grid,单独处理1316 if(trendX>rightX){1317 trendX=rightX;1318 }1319 if(i<data.length){1320 cacheContext.lineTo(trendX,data[i].axis);1321 }1322 cacheContext.lineTo(trendX,bottomY);1323 cacheContext.closePath();1324 cacheContext.fill();1325 //---绘制分时图均价线1326 trendX=leftX;1327 cacheContext.beginPath();1328 cacheContext.strokeStyle="#ffc436";1329 cacheContext.moveTo(trendX,data[start].avgAxis);1330 for(i=start+1;i<l-1;i++){1331 trendX+=gapWidth+kWidth;1332 cacheContext.lineTo(trendX,data[i].avgAxis);1333 }1334 //为避免最后一个数据超出grid,单独处理1335 trendX+=gapWidth+kWidth;1336 if(trendX>rightX){1337 trendX=rightX;1338 }1339 if(i<data.length){1340 cacheContext.lineTo(trendX,data[i].avgAxis);1341 }1342 cacheContext.stroke();1343 //绘制头部球1344 if(process==1 && i==data.length-1){1345 ballY=data[i].axis;1346 drawBall(trendX,ballY);1347 }1348 };1349 //绘制五日分时网格1350 draw5Grid=function(){1351 var stepY,i,x,amount,l,date,position,gridTop,1352 gridBottom,wordLength;1353 cacheContext.beginPath();1354 cacheContext.strokeStyle="#000";1355 cacheContext.lineWidth=1;1356 //绘制实线1357 gridTop=topY-gridExpand;1358 gridBottom=bottomY+gridExpand;1359 cacheContext.moveTo(leftX,gridTop);1360 cacheContext.lineTo(rightX,gridTop);1361 cacheContext.lineTo(rightX,gridBottom);1362 cacheContext.lineTo(leftX,gridBottom);1363 cacheContext.closePath();1364 cacheContext.stroke();1365 //绘制虚线1366 amount=4;1367 stepY=height/amount;1368 for(i=1;i<amount;i++){1369 painterTool.drawDashed(1370 {x:painterTool.getOdd(leftX),y:painterTool.getOdd(gridTop+i*stepY)},1371 {x:painterTool.getOdd(rightX),y:painterTool.getOdd(gridTop+i*stepY)}1372 );1373 }1374 //绘制分时时间1375 amount=5;1376 l=data.marketDetail.singleDay;1377 cacheContext.font=fontSize+"px Arial";1378 cacheContext.textAlign="left";1379 cacheContext.textBaseline="top";1380 cacheContext.fillStyle="#999";1381 if(start==0){1382 date=data[0][0]+"";1383 date=date.substring(4,6)+"-"+date.substring(6,8);1384 cacheContext.fillText(date,leftX,gridBottom);1385 }1386 for(i=1;i<amount;i++){1387 position=i*l;1388 if(position>=start && position<end){1389 x=leftX+(position-start)*(gapWidth+kWidth);1390 date=data[position][0]+"";1391 date=date.substring(4,6)+"-"+date.substring(6,8);1392 wordLength=cacheContext.measureText(date).width;1393 if(x+wordLength>rightX){1394 cacheContext.textAlign="right";1395 x=rightX;1396 }1397 cacheContext.fillText(date,x,gridBottom);1398 painterTool.drawDashed(1399 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridTop)},1400 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridBottom)}1401 );1402 }1403 }1404 };1405 //绘制五日分时图折线图&渐变阴影图&均价1406 draw5Trend=function(){1407 var i,l,gradient,amount;1408 //避免出现卡顿动画1409 if(end-start<40){1410 process=1;1411 }1412 trendX=leftX;1413 l=start+Math.floor((end-start)*process);1414 amount=marketDetail.singleDay;1415 //---绘制折线图1416 cacheContext.beginPath();1417 cacheContext.strokeStyle="#3b7fed";1418 cacheContext.moveTo(trendX,data[start].axis);1419 for(i=start+1;i<l-1;i++){1420 trendX+=gapWidth+kWidth;1421 if(i%amount==0){1422 cacheContext.stroke();1423 cacheContext.beginPath();1424 cacheContext.moveTo(trendX,data[i].axis);1425 continue;1426 }1427 cacheContext.lineTo(trendX,data[i].axis);1428 }1429 //为避免最后一个数据超出grid,单独处理1430 trendX+=gapWidth+kWidth;1431 if(trendX>rightX){1432 trendX=rightX;1433 }1434 cacheContext.lineTo(trendX,data[i].axis);1435 cacheContext.stroke();1436 //---绘制渐变阴影1437 cacheContext.beginPath();1438 gradient=cacheContext.createLinearGradient(leftX,topY+height*(max-valueMax)/range,leftX,bottomY);1439 gradient.addColorStop(0.45,"#c2deff");1440 gradient.addColorStop(1,"rgba(255,255,255,0)");1441 cacheContext.fillStyle=gradient;1442 cacheContext.moveTo(leftX,bottomY);1443 trendX=leftX;1444 for(i=start;i<l-1;i++){1445 cacheContext.lineTo(trendX,data[i].axis);1446 trendX+=gapWidth+kWidth;1447 }1448 //为避免最后一个数据超出grid,单独处理1449 if(trendX>rightX){1450 trendX=rightX;1451 }1452 cacheContext.lineTo(trendX,data[i].axis);1453 cacheContext.lineTo(trendX,bottomY);1454 cacheContext.closePath();1455 cacheContext.fill();1456 //---绘制分时图均价线1457 trendX=leftX;1458 cacheContext.beginPath();1459 cacheContext.strokeStyle="#ffc436";1460 cacheContext.moveTo(trendX,data[start].avgAxis);1461 for(i=start+1;i<l-1;i++){1462 trendX+=gapWidth+kWidth;1463 if(i%amount==0){1464 cacheContext.stroke();1465 cacheContext.beginPath();1466 cacheContext.moveTo(trendX,data[i].axis);1467 continue;1468 }1469 cacheContext.lineTo(trendX,data[i].avgAxis);1470 }1471 //为避免最后一个数据超出grid,单独处理1472 trendX+=gapWidth+kWidth;1473 if(trendX>rightX){1474 trendX=rightX;1475 }1476 if(i%amount!=0) {1477 cacheContext.lineTo(trendX, data[i].avgAxis);1478 }1479 cacheContext.stroke();1480 };1481 //绘制五日分时图y轴坐标1482 draw5Text=function(){1483 var middleY;1484 middleY=topY+height/2;1485 //绘制y轴数字1486 cacheContext.font=fontSize+"px Arial";1487 cacheContext.textAlign="left";1488 cacheContext.textBaseline="top";1489 cacheContext.fillStyle=kColor[1];1490 cacheContext.fillText(max.toFixed(2),leftX,topY);1491 cacheContext.textAlign="right";1492 cacheContext.fillText((100*(max-middle)/middle).toFixed(2)+"%",rightX,topY);1493 cacheContext.textAlign="left";1494 cacheContext.textBaseline="bottom";1495 cacheContext.fillStyle=kColor[0];1496 cacheContext.fillText(min.toFixed(2),leftX,bottomY);1497 cacheContext.textAlign="right";1498 cacheContext.fillText((100*(middle-min)/middle).toFixed(2)+"%",rightX,bottomY);1499 cacheContext.textAlign="left";1500 cacheContext.textBaseline="middle";1501 cacheContext.fillStyle="#999";1502 cacheContext.fillText(middle.toFixed(2),leftX,middleY);1503 cacheContext.textAlign="right";1504 cacheContext.fillText("0.00%",rightX,middleY);1505 };1506 //绘制一日分时图帧1507 draw1Frame=function(){1508 draw1Grid();1509 if(start<data.length){1510 draw1Trend();1511 }1512 draw1Text();1513 };1514 //绘制五日分时图帧1515 draw5Frame=function(){1516 draw5Grid();1517 draw5Trend();1518 draw5Text();1519 };1520 //模块模式为一个闭包,输出函数不能动态变化1521 drawFrame=function(){1522 if(marketDetail.dayAmount==1){1523 draw1Frame();1524 }else if(marketDetail.dayAmount==5){1525 draw5Frame();1526 }1527 };1528 //绘制分时图圆角矩形1529 drawRoundRect=function(x,y,w,h){1530 var r,change;1531 r=h/4;1532 change=2;1533 x-=change;1534 y-=change;1535 w+=change*2;1536 h+=change*2;1537 if(x<leftX){1538 x=leftX;1539 }else if((x+w)>rightX){1540 x=rightX-w;1541 }1542 if(y<topY){1543 y=topY;1544 }else if(y+h>bottomY){1545 y=bottomY-h;1546 }1547 cacheCursorContext.beginPath();1548 cacheCursorContext.strokeStyle="#999";1549 cacheCursorContext.fillStyle="#ddd";1550 cacheCursorContext.moveTo(x+r,y);1551 cacheCursorContext.arcTo(x+w,y,x+w,y+h,r);1552 cacheCursorContext.arcTo(x+w,y+h,x,y+h,r);1553 cacheCursorContext.arcTo(x,y+h,x,y,r);1554 cacheCursorContext.arcTo(x,y,x+r,y,r);1555 cacheCursorContext.stroke();1556 cacheCursorContext.fill();1557 };1558 //绘制x轴tip1559 drawXTip=function(x,data){1560 var content,contentLength;1561 //线1562 cacheCursorContext.beginPath();1563 cacheCursorContext.strokeStyle="#000";1564 cacheCursorContext.moveTo(x,topY);1565 cacheCursorContext.lineTo(x,bottomY);1566 cacheCursorContext.stroke();1567 //背景,先设置字体,否则宽度计算错误1568 cacheCursorContext.font=fontSize+"px Arial";1569 content=data[0];1570 contentLength=cacheCursorContext.measureText(content).width/2;1571 drawRoundRect(x-contentLength,bottomY-fontSize,contentLength*2,fontSize);1572 //文字1573 cacheCursorContext.fillStyle="#999";1574 cacheCursorContext.textBaseline="bottom";1575 contentLength=cacheCursorContext.measureText(content).width/2;1576 if(x+contentLength>rightX){1577 cacheCursorContext.textAlign="right";1578 cacheCursorContext.fillText(content,rightX,bottomY);1579 }else if(x-contentLength<leftX){1580 cacheCursorContext.textAlign="left";1581 cacheCursorContext.fillText(content,leftX,bottomY);1582 }else{1583 cacheCursorContext.textAlign="center";1584 cacheCursorContext.fillText(content,x,bottomY);1585 }1586 };1587 //绘制y轴tip1588 drawYTip=function(y,data){1589 var content,contentLength;1590 if(y>bottomY){1591 y=bottomY;1592 }1593 //线1594 cacheCursorContext.beginPath();1595 cacheCursorContext.strokeStyle="#000";1596 cacheCursorContext.moveTo(leftX,y);1597 cacheCursorContext.lineTo(rightX,y);1598 cacheCursorContext.stroke();1599 //背景1600 content=(max-range*(y-topY)/height).toFixed(2);1601 contentLength=cacheCursorContext.measureText(content).width;1602 drawRoundRect(leftX,y-fontSize/2,contentLength,fontSize);1603 //文字1604 cacheCursorContext.fillStyle="#999";1605 cacheCursorContext.font=fontSize+"px Arial";1606 cacheCursorContext.textAlign="left";1607 if(y+fontSize/2>bottomY){1608 cacheCursorContext.textBaseline="bottom";1609 y=bottomY;1610 }else if(y-fontSize/2<topY){1611 cacheCursorContext.textBaseline="top";1612 y=topY;1613 }else{1614 cacheCursorContext.textBaseline="middle";1615 }1616 cacheCursorContext.fillText(content,leftX,y);1617 };1618 //绘制分时图十字光标1619 drawCursor=function(x,y){1620 var temp,width=gapWidth+kWidth;1621 /*-------------公式计算找坐标---------------*/1622 //计算触控事件所在的K线数据索引1623 /*cursorIndex=Math.ceil((x-leftX-gapWidth/2-width)/width)+1;1624 //光标头部越界1625 cursorIndex=cursorIndex<1 ? 1:cursorIndex;1626 //光标尾部越界1627 cursorIndex=cursorIndex<end-start ? cursorIndex:end-start;1628 //计算柱中心坐标1629 cursorX=painterTool.getOdd(leftX+gapWidth/2+cursorIndex*width-width/2);*/1630 /*-------------遍历找坐标---------------*/1631 cursorX=leftX+width/2;1632 cursorIndex=1;1633 while(cursorX<x){1634 cursorIndex++;1635 cursorX+=width;1636 }1637 //尾部取数据数组越界1638 cursorIndex+=start-1;1639 if(cursorIndex<data.length){1640 cursorX=painterTool.getOdd(cursorX-width/2);1641 }else{1642 temp=data.length-start-1;1643 temp=temp<0 ? 0:temp;1644 cursorIndex=data.length-1;1645 cursorX=painterTool.getOdd(leftX+temp*width);1646 }1647 drawXTip(cursorX,data[cursorIndex]);1648 drawYTip(painterTool.getOdd(y),data[cursorIndex]);1649 };1650 /*1651 * 初始化基本配置1652 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1653 */1654 initSize=function(){1655 initValue();1656 };1657 /*1658 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1659 * trendData为分时数据,包含preclosePx昨收价1660 * trendData包含marketDetail数组,开盘收盘时间数组和分时图总数1661 */1662 drawReady=function(trendData,startPosition,endPosition){1663 if(!trendData || trendData.length==0){1664 return ;1665 }1666 data=trendData;1667 start=startPosition;1668 end=endPosition;1669 marketDetail=data.marketDetail;1670 handleData();1671 };1672 //onresize重绘1673 resizeDraw=function(){1674 initValue();1675 calcAxis();1676 drawFrame();1677 };1678 //判断x,y是否在分时图绘制区域内1679 insideOf=function(x,y){1680 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1681 return true;1682 }else{1683 return false;1684 }1685 };1686 //绘制分时图十字光标1687 showCursor=function(x,y){1688 cursorShowed=true;1689 cursorPositionX=x;1690 cursorPositionY=y;1691 drawCursor(x,y);1692 };1693 //关闭十字光标1694 turnOffCursor=function(){1695 cursorShowed=false;1696 };1697 return {1698 initSize:initSize,1699 drawReady:drawReady,1700 drawFrame:drawFrame,1701 resizeDraw:resizeDraw,1702 showCursor:showCursor,1703 turnOffCursor:turnOffCursor,1704 insideOf:insideOf1705 };1706 })();1707 /*1708 * 分时图成交量绘图器1709 */1710 trendBarPainter=(function(){1711 //数据1712 var data,initValue,max,width,height,leftX,rightX,topY,1713 bottomY,barX,layout,start,end;1714 //方法1715 var initSize,drawReady,resizeDraw,drawFrame,handleData,drawGrid,1716 drawBar,calcAxis,insideOf,showCursor,drawCursor,drawCursorTip;1717 //固定配置1718 layout={a:0.74,b:0.01,c:0.01,d:0.01};1719 initValue=function(){1720 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);1721 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);1722 topY=painterTool.getOdd(realCanvas.height*layout.a,false);1723 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);1724 width=rightX-leftX;1725 height=bottomY-topY;1726 };1727 //计算交易量柱的高度1728 calcAxis=function(){1729 var i;1730 for(i=start;i<end;i++){1731 data[i].baHeight=data[i][3]/max*height;1732 }1733 };1734 //计算成交量的最大值1735 handleData=function(){1736 var i;1737 max=data[0][3];1738 for(i=0,l=data.length;i<l;i++){1739 //for(i=start+1;i<end;i++){1740 if(max<data[i][3]){1741 max=data[i][3];1742 }1743 }1744 max*=maxRate;1745 calcAxis();1746 };1747 //绘制边框虚线1748 drawGrid=function(){1749 var y;1750 cacheContext.beginPath();1751 cacheContext.strokeStyle="#000";1752 cacheContext.lineWidth=1;1753 //绘制实线1754 cacheContext.moveTo(leftX,topY);1755 cacheContext.lineTo(rightX,topY);1756 cacheContext.lineTo(rightX,bottomY);1757 cacheContext.lineTo(leftX,bottomY);1758 cacheContext.closePath();1759 cacheContext.stroke();1760 //绘制虚线1761 y=painterTool.getOdd(topY+height/2);1762 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});1763 //绘制y轴文字1764 cacheContext.fillStyle="#999";1765 cacheContext.font=fontSize+"px Arial";1766 cacheContext.textAlign="left";1767 cacheContext.textBaseline="top";1768 cacheContext.fillText("成交量:"+max,leftX,topY);1769 };1770 //绘制成交量柱1771 drawBar=function(x,data){1772 var y;1773 cacheContext.beginPath();1774 cacheContext.fillStyle=kColor[data.color];1775 cacheContext.moveTo(x,bottomY);1776 cacheContext.lineTo(x+kWidth,bottomY);1777 y=bottomY-data.baHeight*process;1778 cacheContext.lineTo(x+kWidth,y);1779 cacheContext.lineTo(x,y);1780 cacheContext.closePath();1781 cacheContext.fill();1782 };1783 //根据process进度情况,绘制交易量图形帧1784 drawFrame=function(){1785 var width=kWidth/2,y;1786 drawGrid();1787 if(start<data.length){1788 //绘制头部半个交易量柱1789 cacheContext.beginPath();1790 cacheContext.fillStyle=kColor[data[start].color];1791 cacheContext.moveTo(leftX,bottomY);1792 cacheContext.lineTo(leftX+width,bottomY);1793 y=bottomY-data[start].baHeight*process;1794 cacheContext.lineTo(leftX+width,y);1795 cacheContext.lineTo(leftX,y);1796 cacheContext.closePath();1797 cacheContext.fill();1798 //绘制中间交易量柱1799 barX=leftX+gapWidth+width;1800 for(var i=start+1;i<end-1;i++){1801 drawBar(barX,data[i]);1802 barX+=gapWidth+kWidth;1803 }1804 //绘制尾部半个交易量柱1805 if(barX+kWidth>rightX){1806 cacheContext.beginPath();1807 cacheContext.fillStyle=kColor[data[i].color];1808 cacheContext.moveTo(rightX,bottomY);1809 cacheContext.lineTo(rightX-width,bottomY);1810 y=bottomY-data[i].baHeight*process;1811 cacheContext.lineTo(rightX-width,y);1812 cacheContext.lineTo(rightX,y);1813 cacheContext.closePath();1814 cacheContext.fill();1815 }else{1816 if(i<data.length){1817 drawBar(barX,data[i]);1818 }1819 }1820 }1821 };1822 //显示分时图交易量1823 drawCursorTip=function(){1824 var content,gap,x;1825 gap=1.2*cacheCursorContext.measureText("成交量:"+max).width;1826 x=rightX-gap;1827 cacheCursorContext.font=fontSize+"px Arial";1828 cacheCursorContext.textBaseline="top";1829 cacheCursorContext.textAlign="left";1830 //成交量1831 content="成交量:"+data[cursorIndex][3];1832 cacheCursorContext.fillStyle=kColor[data[cursorIndex].color];1833 cacheCursorContext.fillText(content,x,topY);1834 };1835 //显示分时图交易量图十字光标1836 drawCursor=function(x,y){1837 cacheCursorContext.beginPath();1838 cacheCursorContext.strokeStyle="#000";1839 cacheCursorContext.moveTo(cursorX,topY);1840 cacheCursorContext.lineTo(cursorX,bottomY);1841 cacheCursorContext.stroke();1842 drawCursorTip();1843 };1844 /*1845 * 初始化基本配置1846 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1847 */1848 initSize=function(){1849 initValue();1850 };1851 /*1852 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1853 */1854 drawReady=function(trendData,startPosition,endPosition){1855 if(!trendData || trendData.length==0){1856 return ;1857 }1858 data=trendData;1859 start=startPosition;1860 end=endPosition;1861 handleData();1862 };1863 //onresize重绘1864 resizeDraw=function(){1865 initValue();1866 calcAxis();1867 drawFrame();1868 };1869 //判断x,y是否在绘制区域内1870 insideOf=function(x,y){1871 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1872 return true;1873 }else{1874 return false;1875 }1876 };1877 //绘制分时交易量图十字光标1878 showCursor=function(x,y){1879 drawCursor(x,y);1880 };1881 return {1882 initSize:initSize,1883 drawReady:drawReady,1884 drawFrame:drawFrame,1885 resizeDraw:resizeDraw,1886 showCursor:showCursor,1887 insideOf:insideOf1888 };1889 })();1890 /*1891 * 分时图五档/明细管理器1892 * 分时图五档明细采取节省流量的策略,展示什么刷新什么,因此会看到切换闪烁1893 */1894 textPainter=(function(){1895 //变量1896 var wdContent,mxContent,buttonTemplate,wdContainer,mxContainer,wdBtn,mxBtn;1897 //方法1898 var fillWDTemplate,fillMXTemplate,drawWD,drawMX,init,bindListener,1899 showWD,showMX;1900 //初始化text容器,加入dom树,display=none1901 init=function(){1902 //外部包裹的div1903 buttonTemplate='<ul class="stockgraph_wdmx_tab clearfix">'1904 +'<li id="stockgraph-wd" class="active">'1905 +'<a href="javascript:void(0)">五档</a>'1906 +'</li>'1907 +'<li id="stockgraph-mx">'1908 +'<a href="javascript:void(0)">明细</a href="javascript:void(0)">'1909 +'</li>'1910 +'</ul>';1911 textContainer=document.createElement("div");1912 textContainer.className="stockgraph_wdmx";1913 textContainer.style.display="none";1914 textContainer.innerHTML=buttonTemplate;1915 container.appendChild(textContainer);1916 //五档容器1917 wdContainer=document.createElement("div");1918 wdContainer.className="stockgraph_wd_mm";1919 //明细容器1920 mxContainer=document.createElement("div");1921 mxContainer.className="stockgraph_wd_mx";1922 //五档/明细按钮1923 wdBtn=document.getElementById("stockgraph-wd");1924 mxBtn=document.getElementById("stockgraph-mx");1925 //绑定切换事件1926 bindListener();1927 };1928 //切换到五档1929 showWD=function(){1930 wdContainer.style.display="block";1931 wdBtn.className="active";1932 mxContainer.style.display="none";1933 mxBtn.className="";1934 };1935 //切换到明细1936 showMX=function(){1937 wdContainer.style.display="none";1938 wdBtn.className="";1939 mxContainer.style.display="block";1940 mxBtn.className="active";1941 };1942 //绑定监听1943 bindListener=function(){1944 wdBtn.addEventListener("click",function(){1945 showWD();1946 if(wdContent!=undefined){1947 fillWDTemplate(wdContent);1948 }1949 requestDispatcher.getWD();1950 });1951 mxBtn.addEventListener("click",function(){1952 showMX();1953 if(mxContent!=undefined){1954 fillMXTemplate(mxContent);1955 }1956 requestDispatcher.getMX();1957 });1958 };1959 /*1960 * 填充五档模板1961 */1962 fillWDTemplate=function(data){1963 var wdTemplate,i,l,color,temp;1964 //卖1-卖51965 wdTemplate='<div class="stockgraph_wd_buy">';1966 temp=data.offer;1967 for(i=0,l=temp.length;i<l;i++){1968 color=temp[i].price<data.lastClosePx ? "d_color":"z_color";1969 wdTemplate+='<p class="clearfix">'1970 +'<span>卖'+(5-i)+'</span>'1971 +'<span class="'+color+'">'+temp[i].price+'</span>'1972 +'<span>'+temp[i].amount+'</span>'1973 +'</p>';1974 }1975 wdTemplate+='</div>';1976 //买1-买51977 wdTemplate+='<div class="stockgraph_wd_sell">';1978 temp=data.bid;1979 for(i=0,l=temp.length;i<l;i++){1980 color=temp[i].price<data.lastClosePx ? "d_color":"z_color";1981 wdTemplate+='<p class="clearfix">'1982 +'<span>买'+(i+1)+'</span>'1983 +'<span class="'+color+'">'+temp[i].price+'</span>'1984 +'<span>'+temp[i].amount+'</span>'1985 +'</p>';1986 }1987 wdTemplate+='</div>';1988 wdContainer.innerHTML=wdTemplate;1989 if(textContainer.contains(mxContainer)){1990 textContainer.removeChild(mxContainer);1991 }1992 textContainer.appendChild(wdContainer);1993 };1994 /*1995 * 填充明细模板1996 */1997 fillMXTemplate=function(data){1998 var i,l,color,mxTemplate,direction;1999 mxTemplate='<div class="stockgraph_mx_wrap">';2000 for(i=0,l=data.length;i<l;i++){2001 color=data[i].price<data.lastClosePx ? "d_color":"z_color";2002 direction=data[i].direction==0 ? "d_color":"z_color";2003 mxTemplate+='<p>'2004 +'<span class="time">'+data[i].time+'</span>'2005 +'<span class="'+color+'">'+data[i].price+'</span>'2006 +'<span class="'+direction+'">'+data[i].amount+'</span>'2007 +'</p>';2008 }2009 mxTemplate+='</div>';2010 mxContainer.innerHTML=mxTemplate;2011 if(textContainer.contains(wdContainer)){2012 textContainer.removeChild(wdContainer);2013 }2014 textContainer.appendChild(mxContainer);2015 };2016 //绘制五档2017 drawWD=function(content){2018 showWD();2019 wdContent=content;2020 fillWDTemplate(content);2021 };2022 //绘制明细2023 drawMX=function(content){2024 showMX();2025 mxContent=content;2026 fillMXTemplate(content);2027 };2028 return {2029 init:init,2030 drawWD:drawWD,2031 drawMX:drawMX2032 };2033 })();2034 /*2035 * 【K线蜡烛图、交易量柱图、MACD指标图】事件控制器,左右滑动、缩放事件、十字光标2036 */2037 kControl=(function(){2038 //变量2039 var totalLength,minScale,maxScale,scaleStep,scrollStep,currScale,2040 currPosition,data;2041 //方法2042 var init,draw,enlarge,narrow,scrollRight,scrollLeft,2043 calcMA,calcColor,showCursor,clearCursor,resize;2044 //固定变量2045 scaleStep=1;2046 scrollStep=1;2047 /*2048 * 计算均线值,传入股票数据和均线日期2049 * maData={2050 * 5:[[K线ma5,交易量ma5],[]...]2051 * }2052 */2053 calcMA=function(){2054 var i,j,k, l,sumk,sumb,maData;2055 maData={};2056 for(i=0,l=dayCount.length;i<l;i++){2057 maData[dayCount[i]]=[];2058 for(j=0;j<totalLength;j++){2059 if(j<dayCount[i]){2060 maData[dayCount[i]].push(["-","-"]);2061 continue;2062 }2063 sumk=0;2064 sumb=0;2065 for(k=0;k<dayCount[i];k++){2066 sumk+=data[j-k][4];2067 sumb+=data[j-k][5];2068 }2069 maData[dayCount[i]].push([sumk/dayCount[i],sumb/dayCount[i]]);2070 }2071 maData[dayCount[i]].push("-");2072 }2073 data.maData=maData;2074 };2075 //计算颜色指标2076 calcColor=function(){2077 for(var i=0;i<totalLength;i++){2078 //颜色指标2079 if(data[i][4]>=data[i][1]){2080 data[i].color=1;2081 }else{2082 data[i].color=0;2083 }2084 }2085 };2086 //日K十字光标2087 showCursor=function(x,y){2088 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2089 for(var i in painterStack){2090 painterStack[i].showCursor(x,y);2091 }2092 refreshCursorCache();2093 };2094 //清除日K十字光标2095 clearCursor=function(){2096 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2097 refreshCursorCache();2098 candlePainter.showMAText();2099 };2100 //控制器启动绘图2101 draw=function(){2102 var start;2103 start=currPosition-currScale;2104 start=start<0 ? 0:start;2105 currPosition=currPosition>totalLength ? totalLength:currPosition;2106 for(var i in painterStack){2107 painterStack[i].drawReady(data,start,currPosition,currScale);2108 }2109 animate();2110 };2111 //初始化比例尺2112 init=function(){2113 data=rawData;2114 totalLength=data.length;2115 /*minScale=totalLength>40 ? 40:totalLength;2116 maxScale=totalLength>100 ? 100:totalLength;2117 currScale=totalLength>60 ? 60:totalLength;*/2118 minScale=40;2119 maxScale=100;2120 currScale=totalLength>minScale ? (totalLength>60 ? 60:totalLength):minScale;2121 currPosition=totalLength;2122 calcMA();2123 calcColor();2124 draw();2125 };2126 //切换K线图种类时重新计算长宽2127 resize=function(){2128 for(var i in painterStack){2129 painterStack[i].initSize();;2130 }2131 };2132 //放大-减少显示条数2133 enlarge=function(){2134 if(currScale>minScale){2135 currScale-=scaleStep;2136 if(currScale<minScale){2137 currScale=minScale;2138 }2139 draw();2140 }else{2141 return ;2142 }2143 };2144 //缩小-增加显示条数2145 narrow=function(){2146 if(currScale<maxScale){2147 currScale+=scaleStep;2148 if(currScale>maxScale){2149 currScale=maxScale;2150 }2151 if(currScale>currPosition){2152 currPosition=currScale;2153 }2154 draw();2155 }else{2156 return ;2157 }2158 };2159 //手指向右滑动-数据向左滚动2160 scrollRight=function(){2161 if(currPosition>currScale){2162 currPosition-=scrollStep;2163 if(currPosition<currScale){2164 currPosition=currScale;2165 }2166 draw();2167 }else{2168 return ;2169 }2170 };2171 //手指向左滑动-数据向右滚动2172 scrollLeft=function(){2173 if(currPosition<totalLength){2174 currPosition+=scrollStep;2175 if(currPosition>totalLength){2176 currPosition=totalLength;2177 }2178 draw();2179 }else{2180 return ;2181 }2182 };2183 return {2184 init:init,2185 resize:resize,2186 enlarge:enlarge,2187 narrow:narrow,2188 scrollLeft:scrollLeft,2189 scrollRight:scrollRight,2190 showCursor:showCursor,2191 clearCursor:clearCursor2192 };2193 })();2194 /*2195 * 【K线分时图、交易量柱图】事件控制器,左右滑动、缩放事件、十字光标2196 */2197 trendControl=(function(){2198 //变量2199 var totalLength,minScale,maxScale,scaleStep,scrollStep,currScale,2200 currPosition,data;2201 //方法2202 var init,draw,enlarge,narrow,scrollRight,scrollLeft,calcColor,2203 calcBusinessAmount,showCursor,clearCursor,resize;2204 //计算交易量值2205 calcBusinessAmount=function(){2206 if(data.append){2207 return ;2208 }2209 var i,l;2210 //倒叙相减2211 for(l=data.length,i=l-1;i>0;i--){2212 data[i][3]=data[i][3]-data[i-1][3];2213 }2214 };2215 //计算交易量柱的颜色2216 calcColor=function(){2217 var i,l;2218 //增量分时图2219 if(data.append){2220 return ;2221 }2222 //第一个柱和昨收比2223 if(data[0][1]<data.preclosePx){2224 data[0].color=0;2225 }else{2226 data[0].color=1;2227 }2228 for(i=1,l=data.length;i<l;i++){2229 if(data[i][1]<data[i-1][1]){2230 data[i].color=0;2231 }else{2232 data[i].color=1;2233 }2234 }2235 };2236 //控制器启动绘图2237 draw=function(){2238 var start,end;2239 start=currPosition-currScale;2240 start=start<0 ? 0:start;2241 end=currPosition<data.length ? currPosition+1:data.length;2242 //放大缩小时2243 data.marketDetail.amount=currScale;2244 for(var i in painterStack){2245 painterStack[i].drawReady(data,start,end);2246 }2247 animate();2248 };2249 //分时图十字光标2250 showCursor=function(x,y){2251 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2252 for(var i in painterStack){2253 painterStack[i].showCursor(x,y);2254 }2255 refreshCursorCache();2256 };2257 //清除分时图十字光标2258 clearCursor=function(){2259 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2260 refreshCursorCache();2261 trendPainter.turnOffCursor();2262 };2263 //初始化比例尺2264 init=function(){2265 data=rawData;2266 if(!data.append){2267 //非增量初始化2268 totalLength=data.marketDetail.amount;2269 if(data.marketDetail.dayAmount==5){2270 scaleStep=20;2271 scrollStep=5;2272 minScale=parseInt(totalLength*0.4);2273 }else{2274 scaleStep=5;2275 scrollStep=1;2276 minScale=parseInt(totalLength*0.6);2277 }2278 maxScale=totalLength;2279 currScale=totalLength;2280 currPosition=totalLength;2281 }2282 calcBusinessAmount();2283 calcColor();2284 draw();2285 };2286 //切换K线图种类时重新计算长宽2287 resize=function(){2288 for(var i in painterStack){2289 painterStack[i].initSize();;2290 }2291 };2292 //放大-减少显示条数2293 enlarge=function(){2294 if(currScale>minScale){2295 currScale-=scaleStep;2296 if(currScale<minScale){2297 currScale=minScale;2298 }2299 draw();2300 }else{2301 return ;2302 }2303 };2304 //缩小-增加显示条数2305 narrow=function(){2306 if(currScale<maxScale){2307 currScale+=scaleStep;2308 if(currScale>maxScale){2309 currScale=maxScale;2310 }2311 if(currScale>currPosition){2312 currPosition=currScale;2313 }2314 draw();2315 }else{2316 return ;2317 }2318 };2319 //手指向右滑动-数据向左滚动2320 scrollRight=function(){2321 if(currPosition>currScale){2322 currPosition-=scrollStep;2323 if(currPosition<currScale){2324 currPosition=currScale;2325 }2326 draw();2327 }else{2328 return ;2329 }2330 };2331 //手指向左滑动-数据向右滚动2332 scrollLeft=function(){2333 if(currPosition<totalLength){2334 currPosition+=scrollStep;2335 if(currPosition>totalLength){2336 currPosition=totalLength;2337 }2338 draw();2339 }else{2340 return ;2341 }2342 };2343 return {2344 init:init,2345 resize:resize,2346 enlarge:enlarge,2347 narrow:narrow,2348 scrollLeft:scrollLeft,2349 scrollRight:scrollRight,2350 showCursor:showCursor,2351 clearCursor:clearCursor2352 };2353 })();2354 /*------------------------绘图器end---------------------------*/2355 /*2356 * 管理K线图的事件,绑定、解绑、页面刷新时重计算坐标2357 */2358 eventControl=(function(){2359 //变量2360 var hammerManager,hammerPan,hammerPinch,hammerPress,offsetLeft,offsetTop,2361 x,y,cursorShowed;2362 //方法-避免事件未被清理2363 var press,pressup,panup,pandown,panright,panleft,2364 panend,pinchin,pinchout,mousewheel,setup,bindListener,2365 destroy,setOffset;2366 hammerPan=new Hammer.Pan();2367 hammerPinch = new Hammer.Pinch();2368 hammerPress=new Hammer.Press();2369 hammerManager=new Hammer.Manager(canvasContainer);2370 hammerManager.add([hammerPan,hammerPinch,hammerPress]);2371 //长按2372 press=function(e){2373 cursorShowed=true;2374 currControl.showCursor(x,y);2375 };2376 //抬起手指2377 pressup=function(e){2378 cursorShowed=false;2379 currControl.clearCursor();2380 };2381 //向上滑2382 panup=function(e){2383 if(cursorShowed){2384 currControl.showCursor(x,y);2385 }2386 };2387 //向下滑2388 pandown=function(e){2389 if(cursorShowed){2390 currControl.showCursor(x,y);2391 }2392 };2393 //手指右滑2394 panright=function(e){2395 if(cursorShowed){2396 currControl.showCursor(x,y);2397 }else{2398 currControl.scrollRight();2399 }2400 };2401 //手指左滑2402 panleft=function(e){2403 if(cursorShowed){2404 currControl.showCursor(x,y);2405 }else{2406 currControl.scrollLeft();2407 }2408 };2409 //结束滑动2410 panend=function(e){2411 if(cursorShowed){2412 cursorShowed=false;2413 currControl.clearCursor();2414 }2415 };2416 //缩小2417 pinchin=function(e){2418 currControl.narrow();2419 };2420 //放大2421 pinchout=function(e){2422 currControl.enlarge();2423 };2424 mousewheel=function(e){2425 panend();2426 if(e.wheelDelta>0){2427 pinchin(e);2428 }else if(e.wheelDelta<0){2429 pinchout(e);2430 }2431 e.preventDefault();2432 };2433 //AOP封装方法2434 setup=function(callback){2435 return function(e){2436 x=(e.changedPointers[0].pageX-offsetLeft)*pixel;2437 y=(e.changedPointers[0].pageY-offsetTop)*pixel;2438 for(var i in painterStack){2439 if(painterStack[i].insideOf(x,y)){2440 callback(e);2441 return ;2442 }2443 }2444 if(cursorShowed){2445 currControl.clearCursor();2446 }2447 };2448 };2449 bindListener=function(){2450 //绑定所有事件2451 hammerManager.on("press",setup(press));2452 hammerManager.on("pressup",setup(pressup));2453 hammerManager.on("panup",setup(panup));2454 hammerManager.on("pandown",setup(pandown));2455 hammerManager.on("panright",setup(panright));2456 hammerManager.on("panleft",setup(panleft));2457 hammerManager.on("panend",setup(panend));2458 hammerManager.on("pinchin",pinchin);2459 hammerManager.on("pinchout",pinchout);2460 //鼠标滚动缩放事件2461 canvasContainer.addEventListener("mousewheel",mousewheel);2462 };2463 //销毁所有已绑定的事件2464 destroy=function(){2465 hammerManager.destroy();2466 hammerManager=new Hammer.Manager(canvasContainer);2467 hammerManager.add([hammerPan,hammerPinch,hammerPress]);2468 };2469 //设置canvasContainer的偏移量,计算坐标点2470 setOffset=function(){2471 var parent;2472 parent=canvasContainer;2473 offsetLeft=parent.offsetLeft;2474 offsetTop=parent.offsetTop;2475 while(parent.offsetParent){2476 parent=parent.offsetParent;2477 offsetLeft+=parent.offsetLeft;2478 offsetTop+=parent.offsetTop;2479 }2480 };2481 return {2482 init:setOffset,2483 bindListener:bindListener,2484 destroy:destroy,2485 resize:setOffset2486 }2487 })();2488 /*2489 * 切换currControl,传入control对象2490 * 清除上一个control设置的监听事件2491 * 启动绘图方法2492 */2493 triggerControl=function(control){2494 if(currControl==control){2495 currControl.init();2496 return ;2497 }2498 painterStack=[];2499 if(control==trendControl){2500 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2501 refreshCursorCache();2502 painterStack.push(trendPainter);2503 painterStack.push(trendBarPainter);2504 canvasContainer.style.width="80%";2505 textContainer.style.display="block";2506 }else if(control==kControl){2507 painterStack.push(candlePainter);2508 painterStack.push(kBarPainter);2509 painterStack.push(extraPainterCollection.MACDPainter);2510 canvasContainer.style.width="100%";2511 textContainer.style.display="none";2512 }2513 //销毁上一个K线图的监听事件2514 eventControl.destroy();2515 //切换K线图控制器2516 currControl=control;2517 //重设画布长宽2518 initCanvas();2519 //重新计算事件坐标的偏移量2520 eventControl.resize();2521 //重新计算每个绘图器内部长宽边界2522 currControl.resize();2523 //绑定触控事件2524 eventControl.bindListener();2525 //开始绘制2526 currControl.init();2527 };2528 /*2529 * 动画,执行所有进入方法栈的drawFrame方法2530 * 如果process为1,则animate退化成无动画绘制2531 * 每个页面只执行一次动画,要修改的话,在最后一次animate将process初始化2532 */2533 animate=function(){2534 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2535 speed=Math.ceil((100-process*100)/30)/100;2536 process+=speed;2537 if(process<1){2538 for(var i in painterStack){2539 painterStack[i].drawFrame();2540 }2541 requestAnimationFrame(animate);2542 }else{2543 process=1;2544 for(var i in painterStack){2545 painterStack[i].drawFrame();2546 }2547 }2548 refreshCache();2549 };2550 //将虚拟画布上的图形刷新到画布上2551 refreshCache=function(){2552 canvasContainer.removeChild(realCanvas);2553 realContext.clearRect(0,0,realCanvas.width,realCanvas.height);2554 realContext.drawImage(cacheCanvas,0,0);2555 canvasContainer.appendChild(realCanvas);2556 };2557 //十字光标的画布缓冲绘图2558 refreshCursorCache=function(){2559 canvasContainer.removeChild(realCursorCanvas);2560 realCursorContext.clearRect(0,0,realCursorCanvas.width,realCursorCanvas.height);2561 realCursorContext.drawImage(cacheCursorCanvas,0,0);2562 canvasContainer.appendChild(realCursorCanvas);2563 };2564 //全局初始化,调用各个内部初始化方法,页面就绪即可执行2565 init=function(){2566 initCanvas();2567 eventControl.init();2568 candlePainter.initSize();2569 kBarPainter.initSize();2570 trendPainter.initSize();2571 trendBarPainter.initSize();2572 textPainter.init();2573 extraPainterCollection.initSize();2574 };2575 //开始绘制,接收接口返回的数据2576 draw=function(ajaxData,period){2577 loading=false;2578 rawData=ajaxData;2579 if(!rawData.append){2580 process=0;2581 }2582 if(period>9){2583 //分时图2584 triggerControl(trendControl);2585 }else{2586 //K线图2587 triggerControl(kControl);2588 }2589 };2590 //窗口大小变化时重绘2591 resize=function(){2592 initCanvas();2593 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2594 for(var i in painterStack){2595 painterStack[i].resizeDraw();2596 refreshCache();2597 }2598 eventControl.resize();2599 refreshCache();2600 };2601 //查询股票资料时展示loading2602 showLoading=function(){2603 realContext.clearRect(0,0,realCanvas.width,realCanvas.height);2604 loading=true;2605 setTimeout(function(){2606 if(loading){2607 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2608 cacheContext.font=fontSize*2+"px Arial";2609 cacheContext.textBaseline="bottom";2610 cacheContext.textAlign="center";2611 cacheContext.fillStyle="#999";2612 cacheContext.fillText("Loading...",cacheCanvas.width/2,cacheCanvas.height*0.382);2613 refreshCache();2614 }2615 },100);2616 };2617 return {2618 init:init,2619 draw:draw,2620 resize:resize,2621 showLoading:showLoading,2622 textPainter:textPainter2623 };2624 })();2625 /*2626 * 请求分派器,管理所有的ajax请求,并执行相应操作2627 */2628 requestDispatcher=(function(){2629 //变量2630 var authorization,storage,supportType,crc,minTime,trendTimer,textType;2631 //方法2632 var queryToken,queryKLine,queryTrend,queryMarketDetail,queryPreclosePx,handleToken,2633 handleKLine,handleTrend,handleMarketDetail,getKLine,setTimer,storeStorage,2634 queryTrend5Day,appendTrend,handleAppend,queryTick,queryReal,appendText,2635 handleText,handleWD,handleMX,getWD,getMX;2636 /*2637 * storage={2638 * code:2639 * period:2640 * trend:2641 * amount:2642 * preclosePx:2643 * text2644 * lastClosePx2645 * }2646 */2647 storage={};2648 //五档/明细/默认值2649 textType=["wd","mx","wd"];2650 supportType={2651 "1分钟":1,2652 "5分钟":2,2653 "15分钟":3,2654 "30分钟":4,2655 "60分钟":5,2656 "日K":6,2657 "周K":7,2658 "月K":8,2659 "年K":9,2660 "分时":10,2661 "五日":112662 };2663 //分时图设置定时器,优化美股时差2664 setTimer=function(){2665 var i,l,now,minutes;2666 clearInterval(trendTimer);2667 trendTimer=setInterval(function(){2668 if(storage.period<10){2669 clearInterval(trendTimer);2670 return ;2671 }2672 now=new Date();2673 minutes=now.getMinutes();2674 if(minutes<10){2675 minutes="0"+minutes;2676 }2677 now=parseInt(now.getHours()+""+minutes);2678 //开盘前刷新昨收价2679 if(now>storage.marketDetail[0].open_time-10 && now<storage.marketDetail[0].open_time){2680 queryPreclosePx(storage.code,storage.period,true);2681 }2682 for(i=0,l=storage.marketDetail.length;i<l;i++){2683 //后台部分接口数据有时间差,前后取缓冲时间2684 if(now>=storage.marketDetail[i].open_time-5 && now<=storage.marketDetail[i].close_time+10){2685 appendTrend();2686 appendText(storage.code,storage.text);2687 }2688 }2689 },6000);2690 };2691 /*2692 * 分时图多个数据存储2693 * real昨收 & marketDetail总量 & trend数据2694 */2695 storeStorage=function(code,period,attr,data){2696 if(code!=storage.code || period!=storage.period){2697 return ;2698 }2699 storage[attr]=data;2700 handleTrend();2701 };2702 //分时增量查询结果处理2703 handleAppend=function(data){2704 var now,temp;2705 storage.trend.append=true;2706 if(data.length==1){2707 //这分钟数据变动中2708 data[0][3]=data[0][3]-storage.trend.lastData[3];2709 data[0].color=data[0][1]<storage.trend.lastData[1] ? 0:1;2710 storage.trend.pop();2711 storage.trend.push(data[0]);2712 }else if(data.length==2){2713 //增量数据,这分钟数据确定了2714 now=new Date();2715 now=parseInt(now.getHours()+""+now.getMinutes());2716 //开盘清数据2717 if(now==storage.marketDetail[0].open_time){2718 storage.trend=[];2719 storage.trend.preclosePx=storage.preclosePx;2720 storage.trend.marketDetail=storage.marketDetail;2721 storage.trend.lastData=[0,0,0,0];2722 }2723 data[1][3]=data[1][3]-data[0][3];2724 temp=data[0].concat();2725 data[0][3]=data[0][3]-storage.trend.lastData[3];2726 data[0].color=data[0][1]<storage.trend.lastData[1] ? 0:1;2727 data[1].color=data[1][1]<data[0][1] ? 0:1;2728 storage.trend.lastData=temp;2729 storage.trend.pop();2730 storage.trend.push(data[0]);2731 storage.trend.push(data[1]);2732 }else{2733 //五日分时初始化append2734 var l=data.length-1;2735 data[l][3]=data[l][3]-storage.trend.lastData[3];2736 data[l].color=data[l][1]<storage.trend.lastData[1] ? 0:1;2737 storage.trend.pop();2738 storage.trend.push(data[l]);2739 }2740 KPainter.draw(storage.trend,storage.period);2741 };2742 /*2743 * 处理五档数据2744 * offer为逆序,显示在上,卖5-卖12745 * bid为正序,显示在下,买1-买52746 */2747 handleWD=function(data){2748 var content,temp,i,l,position,per;2749 per=data[1];2750 content={bid:[],offer:[]};2751 l=5;2752 //bid2753 temp=data[2];2754 temp=temp.split(",");2755 for(i=0;i<l;i++){2756 position=i*3;2757 content.bid.push({2758 price:+temp[position],2759 amount:Math.round(temp[position+1]/per)2760 });2761 }2762 //offer2763 temp=data[3];2764 temp=temp.split(",");2765 for(i=l-1;i>=0;i--){2766 position=i*3;2767 content.offer.push({2768 price:+temp[position],2769 amount:Math.round(temp[position+1]/per)2770 });2771 }2772 //昨收2773 content.lastClosePx=storage.lastClosePx;2774 KPainter.textPainter.drawWD(content);2775 //保存每手股数,供明细使用2776 storage.per=per;2777 };2778 /*2779 * 处理明细数据2780 * 生成一个对象数组,供textPainter使用2781 */2782 handleMX=function(data){2783 var content,i,l,time,length;2784 content=[];2785 for(i=0,l=data.length;i<l;i++){2786 time=data[i][0].toString();2787 length=time.length;2788 time=time.substring(length-6,length-4)+":"+time.substring(length-4,length-2)+":"+time.substring(length-2,length);2789 content.push({2790 time:time,2791 price:data[i][1],2792 amount:Math.round(data[i][2]/storage.per),2793 direction:data[i][3]2794 });2795 }2796 //昨收2797 content.lastClosePx=storage.lastClosePx;2798 KPainter.textPainter.drawMX(content);2799 };2800 //处理五档/明细2801 handleText=function(code,text,data){2802 var checker;2803 if(code!=storage.code || text!=storage.text){2804 return ;2805 }2806 //防止五档/明细处理时昨收数据还没返回2807 checker=setInterval(function(){2808 if(storage.lastClosePx!=undefined){2809 clearInterval(checker);2810 if(text==textType[0]){2811 handleWD(data);2812 }else if(text==textType[1]){2813 handleMX(data);2814 }2815 }2816 },10);2817 };2818 //校验code,period是否正确,执行蜡烛绘图方法2819 handleKLine=function(code,period,data){2820 if(code!=storage.code){2821 return ;2822 }2823 if(period!=storage.period){2824 return ;2825 }2826 KPainter.draw(data,period);2827 };2828 //检查数据完备与否,执行分时绘图方法,storage在刷新股票时会清空2829 handleTrend=function(){2830 var head;2831 if(storage.marketDetail==undefined || storage.trend==undefined || storage.preclosePx==undefined){2832 return ;2833 }2834 storage.trend.preclosePx=storage.preclosePx;2835 storage.trend.marketDetail=storage.marketDetail;2836 head=storage.trend.length-2;2837 head=head<0 ? 0:head;2838 storage.trend.lastData=storage.trend[head].concat();2839 KPainter.draw(storage.trend,storage.period);2840 };2841 //检查数据完备与否,计算分时总量,时间分布。storage在刷新股票时会清空2842 handleMarketDetail=function(code,period,data){2843 var marketDetail,amount,temp,open,close,hour,minute,inAmerica,2844 openHour,closeHour,openMinute,closeMinute;2845 marketDetail=data.trade_section_grp;2846 //openapi返回的时序有问题,冒泡排序2847 for(var i=0,l=marketDetail.length;i<l;i++){2848 for(var j=0,m=l-i-1;j<m;j++){2849 if(marketDetail[j].open_time>marketDetail[j+1].open_time){2850 temp=marketDetail[j];2851 marketDetail[j]=marketDetail[j+1];2852 marketDetail[j+1]=temp;2853 }2854 }2855 }2856 //计算时间差2857 amount=0;2858 marketDetail.inAmerica=Config.AmericanStockList.indexOf(code.split(".")[1])>-1 ? true:false;2859 for(i=0;i<l;i++){2860 open=marketDetail[i].open_time.toString();2861 close=marketDetail[i].close_time.toString();2862 openHour=open.substring(0,open.length-2);2863 closeHour=close.substring(0,close.length-2);2864 openMinute=open.substring(open.length-2,open.length);2865 closeMinute=close.substring(close.length-2,close.length);2866 hour=closeHour-openHour;2867 minute=closeMinute-openMinute;2868 //13:30-15:002869 if(minute<0){2870 hour-=1;2871 minute+=60;2872 }2873 amount+=hour*60+minute;2874 if(marketDetail.inAmerica){2875 //美股转换时差,painterTool访问不到2876 openHour=openHour-13;2877 openHour=openHour<0 ? openHour+24:openHour;2878 openHour=openHour<10 ? "0"+openHour:openHour;2879 marketDetail[i].open_time=openHour+openMinute;2880 closeHour=closeHour-13;2881 closeHour=closeHour<0 ? closeHour+24:closeHour;2882 closeHour=closeHour<10 ? "0"+closeHour:closeHour;2883 marketDetail[i].close_time=closeHour+closeMinute;2884 }2885 }2886 if(period==10){2887 marketDetail.amount=amount;2888 marketDetail.dayAmount=1;2889 marketDetail.singleDay=amount;2890 }else if(period==11){2891 marketDetail.amount=amount*5;2892 marketDetail.dayAmount=5;2893 marketDetail.singleDay=amount;2894 }2895 storeStorage(code,period,"marketDetail",marketDetail);2896 };2897 //openapi获取token成功2898 handleToken=function(result){2899 if(result){2900 authorization=result.token_type+" "+result.access_token;2901 }2902 if(storage.period!=undefined && storage.code!=undefined){2903 switch(storage.period){2904 case 10:2905 //分时图2906 queryMarketDetail(storage.code,storage.period);2907 queryTrend(storage.code,storage.period);2908 queryPreclosePx(storage.code,storage.period);2909 appendText(storage.code,storage.text);2910 setTimer();2911 break;2912 case 11:2913 //五日分时2914 queryMarketDetail(storage.code,storage.period);2915 queryTrend5Day(storage.code,storage.period);2916 queryPreclosePx(storage.code,storage.period);2917 appendText(storage.code,storage.text);2918 setTimer();2919 break;2920 default:2921 //K线图2922 queryKLine(storage.code,storage.period);2923 break;2924 }2925 }2926 };2927 //获取openapi的K线数据2928 queryKLine=function(code,period){2929 var localKLine;2930 localKLine=sessionStorage.getItem("kline");2931 localKLine=JSON.parse(localKLine);2932 if(localKLine && localKLine[code] && localKLine[code][period]){2933 handleKLine(code,period,localKLine[code][period].data.candle[code]);2934 }else{2935 Util.ajax({2936 type:"get",2937 url:"https://open.hscloud.cn/quote/v1/kline",2938 contentType:"application/x-www-form-urlencoded; charset=utf-8",2939 data:{2940 get_type:"offset",2941 prod_code:code,2942 candle_period:period,2943 fields:"open_px,high_px,low_px,close_px,business_amount",2944 data_count:2002945 },2946 beforeSend: function(request) {2947 request.setRequestHeader("Authorization",authorization);2948 },2949 success:function(result){2950 if(result){2951 localKLine || (localKLine={});2952 localKLine[code] || (localKLine[code]={});2953 localKLine[code][period]=result;2954 sessionStorage.setItem("kline",JSON.stringify(localKLine));2955 handleKLine(code,period,result.data.candle[code]);2956 }2957 },2958 error:function(error){2959 console.error("queryKLine:",error);2960 }2961 });2962 }2963 };2964 //获取openapi分时数据2965 queryTrend=function(code,period){2966 Util.ajax({2967 type:"get",2968 url:"https://open.hscloud.cn/quote/v1/trend",2969 contentType:"application/x-www-form-urlencoded; charset=utf-8",2970 data:{2971 prod_code:code,2972 fields:"last_px,avg_px,business_amount"2973 //,date:201703082974 },2975 beforeSend: function(request) {2976 request.setRequestHeader("Authorization",authorization);2977 },2978 success:function(result){2979 if(result){2980 var data=result.data.trend[code];2981 crc=result.data.trend.crc[code];2982 try{2983 minTime=data[data.length-1][0].toString().substring(8,12);2984 }catch(e){2985 console.info("openapiError:",e);2986 }2987 storeStorage(code,period,"trend",data);2988 }2989 },2990 error:function(error){2991 console.error("queryTrend:",error);2992 }2993 });2994 };2995 //分时图五档2996 queryReal=function(code,text){2997 Util.ajax({2998 type:"get",2999 url:"https://open.hscloud.cn/quote/v1/real",3000 contentType:"application/x-www-form-urlencoded; charset=utf-8",3001 data:{3002 en_prod_code:code,3003 fields:"bid_grp,offer_grp"3004 },3005 beforeSend: function(request) {3006 request.setRequestHeader("Authorization",authorization);3007 },3008 success:function(result){3009 if(result){3010 handleText(code,text,result.data.snapshot[code]);3011 }3012 },3013 error:function(error){3014 console.error("queryReal:",error);3015 }3016 });3017 };3018 //分时图明细3019 queryTick=function(code,text){3020 Util.ajax({3021 type:"get",3022 url:"https://open.hscloud.cn/quote/v1/tick",3023 contentType:"application/x-www-form-urlencoded; charset=utf-8",3024 data:{3025 prod_code:code,3026 fields:"hq_px,business_amount,business_direction",3027 data_count:103028 },3029 beforeSend: function(request) {3030 request.setRequestHeader("Authorization",authorization);3031 },3032 success:function(result){3033 if(result){3034 handleText(code,text,result.data.tick[code]);3035 }3036 },3037 error:function(error){3038 console.error("queryTick:",error);3039 }3040 });3041 };3042 //增量查询分时接口3043 appendTrend=function(){3044 Util.ajax({3045 type:"get",3046 url:"https://open.hscloud.cn/quote/v1/trend",3047 contentType:"application/x-www-form-urlencoded; charset=utf-8",3048 data:{3049 prod_code:storage.code,3050 fields:"last_px,avg_px,business_amount",3051 crc:crc,3052 min_time:minTime3053 //,date:201703083054 },3055 beforeSend: function(request) {3056 request.setRequestHeader("Authorization",authorization);3057 },3058 success:function(result){3059 if(result){3060 var data=result.data.trend[storage.code];3061 crc=result.data.trend.crc[storage.code];3062 minTime=data[data.length-1][0].toString().substring(8,12);3063 handleAppend(data);3064 }3065 },3066 error:function(error){3067 console.error("appendTrend:",error);3068 }3069 });3070 };3071 //定时刷新五档/明细的内容3072 appendText=function(code,text){3073 if(text==textType[0]){3074 queryReal(code,text);3075 }else if(text==textType[1]){3076 queryTick(code,text);3077 }3078 };3079 //获取openapi五日分时数据3080 queryTrend5Day=function(code,period){3081 Util.ajax({3082 type:"get",3083 url:"https://open.hscloud.cn/quote/v1/trend5day",3084 contentType:"application/x-www-form-urlencoded; charset=utf-8",3085 data:{3086 prod_code:code,3087 fields:"last_px,avg_px,business_amount"3088 },3089 beforeSend: function(request) {3090 request.setRequestHeader("Authorization",authorization);3091 },3092 success:function(result){3093 if(result){3094 //增量查询3095 var data=result.data.trend[code];3096 storeStorage(code,period,"trend",data);3097 }3098 },3099 error:function(){3100 console.error("queryTrend:",error);3101 }3102 });3103 };3104 //获取分时图数据总量3105 queryMarketDetail=function(code,period){3106 var postfix=code.split(".")[1];3107 //避免请求超时3108 if(Config.tradeSectionGrp[postfix]){3109 handleMarketDetail(code,period,Config.tradeSectionGrp[postfix]);3110 return ;3111 }3112 //请求marketDetail3113 Util.ajax({3114 type:"get",3115 url:"https://open.hscloud.cn/quote/v1/market/detail",3116 contentType:"application/x-www-form-urlencoded",3117 data:{3118 finance_mic:postfix3119 //finance_mic:"XSGE"3120 },3121 beforeSend:function(request) {3122 request.setRequestHeader("Authorization",authorization);3123 },3124 success:function(result){3125 if(result){3126 Config.tradeSectionGrp[postfix]=result.data;3127 handleMarketDetail(code,period,result.data);3128 }3129 },3130 error:function(error){3131 console.error("queryMarketDetail:",error);3132 }3133 });3134 };3135 //获取昨收价3136 queryPreclosePx=function(code,period,refreshNew){3137 var dataAcount;3138 dataAcount=period==10 ? 2:6;3139 Util.ajax({3140 type:"get",3141 url:"https://open.hscloud.cn/quote/v1/kline",3142 contentType:"application/x-www-form-urlencoded; charset=utf-8",3143 data:{3144 get_type:"offset",3145 prod_code:code,3146 candle_period:6,3147 fields:"close_px",3148 data_count:dataAcount3149 },3150 beforeSend: function(request) {3151 request.setRequestHeader("Authorization",authorization);3152 },3153 success:function(result){3154 if(result){3155 if(code==storage.code){3156 if(period==10){3157 storage.lastClosePx=result.data.candle[code][0][1];3158 }else if(period==11){3159 storage.lastClosePx=result.data.candle[code][4][1];3160 }3161 if(!refreshNew){3162 //如果是初始化,需要走storeStorage以执行handleTrend3163 storeStorage(code,period,"preclosePx",result.data.candle[code][0][1]);3164 }else{3165 //如果是开盘前,不需执行handleTrend3166 if(period==storage.period){3167 storage.preclosePx=result.data.candle[code][0][1];3168 }3169 }3170 }3171 }3172 },3173 error:function(error){3174 console.error("queryPreclosePx:",error);3175 }3176 });3177 };3178 //获取hundsun-openapi的token3179 queryToken=function(){3180 var APPKEY="your-key";3181 var APPSECRET="your-secret";3182 var BASIC="Basic ";3183 var auth=Base64.encode(APPKEY+":"+APPSECRET);3184 var openId="bigbird-kline:"+Math.random();3185 Util.ajax({3186 type:"post",3187 url:"https://open.hscloud.cn"+"/oauth2/oauth2/token",3188 contentType:"application/x-www-form-urlencoded",3189 data:{3190 grant_type:"client_credentials",3191 open_id:openId3192 },3193 beforeSend:function(request) {3194 request.setRequestHeader("Authorization", BASIC+auth);3195 },3196 success:function(result){3197 if(result){3198 handleToken(result);3199 }3200 },3201 error:function(error){3202 console.error("queryToken:",error);3203 }3204 });3205 };3206 /*3207 * 暴露给外部使用的查询方法。传入K线类别和股票代码为参数3208 * 1:1分钟 2:5分钟 3:15分钟 4:30分钟 5:60分钟 6:日K 7:周K 8:月K 9:年K3209 * 10:分时 11:五日3210 */3211 getKLine=function(period,code){3212 var per;3213 if(code!=undefined){3214 //保存之前的text状态3215 if(code!=storage.code){3216 textType[3]=textType[0];3217 }3218 //保存每手股数3219 per=storage.per;3220 //切换股票时刷新storage,避免分时图残留数据影响3221 storage={};3222 storage.code=code;3223 storage.text=textType[3];3224 storage.per=per;3225 }3226 storage.period=supportType[period];3227 if(authorization==undefined){3228 queryToken();3229 }else{3230 handleToken();3231 }3232 };3233 //切换到查询五档3234 getWD=function(){3235 storage.text=textType[0];3236 textType[3]=storage.text;3237 appendText(storage.code,storage.text);3238 };3239 //切换到查询明细3240 getMX=function(){3241 storage.text=textType[1];3242 textType[3]=storage.text;3243 appendText(storage.code,storage.text);3244 };3245 return {3246 getKLine:getKLine,3247 getWD:getWD,3248 getMX:getMX3249 };3250 })();3251 /*3252 * 页面控制器,管理页面启动,页面重置等页面级逻辑3253 */3254 pageControl=(function(){3255 //方法3256 var beginPage,bindListener;3257 //页面启动逻辑3258 beginPage=function(){3259 KPainter.init();3260 bindListener();3261 };3262 //页面重置3263 bindListener=function(){3264 window.addEventListener("resize",function(){3265 KPainter.resize();3266 });3267 };3268 return {3269 beginPage:beginPage3270 };3271 })();3272 StockGraph=(function(){3273 var draw;3274 draw=function(p,c){3275 KPainter.showLoading();3276 requestDispatcher.getKLine(p,c);3277 };3278 return {3279 draw:draw3280 };3281 })();3282 Util.ready(pageControl.beginPage);3283 window.StockGraph=StockGraph;...

Full Screen

Full Screen

stockgraph-mobile.js

Source:stockgraph-mobile.js Github

copy

Full Screen

1/*2 * created by bigbird on 2017/2/263 */4(function(){5 var KPainter,requestDispatcher,pageControl,Config,StockGraph;6 //避免marketDetail请求过大而设置的本地变量7 Config={8 tradeSectionGrp:{9 SS:{10 trade_section_grp:[{open_time:930,close_time:1130},{open_time:1300,close_time:1500}]11 },12 SZ:{13 trade_section_grp:[{open_time:930,close_time:1130},{open_time:1300,close_time:1500}]14 },15 HKM:{16 trade_section_grp:[{open_time:930,close_time:1200},{open_time:1300,close_time:1600}]17 }18 },19 AmericanStockList:["A","CBOT","COMEX","N","NYMEX","O","XBUS"]20 };21 /*22 * K线绘图器。本身作为总控制器,内部有多个绘图器23 */24 KPainter=(function(){25 //dom元素26 var container,realCanvas,cacheCanvas,realContext,cacheContext,pixel,27 realCursorCanvas,cacheCursorCanvas,realCursorContext,cacheCursorContext,28 textContainer,canvasContainer,maxRate,gridExpand;29 //配置变量30 var rawData,process,speed,totalTime,painterStack,kColor,kWidth,gapWidth,31 fontSize,maColor,gapOccupy,dayCount,loading,cursorIndex,cursorX;32 //方法&对象33 var init,draw,resize,refreshCache,candlePainter,kBarPainter,trendBarPainter,34 kControl,trendControl,refreshCursorCache,trendPainter,initDom,initCanvas,35 animate,painterTool,eventControl,currControl,triggerControl,showLoading,36 extraPainterCollection,textPainter;37 //初始化dom元素,仅需执行一次38 initDom=function(){39 //pixel=window.devicePixelRatio;40 pixel=2;41 //固定配置项42 painterStack=[];43 //[跌,涨]44 kColor=["#32a647","#fa5d5d"];45 //MA图线颜色46 maColor={5:"#f5a623",10:"#2e84e6",20:"#bd10e0"};47 //ma指标48 dayCount=[5,10,20];49 //柱图间隙占比50 gapOccupy=0.4;51 //文字大小52 fontSize=21*pixel;53 //最大值扩大比例54 maxRate=1;55 //边框扩大值56 gridExpand=pixel*3;57 //线性动画下动画总时长58 totalTime=800;59 //线性动画下递增速度(渐变动画时无效)60 speed=16/totalTime;61 //递增标志62 process=speed;63 //dom64 container=document.getElementById("k-container");65 canvasContainer=document.createElement("div");66 canvasContainer.style.float="left";67 canvasContainer.style.width="100%";68 canvasContainer.style.height="100%";69 container.appendChild(canvasContainer);70 realCanvas=canvasContainer.realCanvas || document.createElement("canvas");71 cacheCanvas=canvasContainer.cacheCanvas || document.createElement("canvas");72 realContext=realCanvas.getContext("2d");73 cacheContext=cacheCanvas.getContext("2d");74 realCanvas.style.position="absolute";75 canvasContainer.appendChild(realCanvas);76 //十字光标画布77 realCursorCanvas=canvasContainer.realCursorCanvas || document.createElement("canvas");78 cacheCursorCanvas=canvasContainer.cacheCursorCanvas || document.createElement("canvas");79 realCursorContext=realCursorCanvas.getContext("2d");80 cacheCursorContext=cacheCursorCanvas.getContext("2d");81 realCursorCanvas.style.position="absolute";82 realCursorCanvas.style.zIndex=1;83 canvasContainer.appendChild(realCursorCanvas);84 };85 initDom();86 87 //初始化画布长宽,在页面resize时需要重新执行88 initCanvas=function(){89 //避免移动设备screenPixel模糊问题90 cacheCanvas.width=canvasContainer.clientWidth*pixel;91 cacheCanvas.height=canvasContainer.clientHeight*pixel;92 realCanvas.width=canvasContainer.clientWidth*pixel;93 realCanvas.height=canvasContainer.clientHeight*pixel;94 realCanvas.style.width=canvasContainer.clientWidth+"px";95 realCanvas.style.height=canvasContainer.clientHeight+"px";96 //十字光标画布97 cacheCursorCanvas.width=canvasContainer.clientWidth*pixel;98 cacheCursorCanvas.height=canvasContainer.clientHeight*pixel;99 realCursorCanvas.width=canvasContainer.clientWidth*pixel;100 realCursorCanvas.height=canvasContainer.clientHeight*pixel;101 realCursorCanvas.style.width=canvasContainer.clientWidth+"px";102 realCursorCanvas.style.height=canvasContainer.clientHeight+"px";103 };104 /*------------------------工具方法---------------------------*/105 painterTool={106 //传入两个坐标点对象,绘制连接这两个点的虚线107 drawDashed:function(start,end){108 var gap=0.004,length=0.006,position=0,x,y,109 gapX,gapY,lengthX,lengthY,step;110 cacheContext.beginPath();111 cacheContext.strokeStyle="#ccc";112 cacheContext.lineWidth=2;113 gapX=(end.x-start.x)*gap;114 gapY=(end.y-start.y)*gap;115 lengthX=(end.x-start.x)*length;116 lengthY=(end.y-start.y)*length;117 step=gap+length;118 x=start.x;119 y=start.y;120 cacheContext.moveTo(x,y);121 for(;position+length<1;position+=step){122 x+=lengthX;123 y+=lengthY;124 cacheContext.lineTo(x,y);125 x+=gapX;126 y+=gapY;127 cacheContext.moveTo(x,y);128 }129 cacheContext.lineTo(end.x,end.y);130 cacheContext.stroke();131 },132 //数字为参数,返回奇数133 getOdd:function(value,add){134 var result;135 if(add){136 result=value%2==0 ? value-1:value;137 }else{138 result=value%2==0 ? value-1:value;139 }140 return result;141 },142 //美国时间转中国时间143 transferAmericaTime:function(time){144 var hour,minute;145 hour=time.substring(time.length-4,time.length-2);146 minute=time.substring(time.length-2,time.length);147 hour=hour-13;148 hour=hour<0 ? hour+24:hour;149 hour=hour<10 ? "0"+hour:hour;150 return time.substring(0,time.length-4)+hour+minute;151 }152 };153 /*------------------------工具方法end---------------------------*/154 /*------------------------绘图器---------------------------*/155 /*156 * 补充绘图器157 * 包含:MACD指标绘图器158 */159 extraPainterCollection=(function(){160 //配置变量161 var data,layout,width,height,leftX,rightX,topY,bottomY;162 //方法163 var initSize,initValue,drawGrid,insideOf,MACDPainter;164 //为固定配置变量赋值165 layout={a:0.8,b:0.01,c:0.01,d:0.01};166 //设置布局属性,画布长宽会在resize时重新计算167 initValue=function(){168 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);169 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);170 topY=painterTool.getOdd(realCanvas.height*layout.a,false);171 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);172 width=rightX-leftX;173 height=bottomY-topY;174 };175 //绘制补充绘图器的边框网格176 drawGrid=function(){177 var y;178 cacheContext.beginPath();179 cacheContext.strokeStyle="#000";180 cacheContext.lineWidth=1;181 //绘制实线182 cacheContext.moveTo(leftX,topY);183 cacheContext.lineTo(rightX,topY);184 cacheContext.lineTo(rightX,bottomY);185 cacheContext.lineTo(leftX,bottomY);186 cacheContext.closePath();187 cacheContext.stroke();188 //绘制虚线189 y=painterTool.getOdd(topY+height/2);190 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});191 };192 /*193 * 初始化基本配置194 * 数据不在init方法中被传入,否则触控事件就要多次不必要的调用init方法195 */196 initSize=function(){197 initValue();198 };199 //判断x,y是否在绘制区域内200 insideOf=function(x,y){201 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){202 return true;203 }else{204 return false;205 }206 };207 /*208 * MACD绘图器209 * EMA(12) = 前一日EMA(12) X 11/13 + 今日收盘 价 X 2/13210 * EMA(26) = 前一日EMA(26) X 25/27 + 今日收盘价 X 2/27211 * DIF = EMA(12) - EMA(26)212 * DEA = (前一日DEA X 8/10 + 今日DIF X 2/10)213 * (DIF-DEA)*2为MACD柱状图214 */215 MACDPainter=(function(){216 //变量217 var data,start,end,ema12,ema26,dif,dea,macd,218 max,min,range,macdX,middleY,macdColor;219 //方法220 var drawReady,resizeDraw,drawFrame,showCursor,drawCursor,handleData,221 calcData,calcAxis,drawMACD,drawLine,drawText,drawCursorTip;222 macdColor={223 dif:"#f5a623",224 dea:"#2e84e6"225 };226 //计算坐标点227 calcAxis=function(){228 var i;229 middleY=topY+height/2;230 max=min=0;231 for(i=start;i<end;i++){232 if(max<dif[i].data){233 max=dif[i].data;234 }235 if(max<dea[i].data){236 max=dea[i].data;237 }238 if(max<macd[i].data){239 max=macd[i].data;240 }241 if(min>dif[i].data){242 min=dif[i].data;243 }244 if(min>dea[i].data){245 min=dea[i].data;246 }247 if(min>macd[i].data){248 min=macd[i].data;249 }250 }251 max=Math.max(max,Math.abs(min))*maxRate;252 min=-max;253 range=max*2;254 for(i=start;i<end;i++){255 dif[i].axis=topY+height*(max-dif[i].data)/range;256 dea[i].axis=topY+height*(max-dea[i].data)/range;257 macd[i].height=height*macd[i].data/range;258 macd[i].color=macd[i].data<0 ? 0:1;259 }260 };261 //计算MACD各项指标262 calcData=function(){263 ema12=[];264 ema26=[];265 dif=[];266 dea=[];267 macd=[];268 ema12.push(data[0][4]);269 ema26.push(data[0][4]);270 dif.push({data:0});271 dea.push({data:0});272 macd.push({data:0});273 for(var i=1,l=data.length;i<l;i++){274 ema12.push(ema12[i-1]*11/13+data[i][4]*2/13);275 ema26.push(ema26[i-1]*25/27+data[i][4]*2/27);276 dif.push({data:ema12[i]-ema26[i]});277 dea.push({data:dea[i-1].data*8/10+dif[i].data*2/10});278 macd.push({data:(dif[i].data-dea[i].data)*2});279 }280 };281 //处理MACD数据282 handleData=function(){283 if(data.MACD){284 return ;285 }286 data.MACD=true;287 calcData();288 };289 //绘制MACD柱290 drawMACD=function(x,data){291 var y;292 cacheContext.beginPath();293 cacheContext.fillStyle=kColor[data.color];294 cacheContext.moveTo(x,middleY);295 cacheContext.lineTo(x+kWidth,middleY);296 y=middleY-data.height*process;297 cacheContext.lineTo(x+kWidth,y);298 cacheContext.lineTo(x,y);299 cacheContext.closePath();300 cacheContext.fill();301 };302 //绘制DIF,DEA线303 drawLine=function(){304 var x,l,i;305 //DIF306 x=leftX+gapWidth+kWidth/2;307 l=start+Math.floor((end-start)*process);308 cacheContext.beginPath();309 cacheContext.strokeStyle=macdColor.dif;310 cacheContext.lineWidth=1;311 //补足头部图形312 if(start>0){313 cacheContext.moveTo(leftX,(dif[start].axis+topY+height*(max-dif[start-1].data)/range)/2);314 }315 for(i=start;i<l;i++){316 cacheContext.lineTo(x,dif[i].axis);317 x+=gapWidth+kWidth;318 }319 //补足尾部图形320 if(i==end){321 if(end<dif.length-1){322 cacheContext.lineTo(rightX,(dif[i-1].axis+dif[i].axis)/2);323 }324 }325 cacheContext.stroke();326 //DEA327 x=leftX+gapWidth+kWidth/2;328 cacheContext.beginPath();329 cacheContext.strokeStyle=macdColor.dea;330 cacheContext.lineWidth=1;331 //补足头部图形332 if(start>0){333 cacheContext.moveTo(leftX,(dea[start].axis+topY+height*(max-dea[start-1].data)/range)/2);334 }335 for(i=start;i<l;i++){336 cacheContext.lineTo(x,dea[i].axis);337 x+=gapWidth+kWidth;338 }339 //补足尾部图形340 if(i==end){341 if(end<dea.length-1){342 cacheContext.lineTo(rightX,(dea[i-1].axis+dea[i].axis)/2);343 }344 }345 cacheContext.stroke();346 };347 //绘制MACDy轴max,min文字348 drawText=function(){349 cacheContext.fillStyle="#999";350 cacheContext.font=fontSize+"px Arial";351 cacheContext.textAlign="left";352 cacheContext.textBaseline="top";353 cacheContext.fillText(max.toFixed(2),leftX,topY);354 cacheContext.textBaseline="middle";355 cacheContext.fillText("0.00",leftX,middleY);356 cacheContext.textBaseline="bottom";357 cacheContext.fillText(min.toFixed(2),leftX,bottomY);358 };359 //绘制MACD帧360 drawFrame=function(){361 drawGrid();362 macdX=leftX+gapWidth;363 for(var i=start;i<end;i++){364 drawMACD(macdX,macd[i]);365 macdX+=gapWidth+kWidth;366 }367 drawLine();368 drawText();369 };370 //右上角显示MACD指标值371 drawCursorTip=function(){372 var content,gap,x;373 gap=1.02*cacheCursorContext.measureText("MACD:+"+max.toFixed(2)).width;374 x=rightX;375 cacheCursorContext.font=fontSize+"px Arial";376 cacheCursorContext.textBaseline="top";377 cacheCursorContext.textAlign="left";378 //macd379 content="MACD:"+macd[cursorIndex].data.toFixed(2);380 x-=gap;381 cacheCursorContext.fillStyle=kColor[macd[cursorIndex].data<0 ? 0:1];382 cacheCursorContext.fillText(content,x,topY);383 //dea384 content="DEA:"+dea[cursorIndex].data.toFixed(2);385 x-=gap;386 cacheCursorContext.fillStyle=macdColor.dea;387 cacheCursorContext.fillText(content,x,topY);388 //dif389 content="DIF:"+dif[cursorIndex].data.toFixed(2);390 x-=gap;391 cacheCursorContext.fillStyle=macdColor.dif;392 cacheCursorContext.fillText(content,x,topY);393 };394 //绘制MACD图十字光标395 drawCursor=function(x,y){396 cacheCursorContext.beginPath();397 cacheCursorContext.strokeStyle="#000";398 cacheCursorContext.moveTo(cursorX,topY);399 cacheCursorContext.lineTo(cursorX,bottomY);400 cacheCursorContext.stroke();401 drawCursorTip();402 };403 //绘制MACD图十字光标404 showCursor=function(x,y){405 drawCursor(x,y);406 };407 /*408 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化409 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];410 * candleData本身为数组,包含maData指针指向均线数组,axis属性指向坐标数组411 */412 drawReady=function(kData,startPosition,endPosition){413 if(!kData || kData.length==0){414 return ;415 }416 data=kData;417 start=startPosition;418 end=endPosition;419 handleData();420 calcAxis();421 };422 //onresize重绘423 resizeDraw=function(){424 initValue();425 calcAxis();426 drawFrame();427 };428 return {429 initSize:initSize,430 drawReady:drawReady,431 drawFrame:drawFrame,432 resizeDraw:resizeDraw,433 showCursor:showCursor,434 insideOf:insideOf435 }436 })();437 return {438 initSize:initSize,439 MACDPainter:MACDPainter440 };441 })();442 /*443 * K线蜡烛绘图器,子绘图器操作在缓冲画布中,不影响显示444 */445 candlePainter=(function(){446 //配置变量447 var data,layout,width,height,leftX,rightX,topY,bottomY,448 max,min,candleY,candleX,amount,range,middleX,449 middleY,start,end;450 //方法451 var initSize,drawReady,resizeDraw,initValue,drawGrid,handleData,452 drawFrame,drawUpCandle,drawDownCandle,calcAxis,insideOf,drawMA,453 drawMAText,showCursor,drawCursor,drawXTip,drawYTip,showMAText,454 drawRoundRect;455 //为固定配置变量赋值456 layout={a:0.01,b:0.01,c:0.46,d:0.01};457 //设置布局属性,画布长宽会在resize时重新计算458 initValue=function(){459 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);460 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);461 topY=painterTool.getOdd(realCanvas.height*layout.a,false);462 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);463 width=rightX-leftX;464 height=bottomY-topY;465 };466 //计算y坐标值467 calcAxis=function(){468 var i,j,k;469 kWidth=width*(1-gapOccupy)/amount;470 gapWidth=width*gapOccupy/(amount+1);471 for(i=start;i<end;i++){472 //蜡烛坐标计算,[开盘价,最高价,最低价,收盘价,中点]y坐标473 data[i].axis=[];474 for(j=1;j<5;j++){475 data[i].axis.push(topY+height*(max-data[i][j])/range);476 }477 data[i].axis.push((data[i].axis[3]+data[i].axis[0])/2);478 for(k in data.maData){479 data.maData[k][i].maAxis=topY+height*(max-data.maData[k][i][0])/range;480 }481 }482 };483 /*484 * 为可变配置赋值485 * 计算数据展示总数486 * 计算蜡烛宽度、间距宽度487 * 计算y坐标轴的最大值,最小值488 * 计算每个数据的颜色标记:1-涨,0-跌489 */490 handleData=function(){491 var i,j,temp;492 //处理ma头尾补图形引起的作用于变化问题493 max=data[start][2];494 min=data[start][3];495 for(i=start;i<end;i++){496 if(max<data[i][2]){497 max=data[i][2];498 }499 for(j in data.maData){500 if(max<data.maData[j][i][0]){501 max=data.maData[j][i][0];502 }503 }504 if(min>data[i][3]){505 min=data[i][3];506 }507 for(j in data.maData){508 if(min>data.maData[j][i][0]){509 min=data.maData[j][i][0];510 }511 }512 }513 //和头尾的均线值比较514 if(start>0){515 temp=start-1;516 for(j in data.maData){517 if(max<data.maData[j][temp][0]){518 max=data.maData[j][temp][0];519 }520 }521 for(j in data.maData){522 if(min>data.maData[j][temp][0]){523 min=data.maData[j][temp][0];524 }525 }526 }527 if(end<data.length){528 temp=end+1;529 for(j in data.maData){530 if(max<data.maData[j][temp][0]){531 max=data.maData[j][temp][0];532 }533 }534 for(j in data.maData){535 if(min>data.maData[j][temp][0]){536 min=data.maData[j][temp][0];537 }538 }539 }540 max*=maxRate;541 range=max-min;542 calcAxis();543 };544 //绘制蜡烛图ma文字545 drawMAText=function(index){546 var maTips,i,wordWidth,word,gapWidth,wordX,count;547 count=0;548 wordWidth=0;549 maTips={};550 for(i in data.maData){551 word=data.maData[i][index][0]=="-" ? "-":(data.maData[i][index][0].toFixed(2));552 word="MA"+i+":"+word;553 maTips[i]=word;554 wordWidth+=cacheCursorContext.measureText(word).width;555 count++;556 }557 gapWidth=(width-wordWidth)/(count+1);558 cacheCursorContext.font=fontSize+"px Arial";559 cacheCursorContext.textBaseline="top";560 cacheCursorContext.textAlign="left";561 wordX=leftX+gapWidth;562 wordWidth/=count;563 for(i in data.maData){564 cacheCursorContext.fillStyle=maColor[i];565 cacheCursorContext.fillText(maTips[i],wordX,topY);566 wordX+=wordWidth+gapWidth;567 }568 };569 //显示最后一条ma值570 showMAText=function(){571 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);572 drawMAText(end-1);573 refreshCursorCache();574 };575 576 //绘制坐标轴网格577 drawGrid=function(){578 var stepY;579 cacheContext.beginPath();580 cacheContext.strokeStyle="#000";581 cacheContext.lineWidth=1;582 //绘制实线583 cacheContext.moveTo(leftX,topY);584 cacheContext.lineTo(rightX,topY);585 cacheContext.lineTo(rightX,bottomY);586 cacheContext.lineTo(leftX,bottomY);587 cacheContext.closePath();588 cacheContext.stroke();589 //绘制虚线590 stepY=height/4;591 for(var i=1;i<4;i++){592 painterTool.drawDashed({x:painterTool.getOdd(leftX),y:painterTool.getOdd(topY+i*stepY)},{x:painterTool.getOdd(rightX),y:painterTool.getOdd(topY+i*stepY)});593 }594 //绘制y轴数字595 cacheContext.fillStyle="#999";596 cacheContext.font=fontSize+"px Arial";597 cacheContext.textAlign="left";598 cacheContext.textBaseline="top";599 cacheContext.fillText(max.toFixed(2),leftX,topY);600 cacheContext.textBaseline="middle";601 cacheContext.fillText(((max+min)/2).toFixed(2),leftX,topY+height/2);602 cacheContext.textBaseline="bottom";603 cacheContext.fillText(min.toFixed(2),leftX,bottomY);604 //绘制x轴日期605 cacheContext.textBaseline="top";606 cacheContext.fillText(data[start][0],leftX,bottomY);607 cacheContext.textAlign="right";608 cacheContext.fillText(data[end-1][0],rightX,bottomY);609 showMAText();610 };611 /*612 * 红色K线,从下往上画613 * 传入蜡烛左侧x坐标和K线数据[日期,开盘价,最高价,最低价,收盘价,成交量]为参数614 */615 drawUpCandle=function(x,value){616 middleX=painterTool.getOdd(x+kWidth/2);617 middleY=value.axis[4];618 cacheContext.beginPath();619 cacheContext.fillStyle=kColor[value.color];620 cacheContext.strokeStyle=kColor[value.color];621 cacheContext.lineWidth=2;622 candleY=middleY+(value.axis[0]-middleY)*process;623 cacheContext.moveTo(x,candleY);624 cacheContext.lineTo(middleX,candleY);625 cacheContext.moveTo(middleX,middleY+(value.axis[2]-middleY)*process);626 cacheContext.lineTo(middleX,candleY);627 cacheContext.lineTo(x+kWidth,candleY);628 candleY=middleY+(value.axis[3]-middleY)*process;629 cacheContext.lineTo(x+kWidth,candleY);630 cacheContext.lineTo(middleX,candleY);631 cacheContext.moveTo(middleX,middleY+(value.axis[1]-middleY)*process);632 cacheContext.lineTo(middleX,candleY);633 cacheContext.lineTo(x,candleY);634 cacheContext.lineTo(x,middleY+(value.axis[0]-middleY)*process);635 cacheContext.stroke();636 };637 /*638 * 绿色K线,从上往下画639 * 传入蜡烛左侧x坐标和K线数据[日期,开盘价,最高价,最低价,收盘价,成交量]为参数640 */641 drawDownCandle=function(x,value){642 middleX=painterTool.getOdd(x+kWidth/2);643 middleY=value.axis[4];644 cacheContext.beginPath();645 cacheContext.fillStyle=kColor[value.color];646 cacheContext.strokeStyle=kColor[value.color];647 cacheContext.lineWidth=2;648 candleY=middleY+(value.axis[0]-middleY)*process;649 cacheContext.moveTo(x,candleY);650 cacheContext.lineTo(x+kWidth,candleY);651 candleY=middleY+(value.axis[3]-middleY)*process;652 cacheContext.lineTo(x+kWidth,candleY);653 cacheContext.lineTo(x,candleY);654 cacheContext.closePath();655 cacheContext.fill();656 cacheContext.stroke();657 cacheContext.beginPath();658 cacheContext.moveTo(middleX,middleY+(value.axis[1]-middleY)*process);659 cacheContext.lineTo(middleX,middleY+(value.axis[2]-middleY)*process);660 cacheContext.stroke();661 };662 /*663 * 绘制ma均线664 * 传入索引,表示绘制哪一个均线665 */666 drawMA=function(index){667 var value,x,l;668 value=data.maData[index];669 x=leftX+gapWidth+kWidth/2;670 l=start+Math.floor((end-start)*process);671 cacheContext.beginPath();672 cacheContext.strokeStyle=maColor[index];673 cacheContext.lineWidth=1;674 //为ma补足头部图形675 if(start>0){676 cacheContext.moveTo(leftX,(value[start].maAxis+topY+height*(max-value[start-1][0])/range)/2);677 }678 for(var i=start;i<l;i++){679 cacheContext.lineTo(x,value[i].maAxis);680 x+=gapWidth+kWidth;681 }682 //为ma补足尾部图形683 if(i==end){684 if(value[i]!="-"){685 cacheContext.lineTo(rightX,(value[i-1].maAxis+value[i].maAxis)/2);686 }687 }688 cacheContext.stroke();689 };690 691 //根据process进度情况,绘制K线蜡烛图图形帧692 drawFrame=function(){693 var width=gapWidth+kWidth;694 drawGrid();695 candleX=leftX+gapWidth;696 for(var i=start;i<end;i++){697 if(data[i].color==1){698 drawUpCandle(candleX,data[i]);699 }else{700 drawDownCandle(candleX,data[i]);701 }702 candleX+=width;703 }704 for(i in data.maData){705 drawMA(i);706 }707 };708 //绘制圆角矩形709 drawRoundRect=function(x,y,w,h){710 var r,change;711 r=h/4;712 change=2;713 x-=change;714 y-=change;715 w+=change*2;716 h+=change*2;717 if(x<leftX){718 x=leftX;719 }else if((x+w)>rightX){720 x=rightX-w;721 }722 if(y<topY){723 y=topY;724 }else if(y+h>bottomY){725 y=bottomY-h;726 }727 cacheCursorContext.beginPath();728 cacheCursorContext.strokeStyle="#999";729 cacheCursorContext.fillStyle="#ddd";730 cacheCursorContext.moveTo(x+r,y);731 cacheCursorContext.arcTo(x+w,y,x+w,y+h,r);732 cacheCursorContext.arcTo(x+w,y+h,x,y+h,r);733 cacheCursorContext.arcTo(x,y+h,x,y,r);734 cacheCursorContext.arcTo(x,y,x+r,y,r);735 cacheCursorContext.stroke();736 cacheCursorContext.fill();737 };738 //绘制日Kx轴tip739 drawXTip=function(x,data){740 var content,contentLength;741 //线742 cacheCursorContext.beginPath();743 cacheCursorContext.strokeStyle="#000";744 cacheCursorContext.moveTo(x,topY);745 cacheCursorContext.lineTo(x,bottomY);746 cacheCursorContext.stroke();747 //背景748 content=data[0];749 contentLength=cacheCursorContext.measureText(content).width/2;750 drawRoundRect(x-contentLength,bottomY-fontSize,contentLength*2,fontSize);751 //文字752 cacheCursorContext.fillStyle="#999";753 cacheCursorContext.font=fontSize+"px Arial";754 cacheCursorContext.textBaseline="bottom";755 if(x+contentLength>rightX){756 cacheCursorContext.textAlign="right";757 cacheCursorContext.fillText(content,rightX,bottomY);758 }else if(x-contentLength<leftX){759 cacheCursorContext.textAlign="left";760 cacheCursorContext.fillText(content,leftX,bottomY);761 }else{762 cacheCursorContext.textAlign="center";763 cacheCursorContext.fillText(content,x,bottomY);764 }765 };766 //绘制日Ky轴tip767 drawYTip=function(y,data){768 var content,contentLength;769 if(y>bottomY){770 y=bottomY;771 }772 //线773 cacheCursorContext.beginPath();774 cacheCursorContext.strokeStyle="#000";775 cacheCursorContext.moveTo(leftX,y);776 cacheCursorContext.lineTo(rightX,y);777 cacheCursorContext.stroke();778 //背景779 content=(max-range*(y-topY)/height).toFixed(2);780 contentLength=cacheCursorContext.measureText(content).width;781 drawRoundRect(leftX,y-fontSize/2,contentLength,fontSize);782 //文字783 cacheCursorContext.fillStyle="#999";784 cacheCursorContext.font=fontSize+"px Arial";785 cacheCursorContext.textAlign="left";786 if(y+fontSize/2>bottomY){787 cacheCursorContext.textBaseline="bottom";788 y=bottomY;789 }else if(y-fontSize/2<topY){790 cacheCursorContext.textBaseline="top";791 y=topY;792 }else{793 cacheCursorContext.textBaseline="middle";794 }795 cacheCursorContext.fillText(content,leftX,y);796 };797 //显示蜡烛图十字光标798 drawCursor=function(x,y){799 var width=gapWidth+kWidth;800 /*-------------公式计算找坐标---------------*/801 //计算触控事件所在的K线数据索引802 cursorIndex=Math.ceil((x-leftX-gapWidth/2-width)/width)+1;803 //光标头部越界804 cursorIndex=cursorIndex<1 ? 1:cursorIndex;805 //光标尾部越界806 cursorIndex=cursorIndex<end-start ? cursorIndex:end-start;807 //计算柱中心坐标808 cursorX=painterTool.getOdd(leftX+gapWidth/2+cursorIndex*width-width/2);809 /*-------------遍历找坐标---------------*/810 /*cursorX=leftX+width+gapWidth/2;811 cursorIndex=1;812 while(cursorX<x){813 cursorIndex++;814 cursorX+=width;815 }816 cursorX=painterTool.getOdd(cursorX-width/2);*/817 //尾部取数据数组越界818 cursorIndex+=start-1;819 drawXTip(cursorX,data[cursorIndex]);820 drawYTip(painterTool.getOdd(y),data[cursorIndex]);821 drawMAText(cursorIndex);822 };823 /*824 * 初始化基本配置825 * 数据不在init方法中被传入,否则触控事件就要多次不必要的调用init方法826 */827 initSize=function(){828 initValue();829 };830 831 /*832 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化833 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];834 * candleData本身为数组,包含maData指针指向均线数组,axis属性指向坐标数组835 */836 drawReady=function(candleData,startPosition,endPosition,candleAmount){837 if(!candleData || candleData.length==0){838 return ;839 }840 data=candleData;841 start=startPosition;842 end=endPosition;843 amount=candleAmount;844 handleData();845 };846 //onresize重绘847 resizeDraw=function(){848 initValue();849 calcAxis();850 drawFrame();851 };852 //判断x,y是否在绘制区域内853 insideOf=function(x,y){854 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){855 return true;856 }else{857 return false;858 }859 };860 //绘制蜡烛图十字光标861 showCursor=function(x,y){862 drawCursor(x,y);863 };864 865 return {866 initSize:initSize,867 drawReady:drawReady,868 drawFrame:drawFrame,869 resizeDraw:resizeDraw,870 showCursor:showCursor,871 insideOf:insideOf,872 showMAText:showMAText873 };874 })();875 876 /*877 * K线交易量柱状图绘图器,子绘图器操作在缓冲画布中,不影响显示878 */879 kBarPainter=(function(){880 //数据881 var data,initValue,max,width,height,leftX,rightX,topY,882 bottomY,barX,layout,start,end;883 //方法884 var initSize,drawReady,resizeDraw,drawFrame,handleData,drawGrid,885 drawBar,calcAxis,insideOf,drawMA,showCursor,drawCursor,886 drawCursorTip;887 //固定配置888 layout={a:0.58,b:0.01,c:0.23,d:0.01};889 initValue=function(){890 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);891 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);892 topY=painterTool.getOdd(realCanvas.height*layout.a,false);893 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);894 width=rightX-leftX;895 height=bottomY-topY;896 };897 //计算交易量柱的高度898 calcAxis=function(){899 var i,k;900 for(i=start;i<end;i++){901 data[i].baHeight=data[i][5]/max*height;902 for(k in data.maData){903 data.maData[k][i].maBaAxis=bottomY-height*data.maData[k][i][1]/max;904 }905 }906 };907 //计算成交量的最大值908 handleData=function(){909 var i,j,temp;910 max=data[start][5];911 for(i=start;i<end;i++){912 if(max<data[i][5]){913 max=data[i][5];914 }915 for(j in data.maData){916 if(max<data.maData[j][i][1]){917 max=data.maData[j][i][1];918 }919 }920 }921 //比较均线值头尾数据922 if(start>0){923 temp=start-1;924 for(j in data.maData){925 if(max<data.maData[j][temp][1]){926 max=data.maData[j][temp][1];927 }928 }929 }930 if(end<data.length){931 temp=end+1;932 for(j in data.maData){933 if(max<data.maData[j][temp][1]){934 max=data.maData[j][temp][1];935 }936 }937 }938 max*=maxRate;939 calcAxis();940 };941 //绘制边框虚线942 drawGrid=function(){943 var y;944 cacheContext.beginPath();945 cacheContext.strokeStyle="#000";946 cacheContext.lineWidth=1;947 //绘制实线948 cacheContext.moveTo(leftX,topY);949 cacheContext.lineTo(rightX,topY);950 cacheContext.lineTo(rightX,bottomY);951 cacheContext.lineTo(leftX,bottomY);952 cacheContext.closePath();953 cacheContext.stroke();954 //绘制虚线955 y=painterTool.getOdd(topY+height/2);956 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});957 //绘制y轴文字958 cacheContext.fillStyle="#999";959 cacheContext.font=fontSize+"px Arial";960 cacheContext.textAlign="left";961 cacheContext.textBaseline="top";962 cacheContext.fillText("成交量:"+max,leftX,topY);963 };964 //绘制成交量柱965 drawBar=function(x,data){966 var y;967 cacheContext.beginPath();968 cacheContext.fillStyle=kColor[data.color];969 cacheContext.moveTo(x,bottomY);970 cacheContext.lineTo(x+kWidth,bottomY);971 y=bottomY-data.baHeight*process;972 cacheContext.lineTo(x+kWidth,y);973 cacheContext.lineTo(x,y);974 cacheContext.closePath();975 cacheContext.fill();976 };977 //绘制成交量ma均线978 drawMA=function(index){979 var value,x,l;980 value=data.maData[index];981 x=leftX+gapWidth+kWidth/2;982 l=start+Math.floor((end-start)*process);983 cacheContext.beginPath();984 cacheContext.strokeStyle=maColor[index];985 cacheContext.lineWidth=1;986 //为ma补足头部图形987 if(start>0){988 cacheContext.moveTo(leftX,(value[start].maBaAxis+bottomY-height*value[start-1][1]/max)/2);989 }990 for(var i=start;i<l;i++){991 cacheContext.lineTo(x,value[i].maBaAxis);992 x+=gapWidth+kWidth;993 }994 //为ma补足尾部图形995 if(i==end){996 if(value[i]!="-"){997 cacheContext.lineTo(rightX,(value[i-1].maBaAxis+value[i].maBaAxis)/2);998 }999 }1000 cacheContext.stroke();1001 };1002 //根据process进度情况,绘制交易量图形帧1003 drawFrame=function(){1004 drawGrid();1005 barX=leftX+gapWidth;1006 for(var i=start;i<end;i++){1007 drawBar(barX,data[i]);1008 barX+=gapWidth+kWidth;1009 }1010 for(i in data.maData){1011 drawMA(i);1012 }1013 };1014 //右上角显示交易量指标值1015 drawCursorTip=function(){1016 var content,gap,x;1017 gap=1.02*cacheCursorContext.measureText("成交量:"+max).width;1018 x=rightX;1019 cacheCursorContext.font=fontSize+"px Arial";1020 cacheCursorContext.textBaseline="top";1021 cacheCursorContext.textAlign="left";1022 //成交量1023 content="成交量:"+data[cursorIndex][5];1024 x-=gap;1025 cacheCursorContext.fillStyle=kColor[data[cursorIndex].color];1026 cacheCursorContext.fillText(content,x,topY);1027 //ma1028 x-=gap*4;1029 for(var i in data.maData){1030 content=parseInt(data.maData[i][cursorIndex][1]);1031 content=isNaN(content) ? "-":content;1032 content="MA"+i+":"+content;1033 x+=gap;1034 cacheCursorContext.fillStyle=maColor[i];1035 cacheCursorContext.fillText(content,x,topY);1036 }1037 };1038 //显示日K交易量图十字光标1039 drawCursor=function(x,y){1040 cacheCursorContext.beginPath();1041 cacheCursorContext.strokeStyle="#000";1042 cacheCursorContext.moveTo(cursorX,topY);1043 cacheCursorContext.lineTo(cursorX,bottomY);1044 cacheCursorContext.stroke();1045 drawCursorTip();1046 };1047 /*1048 * 初始化基本配置1049 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1050 */1051 initSize=function(){1052 initValue();1053 };1054 /*1055 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1056 * 接收二维数组为参数,每一项包含[日期,开盘价,最高价,最低价,收盘价,成交量];1057 */1058 drawReady=function(barData,startPosition,endPosition){1059 if(!barData || barData.length==0){1060 return ;1061 }1062 data=barData;1063 start=startPosition;1064 end=endPosition;1065 handleData();1066 };1067 //onresize重绘1068 resizeDraw=function(){1069 initValue();1070 calcAxis();1071 drawFrame();1072 };1073 //判断x,y是否在绘制区域内1074 insideOf=function(x,y){1075 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1076 return true;1077 }else{1078 return false;1079 }1080 };1081 //绘制日K线交易量图十字光标1082 showCursor=function(x,y){1083 drawCursor(x,y);1084 };1085 return {1086 initSize:initSize,1087 drawReady:drawReady,1088 drawFrame:drawFrame,1089 resizeDraw:resizeDraw,1090 showCursor:showCursor,1091 insideOf:insideOf1092 };1093 })();1094 /*1095 * 分时图绘图器1096 */1097 trendPainter=(function(){1098 //变量1099 var data,layout,width,height,leftX,rightX,topY,bottomY,1100 middle,max,min,range,amount,range,start,end,1101 marketDetail,trendX,valueMax;1102 //方法1103 var initSize,drawReady,resizeDraw,initValue,draw1Grid,handleData,1104 draw1Frame,calcAxis,insideOf,draw1Trend,draw1Text,draw5Frame,1105 draw5Grid,draw5Trend,draw5Text,drawFrame,showCursor,drawCursor,1106 drawXTip,drawYTip,drawRoundRect,drawBall,flash,cursorShowed,1107 cursorPositionX,cursorPositionY,turnOffCursor;1108 //为固定配置变量赋值1109 layout={a:0.03,b:0.01,c:0.3,d:0.01};1110 //设置布局属性,画布长宽会在resize时重新计算1111 initValue=function(){1112 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);1113 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);1114 topY=painterTool.getOdd(realCanvas.height*layout.a,false);1115 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);1116 width=rightX-leftX;1117 height=bottomY-topY;1118 };1119 //计算分时图坐标点1120 calcAxis=function(){1121 var i,j,k;1122 //分时图的成交量图头尾都为半根1123 kWidth=width*(1-gapOccupy)/amount;1124 gapWidth=width*gapOccupy/amount;1125 for(i=start;i<end;i++){1126 data[i].axis=topY+height*(max-data[i][1])/range;1127 data[i].avgAxis=topY+height*(max-data[i][2])/range;1128 }1129 };1130 //处理数据,计算最大值最小值1131 handleData=function(){1132 var i,l;1133 amount=marketDetail.amount;1134 middle=data.preclosePx;1135 max=min=middle;1136 for(i=0,l=data.length;i<l;i++){1137 //for(i=start;i<end;i++){1138 if(max<data[i][1]){1139 max=data[i][1];1140 }1141 if(min>data[i][1]){1142 min=data[i][1];1143 }1144 }1145 //记录数据最大值(不一定是y轴最大值),后面设置渐变用1146 valueMax=max;1147 max=Math.max(max-middle,Math.abs(min-middle))*maxRate;1148 max=middle+max;1149 min=middle-(max-middle);1150 range=max-min;1151 calcAxis();1152 };1153 //头部球闪烁,会被十字光标影响1154 flash=function(x,y){1155 cacheCursorContext.beginPath();1156 cacheCursorContext.fillStyle="rgba(255,255,240,0.30)";1157 cacheCursorContext.arc(x,y,kWidth*3,0,2*Math.PI,false);1158 cacheCursorContext.fill();1159 cacheCursorContext.beginPath();1160 cacheCursorContext.fillStyle="rgba(76,143,254,0.5)";1161 cacheCursorContext.arc(x,y,kWidth*1.6,0,2*Math.PI,false);1162 cacheCursorContext.fill();1163 refreshCursorCache();1164 setTimeout(function(){1165 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);1166 if(cursorShowed){1167 drawCursor(cursorPositionX,cursorPositionY);1168 }1169 refreshCursorCache();1170 },200);1171 };1172 //绘制头部球1173 drawBall=function(x,y){1174 cacheContext.beginPath();1175 cacheContext.fillStyle="rgba(59,126,237,0.30)";1176 cacheContext.arc(x,y,kWidth*2.6,0,2*Math.PI,false);1177 cacheContext.fill();1178 cacheContext.beginPath();1179 cacheContext.fillStyle="#3b7fed";1180 cacheContext.arc(x,y,kWidth*1.4,0,2*Math.PI,false);1181 cacheContext.fill();1182 if(data.append){1183 flash(x,y);1184 }1185 };1186 //绘制分时图边框1187 draw1Grid=function(){1188 var stepY,avg,i,l,x,position,date,gridTop,gridBottom;1189 cacheContext.beginPath();1190 cacheContext.strokeStyle="#000";1191 cacheContext.lineWidth=1;1192 //绘制实线1193 gridTop=topY-gridExpand;1194 gridBottom=bottomY+gridExpand;1195 cacheContext.moveTo(leftX,gridTop);1196 cacheContext.lineTo(rightX,gridTop);1197 cacheContext.lineTo(rightX,gridBottom);1198 cacheContext.lineTo(leftX,gridBottom);1199 cacheContext.closePath();1200 cacheContext.stroke();1201 //绘制虚线1202 stepY=height/4;1203 for(i=1;i<4;i++){1204 painterTool.drawDashed(1205 {x:painterTool.getOdd(leftX),y:painterTool.getOdd(gridTop+i*stepY)},1206 {x:painterTool.getOdd(rightX),y:painterTool.getOdd(gridTop+i*stepY)}1207 );1208 }1209 //绘制分时时间1210 avg=marketDetail.singleDay/marketDetail.length;1211 cacheContext.font=fontSize+"px Arial";1212 cacheContext.textAlign="center";1213 cacheContext.textBaseline="top";1214 cacheContext.fillStyle="#999";1215 for(i=1,l=marketDetail.length;i<l;i++){1216 position=i*avg;1217 if(position>=start && position<start+amount){1218 x=leftX+(position-start)*(gapWidth+kWidth);1219 painterTool.drawDashed(1220 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridTop)},1221 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridBottom)}1222 );1223 cacheContext.fillText(marketDetail[i-1].close_time+"/"+marketDetail[i].open_time,x,gridTop);1224 }1225 }1226 //绘制头尾x轴时间1227 cacheContext.textAlign="left";1228 if(data[start]){1229 if(data.marketDetail.inAmerica){1230 date=painterTool.transferAmericaTime(data[start][0]+"");1231 }else{1232 date=data[start][0]+"";1233 }1234 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1235 }else{1236 date="--";1237 }1238 cacheContext.fillText(date,leftX,gridBottom);1239 cacheContext.textAlign="right";1240 if(end>=data.length){1241 //marketDetail的时间已经转换过了1242 date=data.marketDetail[data.marketDetail.length-1].close_time+"";1243 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1244 }else{1245 if(data.marketDetail.inAmerica){1246 date=painterTool.transferAmericaTime(data[end-1][0]+"");1247 }else{1248 date=data[end-1][0]+"";1249 }1250 date=date.substring(date.length-4,date.length-2)+":"+date.substring(date.length-2,date.length);1251 }1252 cacheContext.fillText(date,rightX,gridBottom);1253 };1254 //绘制坐标轴文字1255 draw1Text=function(){1256 var middleY;1257 middleY=topY+height/2;1258 //绘制y轴数字1259 cacheContext.font=fontSize+"px Arial";1260 cacheContext.textAlign="left";1261 cacheContext.textBaseline="top";1262 cacheContext.fillStyle=kColor[1];1263 cacheContext.fillText(max.toFixed(2),leftX,topY);1264 cacheContext.textAlign="right";1265 cacheContext.fillText((100*(max-middle)/middle).toFixed(2)+"%",rightX,topY);1266 cacheContext.textAlign="left";1267 cacheContext.textBaseline="bottom";1268 cacheContext.fillStyle=kColor[0];1269 cacheContext.fillText(min.toFixed(2),leftX,bottomY);1270 cacheContext.textAlign="right";1271 cacheContext.fillText((100*(middle-min)/middle).toFixed(2)+"%",rightX,bottomY);1272 cacheContext.textAlign="left";1273 cacheContext.textBaseline="middle";1274 cacheContext.fillStyle="#999";1275 cacheContext.fillText(middle.toFixed(2),leftX,middleY);1276 cacheContext.textAlign="right";1277 cacheContext.fillText("0.00%",rightX,middleY);1278 };1279 //绘制分时图折线图&渐变阴影图1280 draw1Trend=function(){1281 var i,l,gradient,ballY;1282 //避免出现卡顿动画1283 if(end-start<40){1284 process=1;1285 }1286 trendX=leftX;1287 l=start+Math.floor((end-start)*process);1288 //---绘制折线图1289 cacheContext.beginPath();1290 cacheContext.strokeStyle="#3b7fed";1291 cacheContext.moveTo(trendX,data[start].axis);1292 for(i=start+1;i<l-1;i++){1293 trendX+=gapWidth+kWidth;1294 cacheContext.lineTo(trendX,data[i].axis);1295 }1296 //为避免最后一个数据超出grid,单独处理1297 trendX+=gapWidth+kWidth;1298 if(trendX>rightX){1299 trendX=rightX;1300 }1301 if(i<data.length){1302 cacheContext.lineTo(trendX,data[i].axis);1303 cacheContext.stroke();1304 }1305 //---绘制渐变阴影1306 cacheContext.beginPath();1307 try{1308 gradient=cacheContext.createLinearGradient(leftX,topY+height*(max-valueMax)/range,leftX,bottomY);1309 gradient.addColorStop(0.45,"#c2deff");1310 gradient.addColorStop(1,"rgba(255,255,255,0)");1311 }catch(e){1312 console.info("openapiError:",e);1313 }1314 cacheContext.fillStyle=gradient;1315 cacheContext.moveTo(leftX,bottomY);1316 trendX=leftX;1317 for(i=start;i<l-1;i++){1318 cacheContext.lineTo(trendX,data[i].axis);1319 trendX+=gapWidth+kWidth;1320 }1321 //为避免最后一个数据超出grid,单独处理1322 if(trendX>rightX){1323 trendX=rightX;1324 }1325 if(i<data.length){1326 cacheContext.lineTo(trendX,data[i].axis);1327 }1328 cacheContext.lineTo(trendX,bottomY);1329 cacheContext.closePath();1330 cacheContext.fill();1331 //---绘制分时图均价线1332 trendX=leftX;1333 cacheContext.beginPath();1334 cacheContext.strokeStyle="#ffc436";1335 cacheContext.moveTo(trendX,data[start].avgAxis);1336 for(i=start+1;i<l-1;i++){1337 trendX+=gapWidth+kWidth;1338 cacheContext.lineTo(trendX,data[i].avgAxis);1339 }1340 //为避免最后一个数据超出grid,单独处理1341 trendX+=gapWidth+kWidth;1342 if(trendX>rightX){1343 trendX=rightX;1344 }1345 if(i<data.length){1346 cacheContext.lineTo(trendX,data[i].avgAxis);1347 }1348 cacheContext.stroke();1349 //绘制头部球1350 if(process==1 && i==data.length-1){1351 ballY=data[i].axis;1352 drawBall(trendX,ballY);1353 }1354 };1355 //绘制五日分时网格1356 draw5Grid=function(){1357 var stepY,i,x,amount,l,date,position,gridTop,1358 gridBottom,wordLength;1359 cacheContext.beginPath();1360 cacheContext.strokeStyle="#000";1361 cacheContext.lineWidth=1;1362 //绘制实线1363 gridTop=topY-gridExpand;1364 gridBottom=bottomY+gridExpand;1365 cacheContext.moveTo(leftX,gridTop);1366 cacheContext.lineTo(rightX,gridTop);1367 cacheContext.lineTo(rightX,gridBottom);1368 cacheContext.lineTo(leftX,gridBottom);1369 cacheContext.closePath();1370 cacheContext.stroke();1371 //绘制虚线1372 amount=4;1373 stepY=height/amount;1374 for(i=1;i<amount;i++){1375 painterTool.drawDashed(1376 {x:painterTool.getOdd(leftX),y:painterTool.getOdd(gridTop+i*stepY)},1377 {x:painterTool.getOdd(rightX),y:painterTool.getOdd(gridTop+i*stepY)}1378 );1379 }1380 //绘制分时时间1381 amount=5;1382 l=data.marketDetail.singleDay;1383 cacheContext.font=fontSize+"px Arial";1384 cacheContext.textAlign="left";1385 cacheContext.textBaseline="top";1386 cacheContext.fillStyle="#999";1387 if(start==0){1388 date=data[0][0]+"";1389 date=date.substring(4,6)+"-"+date.substring(6,8);1390 cacheContext.fillText(date,leftX,gridBottom);1391 }1392 for(i=1;i<amount;i++){1393 position=i*l;1394 if(position>=start && position<end){1395 x=leftX+(position-start)*(gapWidth+kWidth);1396 date=data[position][0]+"";1397 date=date.substring(4,6)+"-"+date.substring(6,8);1398 wordLength=cacheContext.measureText(date).width;1399 if(x+wordLength>rightX){1400 cacheContext.textAlign="right";1401 x=rightX;1402 }1403 cacheContext.fillText(date,x,gridBottom);1404 painterTool.drawDashed(1405 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridTop)},1406 {x:painterTool.getOdd(x),y:painterTool.getOdd(gridBottom)}1407 );1408 }1409 }1410 };1411 //绘制五日分时图折线图&渐变阴影图&均价1412 draw5Trend=function(){1413 var i,l,gradient,amount;1414 //避免出现卡顿动画1415 if(end-start<40){1416 process=1;1417 }1418 trendX=leftX;1419 l=start+Math.floor((end-start)*process);1420 amount=marketDetail.singleDay;1421 //---绘制折线图1422 cacheContext.beginPath();1423 cacheContext.strokeStyle="#3b7fed";1424 cacheContext.moveTo(trendX,data[start].axis);1425 for(i=start+1;i<l-1;i++){1426 trendX+=gapWidth+kWidth;1427 if(i%amount==0){1428 cacheContext.stroke();1429 cacheContext.beginPath();1430 cacheContext.moveTo(trendX,data[i].axis);1431 continue;1432 }1433 cacheContext.lineTo(trendX,data[i].axis);1434 }1435 //为避免最后一个数据超出grid,单独处理1436 trendX+=gapWidth+kWidth;1437 if(trendX>rightX){1438 trendX=rightX;1439 }1440 cacheContext.lineTo(trendX,data[i].axis);1441 cacheContext.stroke();1442 //---绘制渐变阴影1443 cacheContext.beginPath();1444 gradient=cacheContext.createLinearGradient(leftX,topY+height*(max-valueMax)/range,leftX,bottomY);1445 gradient.addColorStop(0.45,"#c2deff");1446 gradient.addColorStop(1,"rgba(255,255,255,0)");1447 cacheContext.fillStyle=gradient;1448 cacheContext.moveTo(leftX,bottomY);1449 trendX=leftX;1450 for(i=start;i<l-1;i++){1451 cacheContext.lineTo(trendX,data[i].axis);1452 trendX+=gapWidth+kWidth;1453 }1454 //为避免最后一个数据超出grid,单独处理1455 if(trendX>rightX){1456 trendX=rightX;1457 }1458 cacheContext.lineTo(trendX,data[i].axis);1459 cacheContext.lineTo(trendX,bottomY);1460 cacheContext.closePath();1461 cacheContext.fill();1462 //---绘制分时图均价线1463 trendX=leftX;1464 cacheContext.beginPath();1465 cacheContext.strokeStyle="#ffc436";1466 cacheContext.moveTo(trendX,data[start].avgAxis);1467 for(i=start+1;i<l-1;i++){1468 trendX+=gapWidth+kWidth;1469 if(i%amount==0){1470 cacheContext.stroke();1471 cacheContext.beginPath();1472 cacheContext.moveTo(trendX,data[i].axis);1473 continue;1474 }1475 cacheContext.lineTo(trendX,data[i].avgAxis);1476 }1477 //为避免最后一个数据超出grid,单独处理1478 trendX+=gapWidth+kWidth;1479 if(trendX>rightX){1480 trendX=rightX;1481 }1482 if(i%amount!=0) {1483 cacheContext.lineTo(trendX, data[i].avgAxis);1484 }1485 cacheContext.stroke();1486 };1487 //绘制五日分时图y轴坐标1488 draw5Text=function(){1489 var middleY;1490 middleY=topY+height/2;1491 //绘制y轴数字1492 cacheContext.font=fontSize+"px Arial";1493 cacheContext.textAlign="left";1494 cacheContext.textBaseline="top";1495 cacheContext.fillStyle=kColor[1];1496 cacheContext.fillText(max.toFixed(2),leftX,topY);1497 cacheContext.textAlign="right";1498 cacheContext.fillText((100*(max-middle)/middle).toFixed(2)+"%",rightX,topY);1499 cacheContext.textAlign="left";1500 cacheContext.textBaseline="bottom";1501 cacheContext.fillStyle=kColor[0];1502 cacheContext.fillText(min.toFixed(2),leftX,bottomY);1503 cacheContext.textAlign="right";1504 cacheContext.fillText((100*(middle-min)/middle).toFixed(2)+"%",rightX,bottomY);1505 cacheContext.textAlign="left";1506 cacheContext.textBaseline="middle";1507 cacheContext.fillStyle="#999";1508 cacheContext.fillText(middle.toFixed(2),leftX,middleY);1509 cacheContext.textAlign="right";1510 cacheContext.fillText("0.00%",rightX,middleY);1511 };1512 //绘制一日分时图帧1513 draw1Frame=function(){1514 draw1Grid();1515 if(start<data.length){1516 draw1Trend();1517 }1518 draw1Text();1519 };1520 //绘制五日分时图帧1521 draw5Frame=function(){1522 draw5Grid();1523 draw5Trend();1524 draw5Text();1525 };1526 //模块模式为一个闭包,输出函数不能动态变化1527 drawFrame=function(){1528 if(marketDetail.dayAmount==1){1529 draw1Frame();1530 }else if(marketDetail.dayAmount==5){1531 draw5Frame();1532 }1533 };1534 //绘制分时图圆角矩形1535 drawRoundRect=function(x,y,w,h){1536 var r,change;1537 r=h/4;1538 change=2;1539 x-=change;1540 y-=change;1541 w+=change*2;1542 h+=change*2;1543 if(x<leftX){1544 x=leftX;1545 }else if((x+w)>rightX){1546 x=rightX-w;1547 }1548 if(y<topY){1549 y=topY;1550 }else if(y+h>bottomY){1551 y=bottomY-h;1552 }1553 cacheCursorContext.beginPath();1554 cacheCursorContext.strokeStyle="#999";1555 cacheCursorContext.fillStyle="#ddd";1556 cacheCursorContext.moveTo(x+r,y);1557 cacheCursorContext.arcTo(x+w,y,x+w,y+h,r);1558 cacheCursorContext.arcTo(x+w,y+h,x,y+h,r);1559 cacheCursorContext.arcTo(x,y+h,x,y,r);1560 cacheCursorContext.arcTo(x,y,x+r,y,r);1561 cacheCursorContext.stroke();1562 cacheCursorContext.fill();1563 };1564 //绘制x轴tip1565 drawXTip=function(x,data){1566 var content,contentLength;1567 //线1568 cacheCursorContext.beginPath();1569 cacheCursorContext.strokeStyle="#000";1570 cacheCursorContext.moveTo(x,topY);1571 cacheCursorContext.lineTo(x,bottomY);1572 cacheCursorContext.stroke();1573 //背景,先设置字体,否则宽度计算错误1574 cacheCursorContext.font=fontSize+"px Arial";1575 content=data[0];1576 contentLength=cacheCursorContext.measureText(content).width/2;1577 drawRoundRect(x-contentLength,bottomY-fontSize,contentLength*2,fontSize);1578 //文字1579 cacheCursorContext.fillStyle="#999";1580 cacheCursorContext.textBaseline="bottom";1581 contentLength=cacheCursorContext.measureText(content).width/2;1582 if(x+contentLength>rightX){1583 cacheCursorContext.textAlign="right";1584 cacheCursorContext.fillText(content,rightX,bottomY);1585 }else if(x-contentLength<leftX){1586 cacheCursorContext.textAlign="left";1587 cacheCursorContext.fillText(content,leftX,bottomY);1588 }else{1589 cacheCursorContext.textAlign="center";1590 cacheCursorContext.fillText(content,x,bottomY);1591 }1592 };1593 //绘制y轴tip1594 drawYTip=function(y,data){1595 var content,contentLength;1596 if(y>bottomY){1597 y=bottomY;1598 }1599 //线1600 cacheCursorContext.beginPath();1601 cacheCursorContext.strokeStyle="#000";1602 cacheCursorContext.moveTo(leftX,y);1603 cacheCursorContext.lineTo(rightX,y);1604 cacheCursorContext.stroke();1605 //背景1606 content=(max-range*(y-topY)/height).toFixed(2);1607 contentLength=cacheCursorContext.measureText(content).width;1608 drawRoundRect(leftX,y-fontSize/2,contentLength,fontSize);1609 //文字1610 cacheCursorContext.fillStyle="#999";1611 cacheCursorContext.font=fontSize+"px Arial";1612 cacheCursorContext.textAlign="left";1613 if(y+fontSize/2>bottomY){1614 cacheCursorContext.textBaseline="bottom";1615 y=bottomY;1616 }else if(y-fontSize/2<topY){1617 cacheCursorContext.textBaseline="top";1618 y=topY;1619 }else{1620 cacheCursorContext.textBaseline="middle";1621 }1622 cacheCursorContext.fillText(content,leftX,y);1623 };1624 //绘制分时图十字光标1625 drawCursor=function(x,y){1626 var temp,width=gapWidth+kWidth;1627 /*-------------公式计算找坐标---------------*/1628 //计算触控事件所在的K线数据索引1629 /*cursorIndex=Math.ceil((x-leftX-gapWidth/2-width)/width)+1;1630 //光标头部越界1631 cursorIndex=cursorIndex<1 ? 1:cursorIndex;1632 //光标尾部越界1633 cursorIndex=cursorIndex<end-start ? cursorIndex:end-start;1634 //计算柱中心坐标1635 cursorX=painterTool.getOdd(leftX+gapWidth/2+cursorIndex*width-width/2);*/1636 /*-------------遍历找坐标---------------*/1637 cursorX=leftX+width/2;1638 cursorIndex=1;1639 while(cursorX<x){1640 cursorIndex++;1641 cursorX+=width;1642 }1643 //尾部取数据数组越界1644 cursorIndex+=start-1;1645 if(cursorIndex<data.length){1646 cursorX=painterTool.getOdd(cursorX-width/2);1647 }else{1648 temp=data.length-start-1;1649 temp=temp<0 ? 0:temp;1650 cursorIndex=data.length-1;1651 cursorX=painterTool.getOdd(leftX+temp*width);1652 }1653 drawXTip(cursorX,data[cursorIndex]);1654 drawYTip(painterTool.getOdd(y),data[cursorIndex]);1655 };1656 /*1657 * 初始化基本配置1658 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1659 */1660 initSize=function(){1661 initValue();1662 };1663 /*1664 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1665 * trendData为分时数据,包含preclosePx昨收价1666 * trendData包含marketDetail数组,开盘收盘时间数组和分时图总数1667 */1668 drawReady=function(trendData,startPosition,endPosition){1669 if(!trendData || trendData.length==0){1670 return ;1671 }1672 data=trendData;1673 start=startPosition;1674 end=endPosition;1675 marketDetail=data.marketDetail;1676 handleData();1677 };1678 //onresize重绘1679 resizeDraw=function(){1680 initValue();1681 calcAxis();1682 drawFrame();1683 };1684 //判断x,y是否在分时图绘制区域内1685 insideOf=function(x,y){1686 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1687 return true;1688 }else{1689 return false;1690 }1691 };1692 //绘制分时图十字光标1693 showCursor=function(x,y){1694 cursorShowed=true;1695 cursorPositionX=x;1696 cursorPositionY=y;1697 drawCursor(x,y);1698 };1699 //关闭十字光标1700 turnOffCursor=function(){1701 cursorShowed=false;1702 };1703 return {1704 initSize:initSize,1705 drawReady:drawReady,1706 drawFrame:drawFrame,1707 resizeDraw:resizeDraw,1708 showCursor:showCursor,1709 turnOffCursor:turnOffCursor,1710 insideOf:insideOf1711 };1712 })();1713 /*1714 * 分时图成交量绘图器1715 */1716 trendBarPainter=(function(){1717 //数据1718 var data,initValue,max,width,height,leftX,rightX,topY,1719 bottomY,barX,layout,start,end;1720 //方法1721 var initSize,drawReady,resizeDraw,drawFrame,handleData,drawGrid,1722 drawBar,calcAxis,insideOf,showCursor,drawCursor,drawCursorTip;1723 //固定配置1724 layout={a:0.74,b:0.01,c:0.01,d:0.01};1725 initValue=function(){1726 leftX=painterTool.getOdd(realCanvas.width*layout.d,false);1727 rightX=painterTool.getOdd(realCanvas.width*(1-layout.b),true);1728 topY=painterTool.getOdd(realCanvas.height*layout.a,false);1729 bottomY=painterTool.getOdd(realCanvas.height*(1-layout.c),true);1730 width=rightX-leftX;1731 height=bottomY-topY;1732 };1733 //计算交易量柱的高度1734 calcAxis=function(){1735 var i;1736 for(i=start;i<end;i++){1737 data[i].baHeight=data[i][3]/max*height;1738 }1739 };1740 //计算成交量的最大值1741 handleData=function(){1742 var i;1743 max=data[0][3];1744 for(i=0,l=data.length;i<l;i++){1745 //for(i=start+1;i<end;i++){1746 if(max<data[i][3]){1747 max=data[i][3];1748 }1749 }1750 max*=maxRate;1751 calcAxis();1752 };1753 //绘制边框虚线1754 drawGrid=function(){1755 var y;1756 cacheContext.beginPath();1757 cacheContext.strokeStyle="#000";1758 cacheContext.lineWidth=1;1759 //绘制实线1760 cacheContext.moveTo(leftX,topY);1761 cacheContext.lineTo(rightX,topY);1762 cacheContext.lineTo(rightX,bottomY);1763 cacheContext.lineTo(leftX,bottomY);1764 cacheContext.closePath();1765 cacheContext.stroke();1766 //绘制虚线1767 y=painterTool.getOdd(topY+height/2);1768 painterTool.drawDashed({x:leftX,y:y},{x:rightX,y:y});1769 //绘制y轴文字1770 cacheContext.fillStyle="#999";1771 cacheContext.font=fontSize+"px Arial";1772 cacheContext.textAlign="left";1773 cacheContext.textBaseline="top";1774 cacheContext.fillText("成交量:"+max,leftX,topY);1775 };1776 //绘制成交量柱1777 drawBar=function(x,data){1778 var y;1779 cacheContext.beginPath();1780 cacheContext.fillStyle=kColor[data.color];1781 cacheContext.moveTo(x,bottomY);1782 cacheContext.lineTo(x+kWidth,bottomY);1783 y=bottomY-data.baHeight*process;1784 cacheContext.lineTo(x+kWidth,y);1785 cacheContext.lineTo(x,y);1786 cacheContext.closePath();1787 cacheContext.fill();1788 };1789 //根据process进度情况,绘制交易量图形帧1790 drawFrame=function(){1791 var width=kWidth/2,y;1792 drawGrid();1793 if(start<data.length){1794 //绘制头部半个交易量柱1795 cacheContext.beginPath();1796 cacheContext.fillStyle=kColor[data[start].color];1797 cacheContext.moveTo(leftX,bottomY);1798 cacheContext.lineTo(leftX+width,bottomY);1799 y=bottomY-data[start].baHeight*process;1800 cacheContext.lineTo(leftX+width,y);1801 cacheContext.lineTo(leftX,y);1802 cacheContext.closePath();1803 cacheContext.fill();1804 //绘制中间交易量柱1805 barX=leftX+gapWidth+width;1806 for(var i=start+1;i<end-1;i++){1807 drawBar(barX,data[i]);1808 barX+=gapWidth+kWidth;1809 }1810 //绘制尾部半个交易量柱1811 if(barX+kWidth>rightX){1812 cacheContext.beginPath();1813 cacheContext.fillStyle=kColor[data[i].color];1814 cacheContext.moveTo(rightX,bottomY);1815 cacheContext.lineTo(rightX-width,bottomY);1816 y=bottomY-data[i].baHeight*process;1817 cacheContext.lineTo(rightX-width,y);1818 cacheContext.lineTo(rightX,y);1819 cacheContext.closePath();1820 cacheContext.fill();1821 }else{1822 if(i<data.length){1823 drawBar(barX,data[i]);1824 }1825 }1826 }1827 };1828 //显示分时图交易量1829 drawCursorTip=function(){1830 var content,gap,x;1831 gap=1.02*cacheCursorContext.measureText("成交量:"+max).width;1832 x=rightX-gap;1833 cacheCursorContext.font=fontSize+"px Arial";1834 cacheCursorContext.textBaseline="top";1835 cacheCursorContext.textAlign="left";1836 //成交量1837 content="成交量:"+data[cursorIndex][3];1838 cacheCursorContext.fillStyle=kColor[data[cursorIndex].color];1839 cacheCursorContext.fillText(content,x,topY);1840 };1841 //显示分时图交易量图十字光标1842 drawCursor=function(x,y){1843 cacheCursorContext.beginPath();1844 cacheCursorContext.strokeStyle="#000";1845 cacheCursorContext.moveTo(cursorX,topY);1846 cacheCursorContext.lineTo(cursorX,bottomY);1847 cacheCursorContext.stroke();1848 drawCursorTip();1849 };1850 /*1851 * 初始化基本配置1852 * 数据不在initSize方法中被传入,否则触控事件就要多次不必要的调用init方法1853 */1854 initSize=function(){1855 initValue();1856 };1857 /*1858 * 根据传入的数据初始化配置变量,每次执行drawReady就认为数据有变化1859 */1860 drawReady=function(trendData,startPosition,endPosition){1861 if(!trendData || trendData.length==0){1862 return ;1863 }1864 data=trendData;1865 start=startPosition;1866 end=endPosition;1867 handleData();1868 };1869 //onresize重绘1870 resizeDraw=function(){1871 initValue();1872 calcAxis();1873 drawFrame();1874 };1875 //判断x,y是否在绘制区域内1876 insideOf=function(x,y){1877 if(x>=leftX && x<=rightX && y>=topY && y<=bottomY){1878 return true;1879 }else{1880 return false;1881 }1882 };1883 //绘制分时交易量图十字光标1884 showCursor=function(x,y){1885 drawCursor(x,y);1886 };1887 return {1888 initSize:initSize,1889 drawReady:drawReady,1890 drawFrame:drawFrame,1891 resizeDraw:resizeDraw,1892 showCursor:showCursor,1893 insideOf:insideOf1894 };1895 })();1896 /*1897 * 分时图五档/明细管理器1898 * 分时图五档明细采取节省流量的策略,展示什么刷新什么,因此会看到切换闪烁1899 */1900 textPainter=(function(){1901 //变量1902 var wdContent,mxContent,buttonTemplate,wdContainer,mxContainer,wdBtn,mxBtn;1903 //方法1904 var fillWDTemplate,fillMXTemplate,drawWD,drawMX,init,bindListener,1905 showWD,showMX;1906 //初始化text容器,加入dom树,display=none1907 init=function(){1908 //外部包裹的div1909 buttonTemplate='<ul class="stockgraph_wdmx_tab clearfix">'1910 +'<li id="stockgraph-wd" class="active">'1911 +'<a href="javascript:void(0)">五档</a>'1912 +'</li>'1913 +'<li id="stockgraph-mx">'1914 +'<a href="javascript:void(0)">明细</a href="javascript:void(0)">'1915 +'</li>'1916 +'</ul>';1917 textContainer=document.createElement("div");1918 textContainer.className="stockgraph_wdmx";1919 textContainer.style.display="none";1920 textContainer.innerHTML=buttonTemplate;1921 container.appendChild(textContainer);1922 //五档容器1923 wdContainer=document.createElement("div");1924 wdContainer.className="stockgraph_wd_mm";1925 //明细容器1926 mxContainer=document.createElement("div");1927 mxContainer.className="stockgraph_wd_mx";1928 //五档/明细按钮1929 wdBtn=document.getElementById("stockgraph-wd");1930 mxBtn=document.getElementById("stockgraph-mx");1931 //绑定切换事件1932 bindListener();1933 };1934 //切换到五档1935 showWD=function(){1936 wdContainer.style.display="block";1937 wdBtn.className="active";1938 mxContainer.style.display="none";1939 mxBtn.className="";1940 };1941 //切换到明细1942 showMX=function(){1943 wdContainer.style.display="none";1944 wdBtn.className="";1945 mxContainer.style.display="block";1946 mxBtn.className="active";1947 };1948 //绑定监听1949 bindListener=function(){1950 wdBtn.addEventListener("click",function(){1951 showWD();1952 if(wdContent!=undefined){1953 fillWDTemplate(wdContent);1954 }1955 requestDispatcher.getWD();1956 });1957 mxBtn.addEventListener("click",function(){1958 showMX();1959 if(mxContent!=undefined){1960 fillMXTemplate(mxContent);1961 }1962 requestDispatcher.getMX();1963 });1964 };1965 /*1966 * 填充五档模板1967 */1968 fillWDTemplate=function(data){1969 var wdTemplate,i,l,color,temp;1970 //卖1-卖51971 wdTemplate='<div class="stockgraph_wd_buy">';1972 temp=data.offer;1973 for(i=0,l=temp.length;i<l;i++){1974 color=temp[i].price<data.lastClosePx ? "d_color":"z_color";1975 wdTemplate+='<p class="clearfix">'1976 +'<span>卖'+(5-i)+'</span>'1977 +'<span class="'+color+'">'+temp[i].price+'</span>'1978 +'<span>'+temp[i].amount+'</span>'1979 +'</p>';1980 }1981 wdTemplate+='</div>';1982 //买1-买51983 wdTemplate+='<div class="stockgraph_wd_sell">';1984 temp=data.bid;1985 for(i=0,l=temp.length;i<l;i++){1986 color=temp[i].price<data.lastClosePx ? "d_color":"z_color";1987 wdTemplate+='<p class="clearfix">'1988 +'<span>买'+(i+1)+'</span>'1989 +'<span class="'+color+'">'+temp[i].price+'</span>'1990 +'<span>'+temp[i].amount+'</span>'1991 +'</p>';1992 }1993 wdTemplate+='</div>';1994 wdContainer.innerHTML=wdTemplate;1995 if(textContainer.contains(mxContainer)){1996 textContainer.removeChild(mxContainer);1997 }1998 textContainer.appendChild(wdContainer);1999 };2000 /*2001 * 填充明细模板2002 */2003 fillMXTemplate=function(data){2004 var i,l,color,mxTemplate,direction;2005 mxTemplate='<div class="stockgraph_mx_wrap">';2006 for(i=0,l=data.length;i<l;i++){2007 color=data[i].price<data.lastClosePx ? "d_color":"z_color";2008 direction=data[i].direction==0 ? "d_color":"z_color";2009 mxTemplate+='<p class="clearfix">'2010 +'<span class="time">'+data[i].time+'</span>'2011 +'<span class="'+color+'">'+data[i].price+'</span>'2012 +'<span class="'+direction+'">'+data[i].amount+'</span>'2013 +'</p>';2014 }2015 mxTemplate+='</div>';2016 mxContainer.innerHTML=mxTemplate;2017 if(textContainer.contains(wdContainer)){2018 textContainer.removeChild(wdContainer);2019 }2020 textContainer.appendChild(mxContainer);2021 };2022 //绘制五档2023 drawWD=function(content){2024 showWD();2025 wdContent=content;2026 fillWDTemplate(content);2027 };2028 //绘制明细2029 drawMX=function(content){2030 showMX();2031 mxContent=content;2032 fillMXTemplate(content);2033 };2034 return {2035 init:init,2036 drawWD:drawWD,2037 drawMX:drawMX2038 };2039 })();2040 /*2041 * 【K线蜡烛图、交易量柱图、MACD指标图】事件控制器,左右滑动、缩放事件、十字光标2042 */2043 kControl=(function(){2044 //变量2045 var totalLength,minScale,maxScale,scaleStep,scrollStep,currScale,2046 currPosition,data;2047 //方法2048 var init,draw,enlarge,narrow,scrollRight,scrollLeft,2049 calcMA,calcColor,showCursor,clearCursor,resize;2050 //固定变量2051 scaleStep=1;2052 scrollStep=1;2053 /*2054 * 计算均线值,传入股票数据和均线日期2055 * maData={2056 * 5:[[K线ma5,交易量ma5],[]...]2057 * }2058 */2059 calcMA=function(){2060 var i,j,k, l,sumk,sumb,maData;2061 maData={};2062 for(i=0,l=dayCount.length;i<l;i++){2063 maData[dayCount[i]]=[];2064 for(j=0;j<totalLength;j++){2065 if(j<dayCount[i]){2066 maData[dayCount[i]].push(["-","-"]);2067 continue;2068 }2069 sumk=0;2070 sumb=0;2071 for(k=0;k<dayCount[i];k++){2072 sumk+=data[j-k][4];2073 sumb+=data[j-k][5];2074 }2075 maData[dayCount[i]].push([sumk/dayCount[i],sumb/dayCount[i]]);2076 }2077 maData[dayCount[i]].push("-");2078 }2079 data.maData=maData;2080 };2081 //计算颜色指标2082 calcColor=function(){2083 for(var i=0;i<totalLength;i++){2084 //颜色指标2085 if(data[i][4]>=data[i][1]){2086 data[i].color=1;2087 }else{2088 data[i].color=0;2089 }2090 }2091 };2092 //日K十字光标2093 showCursor=function(x,y){2094 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2095 for(var i in painterStack){2096 painterStack[i].showCursor(x,y);2097 }2098 refreshCursorCache();2099 };2100 //清除日K十字光标2101 clearCursor=function(){2102 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2103 refreshCursorCache();2104 candlePainter.showMAText();2105 };2106 //控制器启动绘图2107 draw=function(){2108 var start;2109 start=currPosition-currScale;2110 start=start<0 ? 0:start;2111 currPosition=currPosition>totalLength ? totalLength:currPosition;2112 for(var i in painterStack){2113 painterStack[i].drawReady(data,start,currPosition,currScale);2114 }2115 animate();2116 };2117 //初始化比例尺2118 init=function(){2119 data=rawData;2120 totalLength=data.length;2121 /*minScale=totalLength>40 ? 40:totalLength;2122 maxScale=totalLength>100 ? 100:totalLength;2123 currScale=totalLength>60 ? 60:totalLength;*/2124 minScale=40;2125 maxScale=100;2126 currScale=totalLength>minScale ? (totalLength>60 ? 60:totalLength):minScale;2127 currPosition=totalLength;2128 calcMA();2129 calcColor();2130 draw();2131 };2132 //切换K线图种类时重新计算长宽2133 resize=function(){2134 for(var i in painterStack){2135 painterStack[i].initSize();;2136 }2137 };2138 //放大-减少显示条数2139 enlarge=function(){2140 if(currScale>minScale){2141 currScale-=scaleStep;2142 if(currScale<minScale){2143 currScale=minScale;2144 }2145 draw();2146 }else{2147 return ;2148 }2149 };2150 //缩小-增加显示条数2151 narrow=function(){2152 if(currScale<maxScale){2153 currScale+=scaleStep;2154 if(currScale>maxScale){2155 currScale=maxScale;2156 }2157 if(currScale>currPosition){2158 currPosition=currScale;2159 }2160 draw();2161 }else{2162 return ;2163 }2164 };2165 //手指向右滑动-数据向左滚动2166 scrollRight=function(){2167 if(currPosition>currScale){2168 currPosition-=scrollStep;2169 if(currPosition<currScale){2170 currPosition=currScale;2171 }2172 draw();2173 }else{2174 return ;2175 }2176 };2177 //手指向左滑动-数据向右滚动2178 scrollLeft=function(){2179 if(currPosition<totalLength){2180 currPosition+=scrollStep;2181 if(currPosition>totalLength){2182 currPosition=totalLength;2183 }2184 draw();2185 }else{2186 return ;2187 }2188 };2189 return {2190 init:init,2191 resize:resize,2192 enlarge:enlarge,2193 narrow:narrow,2194 scrollLeft:scrollLeft,2195 scrollRight:scrollRight,2196 showCursor:showCursor,2197 clearCursor:clearCursor2198 };2199 })();2200 /*2201 * 【K线分时图、交易量柱图】事件控制器,左右滑动、缩放事件、十字光标2202 */2203 trendControl=(function(){2204 //变量2205 var totalLength,minScale,maxScale,scaleStep,scrollStep,currScale,2206 currPosition,data;2207 //方法2208 var init,draw,enlarge,narrow,scrollRight,scrollLeft,calcColor,2209 calcBusinessAmount,showCursor,clearCursor,resize;2210 //计算交易量值2211 calcBusinessAmount=function(){2212 if(data.append){2213 return ;2214 }2215 var i,l;2216 //倒叙相减2217 for(l=data.length,i=l-1;i>0;i--){2218 data[i][3]=data[i][3]-data[i-1][3];2219 }2220 };2221 //计算交易量柱的颜色2222 calcColor=function(){2223 var i,l;2224 //增量分时图2225 if(data.append){2226 return ;2227 }2228 //第一个柱和昨收比2229 if(data[0][1]<data.preclosePx){2230 data[0].color=0;2231 }else{2232 data[0].color=1;2233 }2234 for(i=1,l=data.length;i<l;i++){2235 if(data[i][1]<data[i-1][1]){2236 data[i].color=0;2237 }else{2238 data[i].color=1;2239 }2240 }2241 };2242 //控制器启动绘图2243 draw=function(){2244 var start,end;2245 start=currPosition-currScale;2246 start=start<0 ? 0:start;2247 end=currPosition<data.length ? currPosition+1:data.length;2248 //放大缩小时2249 data.marketDetail.amount=currScale;2250 for(var i in painterStack){2251 painterStack[i].drawReady(data,start,end);2252 }2253 animate();2254 };2255 //分时图十字光标2256 showCursor=function(x,y){2257 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2258 for(var i in painterStack){2259 painterStack[i].showCursor(x,y);2260 }2261 refreshCursorCache();2262 };2263 //清除分时图十字光标2264 clearCursor=function(){2265 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2266 refreshCursorCache();2267 trendPainter.turnOffCursor();2268 };2269 //初始化比例尺2270 init=function(){2271 data=rawData;2272 if(!data.append){2273 //非增量初始化2274 totalLength=data.marketDetail.amount;2275 if(data.marketDetail.dayAmount==5){2276 scaleStep=20;2277 scrollStep=5;2278 minScale=parseInt(totalLength*0.4);2279 }else{2280 scaleStep=5;2281 scrollStep=1;2282 minScale=parseInt(totalLength*0.6);2283 }2284 maxScale=totalLength;2285 currScale=totalLength;2286 currPosition=totalLength;2287 }2288 calcBusinessAmount();2289 calcColor();2290 draw();2291 };2292 //切换K线图种类时重新计算长宽2293 resize=function(){2294 for(var i in painterStack){2295 painterStack[i].initSize();;2296 }2297 };2298 //放大-减少显示条数2299 enlarge=function(){2300 if(currScale>minScale){2301 currScale-=scaleStep;2302 if(currScale<minScale){2303 currScale=minScale;2304 }2305 draw();2306 }else{2307 return ;2308 }2309 };2310 //缩小-增加显示条数2311 narrow=function(){2312 if(currScale<maxScale){2313 currScale+=scaleStep;2314 if(currScale>maxScale){2315 currScale=maxScale;2316 }2317 if(currScale>currPosition){2318 currPosition=currScale;2319 }2320 draw();2321 }else{2322 return ;2323 }2324 };2325 //手指向右滑动-数据向左滚动2326 scrollRight=function(){2327 if(currPosition>currScale){2328 currPosition-=scrollStep;2329 if(currPosition<currScale){2330 currPosition=currScale;2331 }2332 draw();2333 }else{2334 return ;2335 }2336 };2337 //手指向左滑动-数据向右滚动2338 scrollLeft=function(){2339 if(currPosition<totalLength){2340 currPosition+=scrollStep;2341 if(currPosition>totalLength){2342 currPosition=totalLength;2343 }2344 draw();2345 }else{2346 return ;2347 }2348 };2349 return {2350 init:init,2351 resize:resize,2352 enlarge:enlarge,2353 narrow:narrow,2354 scrollLeft:scrollLeft,2355 scrollRight:scrollRight,2356 showCursor:showCursor,2357 clearCursor:clearCursor2358 };2359 })();2360 /*------------------------绘图器end---------------------------*/2361 /*2362 * 管理K线图的事件,绑定、解绑、页面刷新时重计算坐标2363 */2364 eventControl=(function(){2365 //变量2366 var hammerManager,hammerPan,hammerPinch,hammerPress,offsetLeft,offsetTop,2367 x,y,cursorShowed;2368 //方法-避免事件未被清理2369 var press,pressup,panup,pandown,panright,panleft,2370 panend,pinchin,pinchout,mousewheel,setup,bindListener,2371 destroy,setOffset;2372 hammerPan=new Hammer.Pan();2373 hammerPinch = new Hammer.Pinch();2374 hammerPress=new Hammer.Press();2375 hammerManager=new Hammer.Manager(canvasContainer);2376 hammerManager.add([hammerPan,hammerPinch,hammerPress]);2377 //长按2378 press=function(e){2379 cursorShowed=true;2380 currControl.showCursor(x,y);2381 };2382 //抬起手指2383 pressup=function(e){2384 cursorShowed=false;2385 currControl.clearCursor();2386 };2387 //向上滑2388 panup=function(e){2389 if(cursorShowed){2390 currControl.showCursor(x,y);2391 }2392 };2393 //向下滑2394 pandown=function(e){2395 if(cursorShowed){2396 currControl.showCursor(x,y);2397 }2398 };2399 //手指右滑2400 panright=function(e){2401 if(cursorShowed){2402 currControl.showCursor(x,y);2403 }else{2404 currControl.scrollRight();2405 }2406 };2407 //手指左滑2408 panleft=function(e){2409 if(cursorShowed){2410 currControl.showCursor(x,y);2411 }else{2412 currControl.scrollLeft();2413 }2414 };2415 //结束滑动2416 panend=function(e){2417 if(cursorShowed){2418 cursorShowed=false;2419 currControl.clearCursor();2420 }2421 };2422 //缩小2423 pinchin=function(e){2424 currControl.narrow();2425 };2426 //放大2427 pinchout=function(e){2428 currControl.enlarge();2429 };2430 mousewheel=function(e){2431 panend();2432 if(e.wheelDelta>0){2433 pinchin(e);2434 }else if(e.wheelDelta<0){2435 pinchout(e);2436 }2437 e.preventDefault();2438 };2439 //AOP封装方法2440 setup=function(callback){2441 return function(e){2442 x=(e.changedPointers[0].pageX-offsetLeft)*pixel;2443 y=(e.changedPointers[0].pageY-offsetTop)*pixel;2444 for(var i in painterStack){2445 if(painterStack[i].insideOf(x,y)){2446 callback(e);2447 return ;2448 }2449 }2450 if(cursorShowed){2451 currControl.clearCursor();2452 }2453 };2454 };2455 bindListener=function(){2456 //绑定所有事件2457 hammerManager.on("press",setup(press));2458 hammerManager.on("pressup",setup(pressup));2459 hammerManager.on("panup",setup(panup));2460 hammerManager.on("pandown",setup(pandown));2461 hammerManager.on("panright",setup(panright));2462 hammerManager.on("panleft",setup(panleft));2463 hammerManager.on("panend",setup(panend));2464 hammerManager.on("pinchin",pinchin);2465 hammerManager.on("pinchout",pinchout);2466 //鼠标滚动缩放事件2467 canvasContainer.addEventListener("mousewheel",mousewheel);2468 };2469 //销毁所有已绑定的事件2470 destroy=function(){2471 hammerManager.destroy();2472 hammerManager=new Hammer.Manager(canvasContainer);2473 hammerManager.add([hammerPan,hammerPinch,hammerPress]);2474 };2475 //设置canvasContainer的偏移量,计算坐标点2476 setOffset=function(){2477 var parent;2478 parent=canvasContainer;2479 offsetLeft=parent.offsetLeft;2480 offsetTop=parent.offsetTop;2481 while(parent.offsetParent){2482 parent=parent.offsetParent;2483 offsetLeft+=parent.offsetLeft;2484 offsetTop+=parent.offsetTop;2485 }2486 };2487 return {2488 init:setOffset,2489 bindListener:bindListener,2490 destroy:destroy,2491 resize:setOffset2492 }2493 })();2494 /*2495 * 切换currControl,传入control对象2496 * 清除上一个control设置的监听事件2497 * 启动绘图方法2498 */2499 triggerControl=function(control){2500 if(currControl==control){2501 currControl.init();2502 return ;2503 }2504 painterStack=[];2505 if(control==trendControl){2506 cacheCursorContext.clearRect(0,0,cacheCursorCanvas.width,cacheCursorCanvas.height);2507 refreshCursorCache();2508 painterStack.push(trendPainter);2509 painterStack.push(trendBarPainter);2510 canvasContainer.style.width="72%";2511 textContainer.style.display="block";2512 }else if(control==kControl){2513 painterStack.push(candlePainter);2514 painterStack.push(kBarPainter);2515 painterStack.push(extraPainterCollection.MACDPainter);2516 canvasContainer.style.width="100%";2517 textContainer.style.display="none";2518 }2519 //销毁上一个K线图的监听事件2520 eventControl.destroy();2521 //切换K线图控制器2522 currControl=control;2523 //重设画布长宽2524 initCanvas();2525 //重新计算事件坐标的偏移量2526 eventControl.resize();2527 //重新计算每个绘图器内部长宽边界2528 currControl.resize();2529 //绑定触控事件2530 eventControl.bindListener();2531 //开始绘制2532 currControl.init();2533 };2534 /*2535 * 动画,执行所有进入方法栈的drawFrame方法2536 * 如果process为1,则animate退化成无动画绘制2537 * 每个页面只执行一次动画,要修改的话,在最后一次animate将process初始化2538 */2539 animate=function(){2540 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2541 speed=Math.ceil((100-process*100)/20)/100;2542 process+=speed;2543 if(process<1){2544 for(var i in painterStack){2545 painterStack[i].drawFrame();2546 }2547 requestAnimationFrame(animate);2548 }else{2549 process=1;2550 for(var i in painterStack){2551 painterStack[i].drawFrame();2552 }2553 }2554 refreshCache();2555 };2556 //将虚拟画布上的图形刷新到画布上2557 refreshCache=function(){2558 canvasContainer.removeChild(realCanvas);2559 realContext.clearRect(0,0,realCanvas.width,realCanvas.height);2560 realContext.drawImage(cacheCanvas,0,0);2561 canvasContainer.appendChild(realCanvas);2562 };2563 //十字光标的画布缓冲绘图2564 refreshCursorCache=function(){2565 canvasContainer.removeChild(realCursorCanvas);2566 realCursorContext.clearRect(0,0,realCursorCanvas.width,realCursorCanvas.height);2567 realCursorContext.drawImage(cacheCursorCanvas,0,0);2568 canvasContainer.appendChild(realCursorCanvas);2569 };2570 //全局初始化,调用各个内部初始化方法,页面就绪即可执行2571 init=function(){2572 initCanvas();2573 eventControl.init();2574 candlePainter.initSize();2575 kBarPainter.initSize();2576 trendPainter.initSize();2577 trendBarPainter.initSize();2578 textPainter.init();2579 extraPainterCollection.initSize();2580 };2581 2582 //开始绘制,接收接口返回的数据2583 draw=function(ajaxData,period){2584 loading=false;2585 rawData=ajaxData;2586 if(!rawData.append){2587 process=0;2588 }2589 if(period>9){2590 //分时图2591 triggerControl(trendControl);2592 }else{2593 //K线图2594 triggerControl(kControl);2595 }2596 };2597 //窗口大小变化时重绘2598 resize=function(){2599 initCanvas();2600 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2601 for(var i in painterStack){2602 painterStack[i].resizeDraw();2603 refreshCache();2604 }2605 eventControl.resize();2606 refreshCache();2607 };2608 //查询股票资料时展示loading2609 showLoading=function(){2610 realContext.clearRect(0,0,realCanvas.width,realCanvas.height);2611 loading=true;2612 setTimeout(function(){2613 if(loading){2614 cacheContext.clearRect(0,0,cacheCanvas.width,cacheCanvas.height);2615 cacheContext.font=fontSize*2+"px Arial";2616 cacheContext.textBaseline="bottom";2617 cacheContext.textAlign="center";2618 cacheContext.fillStyle="#999";2619 cacheContext.fillText("Loading...",cacheCanvas.width/2,cacheCanvas.height*0.382);2620 refreshCache();2621 }2622 },100);2623 };2624 return {2625 init:init,2626 draw:draw,2627 resize:resize,2628 showLoading:showLoading,2629 textPainter:textPainter2630 };2631 })();2632 /*2633 * 请求分派器,管理所有的ajax请求,并执行相应操作2634 */2635 requestDispatcher=(function(){2636 //变量2637 var authorization,storage,supportType,crc,minTime,trendTimer,textType;2638 //方法2639 var queryToken,queryKLine,queryTrend,queryMarketDetail,queryPreclosePx,handleToken,2640 handleKLine,handleTrend,handleMarketDetail,getKLine,setTimer,storeStorage,2641 queryTrend5Day,appendTrend,handleAppend,queryTick,queryReal,appendText,2642 handleText,handleWD,handleMX,getWD,getMX;2643 /*2644 * storage={2645 * code:2646 * period:2647 * trend:2648 * amount:2649 * preclosePx:2650 * text2651 * lastClosePx2652 * }2653 */2654 storage={};2655 //五档/明细/默认值2656 textType=["wd","mx","wd"];2657 supportType={2658 "1分钟":1,2659 "5分钟":2,2660 "15分钟":3,2661 "30分钟":4,2662 "60分钟":5,2663 "日K":6,2664 "周K":7,2665 "月K":8,2666 "年K":9,2667 "分时":10,2668 "五日":112669 };2670 //分时图设置定时器,优化美股时差2671 setTimer=function(){2672 var i,l,now,minutes;2673 clearInterval(trendTimer);2674 trendTimer=setInterval(function(){2675 if(storage.period<10){2676 clearInterval(trendTimer);2677 return ;2678 }2679 now=new Date();2680 minutes=now.getMinutes();2681 if(minutes<10){2682 minutes="0"+minutes;2683 }2684 now=parseInt(now.getHours()+""+minutes);2685 //开盘前刷新昨收价2686 if(now>storage.marketDetail[0].open_time-10 && now<storage.marketDetail[0].open_time){2687 queryPreclosePx(storage.code,storage.period,true);2688 }2689 for(i=0,l=storage.marketDetail.length;i<l;i++){2690 //后台部分接口数据有时间差,前后取缓冲时间2691 if(now>=storage.marketDetail[i].open_time-5 && now<=storage.marketDetail[i].close_time+10){2692 appendTrend();2693 appendText(storage.code,storage.text);2694 }2695 }2696 },6000);2697 };2698 /*2699 * 分时图多个数据存储2700 * real昨收 & marketDetail总量 & trend数据2701 */2702 storeStorage=function(code,period,attr,data){2703 if(code!=storage.code || period!=storage.period){2704 return ;2705 }2706 storage[attr]=data;2707 handleTrend();2708 };2709 //分时增量查询结果处理2710 handleAppend=function(data){2711 var now,temp;2712 storage.trend.append=true;2713 if(data.length==1){2714 //这分钟数据变动中2715 data[0][3]=data[0][3]-storage.trend.lastData[3];2716 data[0].color=data[0][1]<storage.trend.lastData[1] ? 0:1;2717 storage.trend.pop();2718 storage.trend.push(data[0]);2719 }else if(data.length==2){2720 //增量数据,这分钟数据确定了2721 now=new Date();2722 now=parseInt(now.getHours()+""+now.getMinutes());2723 //开盘清数据2724 if(now==storage.marketDetail[0].open_time){2725 storage.trend=[];2726 storage.trend.preclosePx=storage.preclosePx;2727 storage.trend.marketDetail=storage.marketDetail;2728 storage.trend.lastData=[0,0,0,0];2729 }2730 data[1][3]=data[1][3]-data[0][3];2731 temp=data[0].concat();2732 data[0][3]=data[0][3]-storage.trend.lastData[3];2733 data[0].color=data[0][1]<storage.trend.lastData[1] ? 0:1;2734 data[1].color=data[1][1]<data[0][1] ? 0:1;2735 storage.trend.lastData=temp;2736 storage.trend.pop();2737 storage.trend.push(data[0]);2738 storage.trend.push(data[1]);2739 }else{2740 //五日分时初始化append2741 var l=data.length-1;2742 data[l][3]=data[l][3]-storage.trend.lastData[3];2743 data[l].color=data[l][1]<storage.trend.lastData[1] ? 0:1;2744 storage.trend.pop();2745 storage.trend.push(data[l]);2746 }2747 KPainter.draw(storage.trend,storage.period);2748 };2749 /*2750 * 处理五档数据2751 * offer为逆序,显示在上,卖5-卖12752 * bid为正序,显示在下,买1-买52753 */2754 handleWD=function(data){2755 var content,temp,i,l,position,per;2756 per=data[1];2757 content={bid:[],offer:[]};2758 l=5;2759 //bid2760 temp=data[2];2761 temp=temp.split(",");2762 for(i=0;i<l;i++){2763 position=i*3;2764 content.bid.push({2765 price:+temp[position],2766 amount:Math.round(temp[position+1]/per)2767 });2768 }2769 //offer2770 temp=data[3];2771 temp=temp.split(",");2772 for(i=l-1;i>=0;i--){2773 position=i*3;2774 content.offer.push({2775 price:+temp[position],2776 amount:Math.round(temp[position+1]/per)2777 });2778 }2779 //昨收2780 content.lastClosePx=storage.lastClosePx;2781 KPainter.textPainter.drawWD(content);2782 //保存每手股数,供明细使用2783 storage.per=per;2784 };2785 /*2786 * 处理明细数据2787 * 生成一个对象数组,供textPainter使用2788 */2789 handleMX=function(data){2790 var content,i,l,time,length;2791 content=[];2792 for(i=0,l=data.length;i<l;i++){2793 time=data[i][0].toString();2794 length=time.length;2795 time=time.substring(length-6,length-4)+":"+time.substring(length-4,length-2)+":"+time.substring(length-2,length);2796 content.push({2797 time:time,2798 price:data[i][1],2799 amount:Math.round(data[i][2]/storage.per),2800 direction:data[i][3]2801 });2802 }2803 //昨收2804 content.lastClosePx=storage.lastClosePx;2805 KPainter.textPainter.drawMX(content);2806 };2807 //处理五档/明细2808 handleText=function(code,text,data){2809 var checker;2810 if(code!=storage.code || text!=storage.text){2811 return ;2812 }2813 //防止五档/明细处理时昨收数据还没返回2814 checker=setInterval(function(){2815 if(storage.lastClosePx!=undefined){2816 clearInterval(checker);2817 if(text==textType[0]){2818 handleWD(data);2819 }else if(text==textType[1]){2820 handleMX(data);2821 }2822 }2823 },10);2824 };2825 //校验code,period是否正确,执行蜡烛绘图方法2826 handleKLine=function(code,period,data){2827 if(code!=storage.code){2828 return ;2829 }2830 if(period!=storage.period){2831 return ;2832 }2833 KPainter.draw(data,period);2834 };2835 //检查数据完备与否,执行分时绘图方法,storage在刷新股票时会清空2836 handleTrend=function(){2837 var head;2838 if(storage.marketDetail==undefined || storage.trend==undefined || storage.preclosePx==undefined){2839 return ;2840 }2841 storage.trend.preclosePx=storage.preclosePx;2842 storage.trend.marketDetail=storage.marketDetail;2843 head=storage.trend.length-2;2844 head=head<0 ? 0:head;2845 storage.trend.lastData=storage.trend[head].concat();2846 KPainter.draw(storage.trend,storage.period);2847 };2848 //检查数据完备与否,计算分时总量,时间分布。storage在刷新股票时会清空2849 handleMarketDetail=function(code,period,data){2850 var marketDetail,amount,temp,open,close,hour,minute,inAmerica,2851 openHour,closeHour,openMinute,closeMinute;2852 marketDetail=data.trade_section_grp;2853 //openapi返回的时序有问题,冒泡排序2854 for(var i=0,l=marketDetail.length;i<l;i++){2855 for(var j=0,m=l-i-1;j<m;j++){2856 if(marketDetail[j].open_time>marketDetail[j+1].open_time){2857 temp=marketDetail[j];2858 marketDetail[j]=marketDetail[j+1];2859 marketDetail[j+1]=temp;2860 }2861 }2862 }2863 //计算时间差2864 amount=0;2865 marketDetail.inAmerica=Config.AmericanStockList.indexOf(code.split(".")[1])>-1 ? true:false;2866 for(i=0;i<l;i++){2867 open=marketDetail[i].open_time.toString();2868 close=marketDetail[i].close_time.toString();2869 openHour=open.substring(0,open.length-2);2870 closeHour=close.substring(0,close.length-2);2871 openMinute=open.substring(open.length-2,open.length);2872 closeMinute=close.substring(close.length-2,close.length);2873 hour=closeHour-openHour;2874 minute=closeMinute-openMinute;2875 //13:30-15:002876 if(minute<0){2877 hour-=1;2878 minute+=60;2879 }2880 amount+=hour*60+minute;2881 if(marketDetail.inAmerica){2882 //美股转换时差,painterTool访问不到2883 openHour=openHour-13;2884 openHour=openHour<0 ? openHour+24:openHour;2885 openHour=openHour<10 ? "0"+openHour:openHour;2886 marketDetail[i].open_time=openHour+openMinute;2887 closeHour=closeHour-13;2888 closeHour=closeHour<0 ? closeHour+24:closeHour;2889 closeHour=closeHour<10 ? "0"+closeHour:closeHour;2890 marketDetail[i].close_time=closeHour+closeMinute;2891 }2892 }2893 if(period==10){2894 marketDetail.amount=amount;2895 marketDetail.dayAmount=1;2896 marketDetail.singleDay=amount;2897 }else if(period==11){2898 marketDetail.amount=amount*5;2899 marketDetail.dayAmount=5;2900 marketDetail.singleDay=amount;2901 }2902 storeStorage(code,period,"marketDetail",marketDetail);2903 };2904 //openapi获取token成功2905 handleToken=function(result){2906 if(result){2907 authorization=result.token_type+" "+result.access_token;2908 }2909 if(storage.period!=undefined && storage.code!=undefined){2910 switch(storage.period){2911 case 10:2912 //分时图2913 queryMarketDetail(storage.code,storage.period);2914 queryTrend(storage.code,storage.period);2915 queryPreclosePx(storage.code,storage.period);2916 appendText(storage.code,storage.text);2917 setTimer();2918 break;2919 case 11:2920 //五日分时2921 queryMarketDetail(storage.code,storage.period);2922 queryTrend5Day(storage.code,storage.period);2923 queryPreclosePx(storage.code,storage.period);2924 appendText(storage.code,storage.text);2925 setTimer();2926 break;2927 default:2928 //K线图2929 queryKLine(storage.code,storage.period);2930 break;2931 }2932 }2933 };2934 //获取openapi的K线数据2935 queryKLine=function(code,period){2936 var localKLine;2937 localKLine=sessionStorage.getItem("kline");2938 localKLine=JSON.parse(localKLine);2939 if(localKLine && localKLine[code] && localKLine[code][period]){2940 handleKLine(code,period,localKLine[code][period].data.candle[code]);2941 }else{2942 Util.ajax({2943 type:"get",2944 url:"https://open.hscloud.cn/quote/v1/kline",2945 contentType:"application/x-www-form-urlencoded; charset=utf-8",2946 data:{2947 get_type:"offset",2948 prod_code:code,2949 candle_period:period,2950 fields:"open_px,high_px,low_px,close_px,business_amount",2951 data_count:2002952 },2953 beforeSend: function(request) {2954 request.setRequestHeader("Authorization",authorization);2955 },2956 success:function(result){2957 if(result){2958 localKLine || (localKLine={});2959 localKLine[code] || (localKLine[code]={});2960 localKLine[code][period]=result;2961 sessionStorage.setItem("kline",JSON.stringify(localKLine));2962 handleKLine(code,period,result.data.candle[code]);2963 }2964 },2965 error:function(error){2966 console.error("queryKLine:",error);2967 }2968 });2969 }2970 };2971 //获取openapi分时数据2972 queryTrend=function(code,period){2973 Util.ajax({2974 type:"get",2975 url:"https://open.hscloud.cn/quote/v1/trend",2976 contentType:"application/x-www-form-urlencoded; charset=utf-8",2977 data:{2978 prod_code:code,2979 fields:"last_px,avg_px,business_amount"2980 //,date:201703082981 },2982 beforeSend: function(request) {2983 request.setRequestHeader("Authorization",authorization);2984 },2985 success:function(result){2986 if(result){2987 var data=result.data.trend[code];2988 crc=result.data.trend.crc[code];2989 try{2990 minTime=data[data.length-1][0].toString().substring(8,12);2991 }catch(e){2992 console.info("openapiError:",e);2993 }2994 storeStorage(code,period,"trend",data);2995 }2996 },2997 error:function(error){2998 console.error("queryTrend:",error);2999 }3000 });3001 };3002 //分时图五档3003 queryReal=function(code,text){3004 Util.ajax({3005 type:"get",3006 url:"https://open.hscloud.cn/quote/v1/real",3007 contentType:"application/x-www-form-urlencoded; charset=utf-8",3008 data:{3009 en_prod_code:code,3010 fields:"bid_grp,offer_grp"3011 },3012 beforeSend: function(request) {3013 request.setRequestHeader("Authorization",authorization);3014 },3015 success:function(result){3016 if(result){3017 handleText(code,text,result.data.snapshot[code]);3018 }3019 },3020 error:function(error){3021 console.error("queryReal:",error);3022 }3023 });3024 };3025 //分时图明细3026 queryTick=function(code,text){3027 Util.ajax({3028 type:"get",3029 url:"https://open.hscloud.cn/quote/v1/tick",3030 contentType:"application/x-www-form-urlencoded; charset=utf-8",3031 data:{3032 prod_code:code,3033 //0-卖,1-买3034 fields:"hq_px,business_amount,business_direction",3035 data_count:103036 },3037 beforeSend: function(request) {3038 request.setRequestHeader("Authorization",authorization);3039 },3040 success:function(result){3041 if(result){3042 handleText(code,text,result.data.tick[code]);3043 }3044 },3045 error:function(error){3046 console.error("queryTick:",error);3047 }3048 });3049 };3050 //增量查询分时接口3051 appendTrend=function(){3052 Util.ajax({3053 type:"get",3054 url:"https://open.hscloud.cn/quote/v1/trend",3055 contentType:"application/x-www-form-urlencoded; charset=utf-8",3056 data:{3057 prod_code:storage.code,3058 fields:"last_px,avg_px,business_amount",3059 crc:crc,3060 min_time:minTime3061 //,date:201703083062 },3063 beforeSend: function(request) {3064 request.setRequestHeader("Authorization",authorization);3065 },3066 success:function(result){3067 if(result){3068 var data=result.data.trend[storage.code];3069 crc=result.data.trend.crc[storage.code];3070 minTime=data[data.length-1][0].toString().substring(8,12);3071 handleAppend(data);3072 }3073 },3074 error:function(error){3075 console.error("appendTrend:",error);3076 }3077 });3078 };3079 //定时刷新五档/明细的内容3080 appendText=function(code,text){3081 if(text==textType[0]){3082 queryReal(code,text);3083 }else if(text==textType[1]){3084 queryTick(code,text);3085 }3086 };3087 //获取openapi五日分时数据3088 queryTrend5Day=function(code,period){3089 Util.ajax({3090 type:"get",3091 url:"https://open.hscloud.cn/quote/v1/trend5day",3092 contentType:"application/x-www-form-urlencoded; charset=utf-8",3093 data:{3094 prod_code:code,3095 fields:"last_px,avg_px,business_amount"3096 },3097 beforeSend: function(request) {3098 request.setRequestHeader("Authorization",authorization);3099 },3100 success:function(result){3101 if(result){3102 //增量查询3103 var data=result.data.trend[code];3104 storeStorage(code,period,"trend",data);3105 }3106 },3107 error:function(){3108 console.error("queryTrend:",error);3109 }3110 });3111 };3112 //获取分时图数据总量3113 queryMarketDetail=function(code,period){3114 var postfix=code.split(".")[1];3115 //避免请求超时3116 if(Config.tradeSectionGrp[postfix]){3117 handleMarketDetail(code,period,Config.tradeSectionGrp[postfix]);3118 return ;3119 }3120 //请求marketDetail3121 Util.ajax({3122 type:"get",3123 url:"https://open.hscloud.cn/quote/v1/market/detail",3124 contentType:"application/x-www-form-urlencoded",3125 data:{3126 finance_mic:postfix3127 //finance_mic:"XSGE"3128 },3129 beforeSend:function(request) {3130 request.setRequestHeader("Authorization",authorization);3131 },3132 success:function(result){3133 if(result){3134 Config.tradeSectionGrp[postfix]=result.data;3135 handleMarketDetail(code,period,result.data);3136 }3137 },3138 error:function(error){3139 console.error("queryMarketDetail:",error);3140 }3141 });3142 };3143 //获取昨收价3144 queryPreclosePx=function(code,period,refreshNew){3145 var dataAcount;3146 dataAcount=period==10 ? 2:6;3147 Util.ajax({3148 type:"get",3149 url:"https://open.hscloud.cn/quote/v1/kline",3150 contentType:"application/x-www-form-urlencoded; charset=utf-8",3151 data:{3152 get_type:"offset",3153 prod_code:code,3154 candle_period:6,3155 fields:"close_px",3156 data_count:dataAcount3157 },3158 beforeSend: function(request) {3159 request.setRequestHeader("Authorization",authorization);3160 },3161 success:function(result){3162 if(result){3163 if(code==storage.code){3164 if(period==10){3165 storage.lastClosePx=result.data.candle[code][0][1];3166 }else if(period==11){3167 storage.lastClosePx=result.data.candle[code][4][1];3168 }3169 if(!refreshNew){3170 //如果是初始化,需要走storeStorage以执行handleTrend3171 storeStorage(code,period,"preclosePx",result.data.candle[code][0][1]);3172 }else{3173 //如果是开盘前,不需执行handleTrend3174 if(period==storage.period){3175 storage.preclosePx=result.data.candle[code][0][1];3176 }3177 }3178 }3179 }3180 },3181 error:function(error){3182 console.error("queryPreclosePx:",error);3183 }3184 });3185 };3186 //获取hundsun-openapi的token3187 queryToken=function(){3188 var APPKEY="your-key";3189 var APPSECRET="your-secret";3190 var BASIC="Basic ";3191 var auth=Base64.encode(APPKEY+":"+APPSECRET);3192 var openId="bigbird-kline:"+Math.random();3193 Util.ajax({3194 type:"post",3195 url:"https://open.hscloud.cn"+"/oauth2/oauth2/token",3196 contentType:"application/x-www-form-urlencoded",3197 data:{3198 grant_type:"client_credentials",3199 open_id:openId3200 },3201 beforeSend:function(request) {3202 request.setRequestHeader("Authorization", BASIC+auth);3203 },3204 success:function(result){3205 if(result){3206 handleToken(result);3207 }3208 },3209 error:function(error){3210 console.error("queryToken:",error);3211 }3212 });3213 };3214 /*3215 * 暴露给外部使用的查询方法。传入K线类别和股票代码为参数3216 * 1:1分钟 2:5分钟 3:15分钟 4:30分钟 5:60分钟 6:日K 7:周K 8:月K 9:年K3217 * 10:分时 11:五日3218 */3219 getKLine=function(period,code){3220 var per;3221 if(code!=undefined){3222 //保存之前的text状态3223 if(code!=storage.code){3224 textType[3]=textType[0];3225 }3226 //保存每手股数3227 per=storage.per;3228 //切换股票时刷新storage,避免分时图残留数据影响3229 storage={};3230 storage.code=code;3231 storage.text=textType[3];3232 storage.per=per;3233 }3234 storage.period=supportType[period];3235 if(authorization==undefined){3236 queryToken();3237 }else{3238 handleToken();3239 }3240 };3241 //切换到查询五档3242 getWD=function(){3243 storage.text=textType[0];3244 textType[3]=storage.text;3245 appendText(storage.code,storage.text);3246 };3247 //切换到查询明细3248 getMX=function(){3249 storage.text=textType[1];3250 textType[3]=storage.text;3251 appendText(storage.code,storage.text);3252 };3253 return {3254 getKLine:getKLine,3255 getWD:getWD,3256 getMX:getMX3257 };3258 })();3259 /*3260 * 页面控制器,管理页面启动,页面重置等页面级逻辑3261 */3262 pageControl=(function(){3263 //方法3264 var beginPage,bindListener;3265 //页面启动逻辑3266 beginPage=function(){3267 KPainter.init();3268 bindListener();3269 };3270 //页面重置3271 bindListener=function(){3272 window.addEventListener("resize",function(){3273 KPainter.resize();3274 });3275 };3276 return {3277 beginPage:beginPage3278 };3279 })();3280 StockGraph=(function(){3281 var draw;3282 draw=function(p,c){3283 KPainter.showLoading();3284 requestDispatcher.getKLine(p,c);3285 };3286 return {3287 draw:draw3288 };3289 })();3290 Util.ready(pageControl.beginPage);3291 window.StockGraph=StockGraph;...

Full Screen

Full Screen

ReactFiberCacheComponent.old.js

Source:ReactFiberCacheComponent.old.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {ReactContext} from 'shared/ReactTypes';10import type {FiberRoot} from './ReactInternalTypes';11import type {Lanes} from './ReactFiberLane.old';12import type {StackCursor} from './ReactFiberStack.old';13import {enableCache} from 'shared/ReactFeatureFlags';14import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';15import {isPrimaryRenderer} from './ReactFiberHostConfig';16import {createCursor, push, pop} from './ReactFiberStack.old';17import {pushProvider, popProvider} from './ReactFiberNewContext.old';18export type Cache = Map<() => mixed, mixed>;19export type CacheComponentState = {|20 +parent: Cache,21 +cache: Cache,22|};23export type SpawnedCachePool = {|24 +parent: Cache,25 +pool: Cache,26|};27export const CacheContext: ReactContext<Cache> = enableCache28 ? {29 $$typeof: REACT_CONTEXT_TYPE,30 // We don't use Consumer/Provider for Cache components. So we'll cheat.31 Consumer: (null: any),32 Provider: (null: any),33 // We'll initialize these at the root.34 _currentValue: (null: any),35 _currentValue2: (null: any),36 _threadCount: 0,37 }38 : (null: any);39if (__DEV__ && enableCache) {40 CacheContext._currentRenderer = null;41 CacheContext._currentRenderer2 = null;42}43// The cache that newly mounted Cache boundaries should use. It's either44// retrieved from the cache pool, or the result of a refresh.45let pooledCache: Cache | null = null;46// When retrying a Suspense/Offscreen boundary, we override pooledCache with the47// cache from the render that suspended.48const prevFreshCacheOnStack: StackCursor<Cache | null> = createCursor(null);49export function pushCacheProvider(workInProgress: Fiber, cache: Cache) {50 if (!enableCache) {51 return;52 }53 pushProvider(workInProgress, CacheContext, cache);54}55export function popCacheProvider(workInProgress: Fiber, cache: Cache) {56 if (!enableCache) {57 return;58 }59 popProvider(CacheContext, workInProgress);60}61export function requestCacheFromPool(renderLanes: Lanes): Cache {62 if (!enableCache) {63 return (null: any);64 }65 if (pooledCache !== null) {66 return pooledCache;67 }68 // Create a fresh cache.69 pooledCache = new Map();70 return pooledCache;71}72export function pushRootCachePool(root: FiberRoot) {73 if (!enableCache) {74 return;75 }76 // When we start rendering a tree, read the pooled cache for this render77 // from `root.pooledCache`. If it's currently `null`, we will lazily78 // initialize it the first type it's requested. However, we only mutate79 // the root itself during the complete/unwind phase of the HostRoot.80 pooledCache = root.pooledCache;81}82export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) {83 if (!enableCache) {84 return;85 }86 // The `pooledCache` variable points to the cache that was used for new87 // cache boundaries during this render, if any. Stash it on the root so that88 // parallel transitions may share the same cache. We will clear this field89 // once all the transitions that depend on it (which we track with90 // `pooledCacheLanes`) have committed.91 root.pooledCache = pooledCache;92 if (pooledCache !== null) {93 root.pooledCacheLanes |= renderLanes;94 }95}96export function restoreSpawnedCachePool(97 offscreenWorkInProgress: Fiber,98 prevCachePool: SpawnedCachePool,99): SpawnedCachePool | null {100 if (!enableCache) {101 return (null: any);102 }103 const nextParentCache = isPrimaryRenderer104 ? CacheContext._currentValue105 : CacheContext._currentValue2;106 if (nextParentCache !== prevCachePool.parent) {107 // There was a refresh. Don't bother restoring anything since the refresh108 // will override it.109 return null;110 } else {111 // No refresh. Resume with the previous cache. This will override the cache112 // pool so that any new Cache boundaries in the subtree use this one instead113 // of requesting a fresh one.114 push(prevFreshCacheOnStack, pooledCache, offscreenWorkInProgress);115 pooledCache = prevCachePool.pool;116 // Return the cache pool to signal that we did in fact push it. We will117 // assign this to the field on the fiber so we know to pop the context.118 return prevCachePool;119 }120}121// Note: Ideally, `popCachePool` would return this value, and then we would pass122// it to `getSuspendedCachePool`. But factoring reasons, those two functions are123// in different phases/files. They are always called in sequence, though, so we124// can stash the value here temporarily.125let _suspendedPooledCache: Cache | null = null;126export function popCachePool(workInProgress: Fiber) {127 if (!enableCache) {128 return;129 }130 _suspendedPooledCache = pooledCache;131 pooledCache = prevFreshCacheOnStack.current;132 pop(prevFreshCacheOnStack, workInProgress);133}134export function getSuspendedCachePool(): SpawnedCachePool | null {135 if (!enableCache) {136 return null;137 }138 // We check the cache on the stack first, since that's the one any new Caches139 // would have accessed.140 let pool = pooledCache;141 if (pool === null) {142 // There's no pooled cache above us in the stack. However, a child in the143 // suspended tree may have requested a fresh cache pool. If so, we would144 // have unwound it with `popCachePool`.145 if (_suspendedPooledCache !== null) {146 pool = _suspendedPooledCache;147 _suspendedPooledCache = null;148 } else {149 // There's no suspended cache pool.150 return null;151 }152 }153 return {154 // We must also save the parent, so that when we resume we can detect155 // a refresh.156 parent: isPrimaryRenderer157 ? CacheContext._currentValue158 : CacheContext._currentValue2,159 pool,160 };161}162export function getOffscreenDeferredCachePool(): SpawnedCachePool | null {163 if (!enableCache) {164 return null;165 }166 if (pooledCache === null) {167 // There's no deferred cache pool.168 return null;169 }170 return {171 // We must also store the parent, so that when we resume we can detect172 // a refresh.173 parent: isPrimaryRenderer174 ? CacheContext._currentValue175 : CacheContext._currentValue2,176 pool: pooledCache,177 };...

Full Screen

Full Screen

ReactFiberCacheComponent.new.js

Source:ReactFiberCacheComponent.new.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {ReactContext} from 'shared/ReactTypes';10import type {FiberRoot} from './ReactInternalTypes';11import type {Lanes} from './ReactFiberLane.new';12import type {StackCursor} from './ReactFiberStack.new';13import {enableCache} from 'shared/ReactFeatureFlags';14import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';15import {isPrimaryRenderer} from './ReactFiberHostConfig';16import {createCursor, push, pop} from './ReactFiberStack.new';17import {pushProvider, popProvider} from './ReactFiberNewContext.new';18export type Cache = Map<() => mixed, mixed>;19export type CacheComponentState = {|20 +parent: Cache,21 +cache: Cache,22|};23export type SpawnedCachePool = {|24 +parent: Cache,25 +pool: Cache,26|};27export const CacheContext: ReactContext<Cache> = enableCache28 ? {29 $$typeof: REACT_CONTEXT_TYPE,30 // We don't use Consumer/Provider for Cache components. So we'll cheat.31 Consumer: (null: any),32 Provider: (null: any),33 // We'll initialize these at the root.34 _currentValue: (null: any),35 _currentValue2: (null: any),36 _threadCount: 0,37 }38 : (null: any);39if (__DEV__ && enableCache) {40 CacheContext._currentRenderer = null;41 CacheContext._currentRenderer2 = null;42}43// The cache that newly mounted Cache boundaries should use. It's either44// retrieved from the cache pool, or the result of a refresh.45let pooledCache: Cache | null = null;46// When retrying a Suspense/Offscreen boundary, we override pooledCache with the47// cache from the render that suspended.48const prevFreshCacheOnStack: StackCursor<Cache | null> = createCursor(null);49export function pushCacheProvider(workInProgress: Fiber, cache: Cache) {50 if (!enableCache) {51 return;52 }53 pushProvider(workInProgress, CacheContext, cache);54}55export function popCacheProvider(workInProgress: Fiber, cache: Cache) {56 if (!enableCache) {57 return;58 }59 popProvider(CacheContext, workInProgress);60}61export function requestCacheFromPool(renderLanes: Lanes): Cache {62 if (!enableCache) {63 return (null: any);64 }65 if (pooledCache !== null) {66 return pooledCache;67 }68 // Create a fresh cache.69 pooledCache = new Map();70 return pooledCache;71}72export function pushRootCachePool(root: FiberRoot) {73 if (!enableCache) {74 return;75 }76 // When we start rendering a tree, read the pooled cache for this render77 // from `root.pooledCache`. If it's currently `null`, we will lazily78 // initialize it the first type it's requested. However, we only mutate79 // the root itself during the complete/unwind phase of the HostRoot.80 pooledCache = root.pooledCache;81}82export function popRootCachePool(root: FiberRoot, renderLanes: Lanes) {83 if (!enableCache) {84 return;85 }86 // The `pooledCache` variable points to the cache that was used for new87 // cache boundaries during this render, if any. Stash it on the root so that88 // parallel transitions may share the same cache. We will clear this field89 // once all the transitions that depend on it (which we track with90 // `pooledCacheLanes`) have committed.91 root.pooledCache = pooledCache;92 if (pooledCache !== null) {93 root.pooledCacheLanes |= renderLanes;94 }95}96export function restoreSpawnedCachePool(97 offscreenWorkInProgress: Fiber,98 prevCachePool: SpawnedCachePool,99): SpawnedCachePool | null {100 if (!enableCache) {101 return (null: any);102 }103 const nextParentCache = isPrimaryRenderer104 ? CacheContext._currentValue105 : CacheContext._currentValue2;106 if (nextParentCache !== prevCachePool.parent) {107 // There was a refresh. Don't bother restoring anything since the refresh108 // will override it.109 return null;110 } else {111 // No refresh. Resume with the previous cache. This will override the cache112 // pool so that any new Cache boundaries in the subtree use this one instead113 // of requesting a fresh one.114 push(prevFreshCacheOnStack, pooledCache, offscreenWorkInProgress);115 pooledCache = prevCachePool.pool;116 // Return the cache pool to signal that we did in fact push it. We will117 // assign this to the field on the fiber so we know to pop the context.118 return prevCachePool;119 }120}121// Note: Ideally, `popCachePool` would return this value, and then we would pass122// it to `getSuspendedCachePool`. But factoring reasons, those two functions are123// in different phases/files. They are always called in sequence, though, so we124// can stash the value here temporarily.125let _suspendedPooledCache: Cache | null = null;126export function popCachePool(workInProgress: Fiber) {127 if (!enableCache) {128 return;129 }130 _suspendedPooledCache = pooledCache;131 pooledCache = prevFreshCacheOnStack.current;132 pop(prevFreshCacheOnStack, workInProgress);133}134export function getSuspendedCachePool(): SpawnedCachePool | null {135 if (!enableCache) {136 return null;137 }138 // We check the cache on the stack first, since that's the one any new Caches139 // would have accessed.140 let pool = pooledCache;141 if (pool === null) {142 // There's no pooled cache above us in the stack. However, a child in the143 // suspended tree may have requested a fresh cache pool. If so, we would144 // have unwound it with `popCachePool`.145 if (_suspendedPooledCache !== null) {146 pool = _suspendedPooledCache;147 _suspendedPooledCache = null;148 } else {149 // There's no suspended cache pool.150 return null;151 }152 }153 return {154 // We must also save the parent, so that when we resume we can detect155 // a refresh.156 parent: isPrimaryRenderer157 ? CacheContext._currentValue158 : CacheContext._currentValue2,159 pool,160 };161}162export function getOffscreenDeferredCachePool(): SpawnedCachePool | null {163 if (!enableCache) {164 return null;165 }166 if (pooledCache === null) {167 // There's no deferred cache pool.168 return null;169 }170 return {171 // We must also store the parent, so that when we resume we can detect172 // a refresh.173 parent: isPrimaryRenderer174 ? CacheContext._currentValue175 : CacheContext._currentValue2,176 pool: pooledCache,177 };...

Full Screen

Full Screen

innerAnimation.js

Source:innerAnimation.js Github

copy

Full Screen

1//import FileChange from '@/utils/fileChange';2//import WebApi from '@/axios/api';3let data = []4let recorder5let context6let cacheContext7let canvas8let cacheCanvas9let url10export default class innerAnimationRecorder {11 constructor() {12 if (!innerAnimationRecorder.instance) {13 this.recorder = null14 innerAnimationRecorder.instance = this15 }16 return innerAnimationRecorder.instance;17 }18 initRecorder(canvasOptions) {19 data = [];20 canvas = document.createElement("canvas")21 canvas.width = canvasOptions.width;22 canvas.height = canvasOptions.height;23 context = canvas.getContext("2d");24 context.fillStyle = "#ffffff";25 context.fillRect(0, 0, canvas.width, canvas.height);26 //cache context27 cacheCanvas = document.createElement("canvas")28 cacheCanvas.width = canvas.width;29 cacheCanvas.height = canvas.height;30 cacheContext = cacheCanvas.getContext("2d");31 cacheContext.fillStyle = "#ffffff";32 cacheContext.fillRect(0, 0, cacheCanvas.width, cacheCanvas.height);33 let stream = canvas.captureStream()34 var options = {35 mimeType: 'video/webm'36 }37 recorder = new MediaRecorder(stream, options);38 this.recorder = recorder;39 recorder.start();40 this.isStopCreatUrl = false;41 recorder.ondataavailable = function (event) {42 data.push(event.data);43 // console.log("event.data", event.data, recorder.state)44 };45 }46 //绘制svg的每一帧动画canvas,通过canvas录制47 start = (imageURL) => {48 if (recorder.state !== 'recording') {49 recorder.start(30);50 }51 cacheContext.clearRect(0, 0, cacheCanvas.width, cacheCanvas.height);52 cacheContext.fillStyle = "#ffffff";53 cacheContext.fillRect(0, 0, cacheCanvas.width, cacheCanvas.height);54 var img = new Image();55 img.src = imageURL;56 img.width = cacheCanvas.width57 img.width = cacheCanvas.height58 img.onload = function () {59 cacheContext.drawImage(img, 0, 0, canvas.width, canvas.height)60 context.drawImage(cacheCanvas, 0, 0, cacheCanvas.width, cacheCanvas.height)61 }62 }63 //结束录制64 finish = () => {65 return new Promise((resolve, reject) => {66 //console.log("finish结束录制", recorder,recorder.state)67 if (recorder && recorder.state === 'recording') {68 //结束录制69 recorder.stop();70 this.recorder = null71 setTimeout(() => {72 if (!this.isStopCreatUrl) {73 let videoBlob = new Blob(data, { type: "video/mp4" });74 url = URL.createObjectURL(videoBlob);75 //fileChange76 // FileChange.blobToDataURL(videoBlob, (dataURI) => {77 // let base64Data = dataURI.split(",")[1];78 // console.log("base64Data", base64Data)79 // let folderId = '4962';80 // let name = "chartvideo";//重名会引起接口报错81 // let type = 'video' //文件夹不会显示此类型文件82 // WebApi.CreatNewAsset(folderId, type, name, dataURI).then(resolve => {83 // console.log("上传", resolve.data.id)84 // })85 // })86 //console.log("setTimeout...", url)87 resolve(url)88 }89 }, 16)90 }91 })92 }93 //用户退出录制过程94 stop = () => {95 //console.log("用户退出录制过程...")96 if (this.recorder && recorder.state === 'recording') {97 //结束录制98 recorder.stop();99 this.recorder = null;100 this.isStopCreatUrl = true; //此种情况是,在录制过程中,取消录制101 }102 //console.log("用户退出录制过程..recorder.", this.recorder)103 }...

Full Screen

Full Screen

MemCachePlugin.js

Source:MemCachePlugin.js Github

copy

Full Screen

1/*2 * Copyright 2021 Adobe. All rights reserved.3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");4 * you may not use this file except in compliance with the License. You may obtain a copy5 * of the License at http://www.apache.org/licenses/LICENSE-2.06 *7 * Unless required by applicable law or agreed to in writing, software distributed under8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS9 * OF ANY KIND, either express or implied. See the License for the specific language10 * governing permissions and limitations under the License.11 */12let caches = {};13/**14 * Cache plugin for MSAL15 * @class MemCachePlugin16 * @implements ICachePlugin17 */18export default class MemCachePlugin {19 constructor(context, { key, base }) {20 const { log } = context;21 this.log = log;22 this.key = key;23 this.base = base;24 }25 static clear() {26 caches = {};27 }28 async beforeCacheAccess(cacheContext) {29 try {30 this.log.info('mem: read token cache', this.key);31 const cache = caches[this.key];32 if (cache) {33 cacheContext.tokenCache.deserialize(cache);34 return true;35 } else if (this.base) {36 this.log.info('mem: read token cache failed. asking base');37 const ret = await this.base.beforeCacheAccess(cacheContext);38 if (ret) {39 this.log.info('mem: base updated. remember.');40 caches[this.key] = cacheContext.tokenCache.serialize();41 }42 return ret;43 }44 } catch (e) {45 this.log.warn('mem: unable to deserialize token cache.', e);46 }47 return false;48 }49 async afterCacheAccess(cacheContext) {50 if (cacheContext.cacheHasChanged) {51 this.log.info('mem: write token cache', this.key);52 caches[this.key] = cacheContext.tokenCache.serialize();53 if (this.base) {54 this.log.info('mem: write token cache done. telling base', this.key);55 return this.base.afterCacheAccess(cacheContext);56 }57 return true;58 }59 return false;60 }...

Full Screen

Full Screen

aboutCache.js

Source:aboutCache.js Github

copy

Full Screen

1/* This Source Code Form is subject to the terms of the Mozilla Public2 * License, v. 2.0. If a copy of the MPL was not distributed with this3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */4// First, parse and save the incoming arguments ("?storage=name&context=key")5// Note: window.location.search doesn't work with nsSimpleURIs used for about:* addresses.6var search = window.location.href.match(/^.*\?(.*)$/);7var searchParams = new URLSearchParams(search ? search[1] : '');8var storage = searchParams.get('storage');9var cacheContext = searchParams.get('context');10// The context is in a format as used by the HTTP cache v2 back end11if (cacheContext)12 var [context, isAnon, isInBrowser, appId, isPrivate] = cacheContext.match(/(a,)?(b,)?(i\d+,)?(p,)?/);13if (appId)14 appId = appId.match(/i(\d+),/)[1];15function $(id) { return document.getElementById(id) || {}; }16// Initialize the context UI controls at the start according what we got in the "context=" argument17addEventListener('DOMContentLoaded', function() {18 $('anon').checked = !!isAnon;19 $('inbrowser').checked = !!isInBrowser;20 $('appid').value = appId || '';21 $('priv').checked = !!isPrivate;22}, false);23// When user presses the [Update] button, we build a new context key according the UI control24// values and navigate to a new about:cache?storage=<name>&context=<key> URL.25function navigate()26{27 context = '';28 if ($('anon').checked)29 context += 'a,';30 if ($('inbrowser').checked)31 context += 'b,';32 if ($('appid').value)33 context += 'i' + $('appid').value + ',';34 if ($('priv').checked)35 context += 'p,';36 window.location.href = 'about:cache?storage=' + storage + '&context=' + context;...

Full Screen

Full Screen

index.js

Source:index.js Github

copy

Full Screen

1import React from 'react'2import ReactDOM from 'react-dom'3import App from './pages/App'4import connectors from './connectors.js'5import Web3Provider from 'web3-react'6import PropTypes from 'prop-types'7import 'styles/transitions.css'8import 'styles/bootstrap.custom.scss'9import { useIpfs } from './hooks/useIpfs'10import { IpfsContext } from './contexts/ipfs'11import { CacheContext, Cache } from './contexts/cache'12function ContextProviders ({ children }) {13 const ipfs = useIpfs()14 return (15 <Web3Provider connectors={ connectors } libraryName="ethers.js">16 <CacheContext.Provider value={Cache()}>17 <IpfsContext.Provider value={ipfs}>18 { children }19 </IpfsContext.Provider>20 </CacheContext.Provider>21 </Web3Provider>22 )23}24ContextProviders.propTypes = {25 children: PropTypes.object.isRequired26}27ReactDOM.render(28 <ContextProviders>29 <App />30 </ContextProviders>,31 document.getElementById('root')...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.screenshot({ path: 'example.png' });7 await browser.close();8})();9const { chromium } = require('playwright');10(async () => {11 const browser = await chromium.launch();12 const context = await browser.newContext();13 const page = await context.newPage();14 await browser.cacheContext(context);15 await page.screenshot({ path: 'example.png' });16 await browser.close();17})();18const { chromium } = require('playwright');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext();22 await browser.cacheContext(context);23 const page = await context.newPage();24 await page.screenshot({ path: 'example.png' });25 await browser.close();26})();27const { chromium } = require('playwright');28(async () => {29 const browser = await chromium.launch();30 const context = await browser.newContext();31 await browser.cacheContext(context);32 const page = await context.newPage();33 await page.screenshot({ path: 'example.png' });34 await browser.clearContextCache();35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch();40 const context = await browser.newContext();41 await browser.cacheContext(context);42 const page = await context.newPage();43 await page.screenshot({ path: 'example.png' });44 await browser.clearContextCache();45 await browser.cacheContext(context);46 await page.screenshot({ path: 'example.png' });

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const cookies = await context.cookies();7 console.log(cookies);8 await context.close();9 await browser.close();10})();11const { chromium } = require('playwright');12(async () => {13 const browser = await chromium.launch();14 const context = await browser.newContext();15 const page = await context.newPage();16 const cookies = await context.cookies();17 console.log(cookies);18 await context.close();19 await browser.close();20})();21const { chromium } = require('playwright');22(async () => {23 const browser = await chromium.launch();24 const context = await browser.newContext();25 const page = await context.newPage();26 const cookies = await context.cookies();27 console.log(cookies);28 await context.close();29 await browser.close();30})();31const { chromium } = require('playwright');32(async () => {33 const browser = await chromium.launch();34 const context = await browser.newContext();35 const page = await context.newPage();36 const cookies = await context.cookies();37 console.log(cookies);38 await context.close();39 await browser.close();40})();41const { chromium } = require('playwright');42(async () => {43 const browser = await chromium.launch();44 const context = await browser.newContext();45 const page = await context.newPage();46 const cookies = await context.cookies();47 console.log(cookies);48 await context.close();49 await browser.close();50})();51const { chromium } = require('playwright');52(async () => {53 const browser = await chromium.launch();54 const context = await browser.newContext();55 const page = await context.newPage();

Full Screen

Using AI Code Generation

copy

Full Screen

1const {chromium} = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForSelector('text=Example Domain');7 await context.cacheContext();8 await browser.close();9})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2const { cacheContext } = require('playwright/lib/server/browserContext');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.screenshot({ path: 'example.png' });8 await cacheContext(context);9 await browser.close();10})();11const { chromium } = require('playwright');12const { restoreContext } = require('playwright/lib/server/browserContext');13(async () => {14 const browser = await chromium.launch();15 const context = await restoreContext(browser, 'cacheId');16 const page = await context.newPage();17 await page.screenshot({ path: 'example.png' });18 await browser.close();19})();20const cacheId = context._cacheId;21const { chromium } = require('playwright');22const { cacheContext, restoreContext } = require('playwright/lib/server/browserContext');23(async () => {24 const browser = await chromium.launch();25 const context = await browser.newContext();26 const page = await context.newPage();27 await page.screenshot({ path: 'example.png' });28 await cacheContext(context);29 const cacheId = context._cacheId;30 const restoredContext = await restoreContext(browser, cacheId);31 const restoredPage = await restoredContext.newPage();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { cacheContext } = require('playwright/lib/server/browserContext');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const context = await browser.newContext();6 await cacheContext(context);7 await context.close();8 await browser.close();9})();10const { restoreContext } = require('playwright/lib/server/browserContext');11const { chromium } = require('playwright');12(async () => {13 const browser = await chromium.launch({ headless: false });14 const context = await restoreContext(browser, 'b6f2e6d9-bf9a-4f1d-9e6d-1b6c8f6d4f6c');15 await context.close();16 await browser.close();17})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium, webkit, firefox } = require('playwright');2const { cacheContext } = require('playwright/lib/server/chromium/crBrowser');3const browser = await chromium.launch();4const context = await browser.newContext();5const page = await context.newPage();6await cacheContext(context);7await browser.close();8const { chromium, webkit, firefox } = require('playwright');9const { cachedContext } = require('playwright/lib/server/chromium/crBrowser');10const browser = await chromium.launch();11const context = await cachedContext(browser, 'context-id');12const page = await context.newPage();13await browser.close();14const { chromium, webkit, firefox } = require('playwright');15const { cachedPage } = require('playwright/lib/server/chromium/crBrowser');16const browser = await chromium.launch();17const context = await browser.newContext();18const page = await cachedPage(context, 'page-id');19await browser.close();20const { chromium, webkit, firefox } = require('playwright');21const { cacheBrowser } = require('playwright/lib/server/chromium/crBrowser');22const browser = await chromium.launch();23const context = await browser.newContext();24const page = await context.newPage();25await cacheBrowser(browser, 'browser-id');26await browser.close();27const { chromium, webkit, firefox } = require('playwright');28const { cachedBrowser } = require('playwright/lib/server/chromium/crBrowser');29const browser = await cachedBrowser(chromium, 'browser-id');30const context = await browser.newContext();31const page = await context.newPage();32await browser.close();

Full Screen

Using AI Code Generation

copy

Full Screen

1const browser = await chromium.launch();2const context = await browser.newContext();3const page = await context.newPage();4const cacheContext = await page.context().cacheContext();5await cacheContext.addCacheEntry({6 { name: 'Content-Type', value: 'text/html' },7 { name: 'Content-Length', value: '123' },8 body: Buffer.from('<html></html>'),9});10await browser.close();11const browser = await chromium.launch();12const context = await browser.newContext();13const page = await context.newPage();14const cacheContext = await page.context().cacheContext();15await cacheContext.addCacheEntry({16 { name: 'Content-Type', value: 'text/html' },17 { name: 'Content-Length', value: '123' },18 body: Buffer.from('<html></html>'),19});20await browser.close();21const browser = await chromium.launch();22const context = await browser.newContext();23const page = await context.newPage();24const cacheContext = await page.context().cacheContext();25await cacheContext.addCacheEntry({26 { name: 'Content-Type', value: 'text/html' },27 { name: 'Content-Length', value: '123' },28 body: Buffer.from('<html></html>'),29});30await browser.close();31const browser = await chromium.launch();32const context = await browser.newContext();33const page = await context.newPage();34const cacheContext = await page.context().cacheContext();35await cacheContext.addCacheEntry({36 { name: 'Content-Type', value: 'text/html' },37 { name: 'Content-Length', value

Full Screen

Using AI Code Generation

copy

Full Screen

1const {chromium} = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 await context.close();6 await browser.close();7})();8const {chromium} = require('playwright');9(async () => {10 const browser = await chromium.launch();11 const context = await browser.newContext();12 const cookies = await context.cookies();13 console.log(cookies);14 await context.close();15 await browser.close();16})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const context = await browser.newContext();2const page = await context.newPage();3const cachedContext = await page.context().cacheContext();4await cachedContext.close();5await page.close();6await context.close();7I am trying to run the above code with the latest version of Playwright (1.8.0) and Node (14.15.4) but I am getting the following error:8 at CDPSession.send (C:\Users\myuser\playwright\playwright\node_modules\playwright-core\lib\cdp\cdpSession.js:119:19)9 at async BrowserContext.close (C:\Users\myuser\playwright\playwright\node_modules\playwright-core\lib\server\browserContext.js:130:5)

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful