【4858美高梅】落到实处放大镜效果,canvas落成弧形可拖动过程条效果

By admin in 4858美高梅 on 2019年4月22日

图表放大镜

图片放大镜

一、效果如下:

简介:

canvas是html五最器重的因素,提供了2个画布的作用,有庞大的图形管理才能

4858美高梅 1

寻思导图

效果

4858美高梅 2
在线演示
  
源码

效果

4858美高梅 3
在线演示
  
源码

4858美高梅 4

canvas标签增多

要使用canvas,首先要在body中增添上canvas标签

canvas标签是1块暗中认可300*150轻重的画布

原理

首先采纳图片的一块区域,然后将那块区域加大,然后再绘制到原来的图片上,保障两块区域的大旨点一致,
如下图所示:
4858美高梅 5

原理

先是选取图片的1块区域,然后将那块区域加大,然后再绘制到原来的图样上,保证两块区域的中央点1致,
如下图所示:
4858美高梅 6

二、

画布宽高设置:

动用canvas标签的品质,width及height直接在行间设置

此地注意:不要用css样式去改画布大小,那些会促成画布中的图像被拉伸

<canvas id="canvas1" width="800" height="500"></canvas>

初始化

<canvas id="canvas" width="500" height="500">
</canvas>

<img src="image.png" style="display: none" id="img">

收获 canvas 和 image 对象,那里运用 <img> 标签预加载图片,
关于图片预加载能够看这里

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var img = document.getElementById("img");

设置相关变量

// 图片被放大区域的中心点,也是放大镜的中心点
var centerPoint = {};
// 图片被放大区域的半径
var originalRadius = 100;
// 图片被放大区域
var originalRectangle = {};
// 放大倍数
var scale = 2;
// 放大后区域
var scaleGlassRectangle

初始化

<canvas id="canvas" width="500" height="500">
</canvas>

<img src="image.png" style="display: none" id="img">

收获 canvas 和 image 对象,那里运用 <img> 标签预加载图片,
关于图片预加载能够看这里

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var img = document.getElementById("img");

安装相关变量

// 图片被放大区域的中心点,也是放大镜的中心点
var centerPoint = {};
// 图片被放大区域的半径
var originalRadius = 100;
// 图片被放大区域
var originalRectangle = {};
// 放大倍数
var scale = 2;
// 放大后区域
var scaleGlassRectangle

本文是达成可拖动滑块实现的基本思路,及叁个粗略的dome,()

画布css样式

画布的其它css样式能够平常设置

canvas标签中的内容
canvas标签中的内容是(包罗标签)唯有在不帮衬此功用的低版本浏览器中才会呈现的;在高版本浏览器中不会显得出来

<canvas id="canvas1" width="800" height="500">
    只是一个canvas标签,然而你看不到
</canvas>

画背景图片

function drawBackGround() {
    context.drawImage(img, 0, 0);
}

画背景图片

function drawBackGround() {
    context.drawImage(img, 0, 0);
}

【4858美高梅】落到实处放大镜效果,canvas落成弧形可拖动过程条效果。三、

获取canvas标签及上下文

canvas标签使用js符合规律dom节点的获得格局获得

var canvas = document.getElementById('canvas1');

上下文是记录canvas实行命令语句的地方,获取如下,前边的参数未来唯有二d可选

var context = canvas.getContext('2d');

算算图片被加大的区域的界定

此间大家采用鼠标的职分作为被放大区域的大旨点(放大镜随着鼠标移动而运动),因为
canvas
在画图纸的时候,须要精通左上角的坐标以及区域的宽高,所以那边大家总结区域的限定

function calOriginalRectangle(point) {
    originalRectangle.x = point.x - originalRadius;
    originalRectangle.y = point.y - originalRadius;
    originalRectangle.width = originalRadius * 2;
    originalRectangle.height = originalRadius * 2;
}

测算图片被放大的区域的限量

此处我们运用鼠标的职责作为被推广区域的主干点(放大镜随着鼠标移动而移动),因为
canvas
在画图纸的时候,必要通晓左上角的坐标以及区域的宽高,所以那里大家总结区域的界定

function calOriginalRectangle(point) {
    originalRectangle.x = point.x - originalRadius;
    originalRectangle.y = point.y - originalRadius;
    originalRectangle.width = originalRadius * 2;
    originalRectangle.height = originalRadius * 2;
}

1、首先在html中成立一个canvas标签

canvas坐标系

左上角是00点,x轴正方向向右,y轴正方向向下

4858美高梅 7

绘图放大镜区域

制图放大镜区域

<canvas id="canvas"  width="400" height="400"></canvas>

体制设置

边框设置:context.strokeStyle
填充设置:context.fillStyle
线宽设置:context.lineWidth

context.strokeStyle = "red";
context.lineWidth = 2;
context.fillStyle = 'yellow';

剪裁区域

放大镜一般是圈子的,那里大家采纳 clip
函数裁剪出三个圆形区域,然后在该区域中绘制放大后的图。一旦缩短了有些区域,以后全部的绘图都会被限制的那个区域里,那里我们运用
saverestore 方法清除裁剪区域的熏陶。save
保存当前画布的3遍状态,包括 canvas 的内外文属性,比如
stylelineWidth 等,然后会将以此意况压入多少个仓房。restore
用来还原上3回 save 的景况,从仓库里弹出最顶层的情事。

context.save();
context.beginPath();
context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
context.clip();
......
context.restore();

剪裁区域

放大镜一般是圈子的,那里咱们选取 clip
函数裁剪出一个圆形区域,然后在该区域中绘制放大后的图。壹旦减少了有个别区域,以往全数的绘图都会被限定的这几个区域里,那里大家运用
saverestore 方法清除裁剪区域的熏陶。save
保存当前画布的3次状态,包括 canvas 的前后文属性,比如
stylelineWidth 等,然后会将以此景况压入三个仓房。restore
用来苏醒上二遍 save 的景观,从仓库里弹出最顶层的图景。

context.save();
context.beginPath();
context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
context.clip();
......
context.restore();

2、创建贰个进程条对象,编写开头化方法,获取canvas对象及上下文景况;event方法是用来绑定事件(具体后边介绍);draw是用来绘图的措施,那里把Draw对象的上上下下办法赋给draw方法;创造绘图实例p,绘制伊始图形;

绘图图形

计量放大镜区域

通过大旨点、被放大区域的宽高以及放大倍数,获得区域的左上角坐标以及区域的宽高。

scaleGlassRectangle = {
    x: centerPoint.x - originalRectangle.width * scale / 2,
    y: centerPoint.y - originalRectangle.height * scale / 2,
    width: originalRectangle.width * scale,
    height: originalRectangle.height * scale
}

总计放大镜区域

因而着力点、被放大区域的宽高以及放大倍数,获得区域的左上角坐标以及区域的宽高。

scaleGlassRectangle = {
    x: centerPoint.x - originalRectangle.width * scale / 2,
    y: centerPoint.y - originalRectangle.height * scale / 2,
    width: originalRectangle.width * scale,
    height: originalRectangle.height * scale
}
var Draw={
 init:function(){
 this.obj=document.getElementById("canvas"); //获取canvas对象
 this.cObj=document.getElementById("canvas").getContext("2d");//获取canvas对象上下文环境
 this.event(); //初始化事件
 this.pathr=120; //滑动路径半径
 this.draw.prototype=this; //draw继承Draw方法
 this.p=new this.draw(112,284,18); //创建实例p
  } 
  //... 
}
制图命令
  1. 边框式绘制:context.stroke();
  2. 填充式绘制:context.fill();

绘制图片

在此地大家应用
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 方法,将
canvas
自己作为壹副图片,然后取被加大区域的图像,将其绘制到放大镜区域里。

context.drawImage(canvas,
    originalRectangle.x, originalRectangle.y,
    originalRectangle.width, originalRectangle.height,
    scaleGlassRectangle.x, scaleGlassRectangle.y,
    scaleGlassRectangle.width, scaleGlassRectangle.height
);

绘图图片

在那边大家采纳
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 方法,将
canvas
自个儿作为1副图片,然后取被加大区域的图像,将其绘制到放大镜区域里。

context.drawImage(canvas,
    originalRectangle.x, originalRectangle.y,
    originalRectangle.width, originalRectangle.height,
    scaleGlassRectangle.x, scaleGlassRectangle.y,
    scaleGlassRectangle.width, scaleGlassRectangle.height
);

3、在Draw中编辑绘图方法draw绘制下图:

新建路线beginPath()

这几个方法表示重新起首一段路线,也能够领略为新建二个图层
这么些的方法之后实行的绘图动作,不会奉行到这一个艺术此前的下令

context.beginPath();

绘图放大边缘

createRadialGradient 用来绘制渐变图像

context.beginPath();
var gradient = context.createRadialGradient(
    centerPoint.x, centerPoint.y, originalRadius - 5,
    centerPoint.x, centerPoint.y, originalRadius);
gradient.addColorStop(0, 'rgba(0,0,0,0.2)');
gradient.addColorStop(0.80, 'silver');
gradient.addColorStop(0.90, 'silver');
gradient.addColorStop(1.0, 'rgba(150,150,150,0.9)');

context.strokeStyle = gradient;
context.lineWidth = 5;
context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
context.stroke();

绘图放大边缘

createRadialGradient 用来绘制渐变图像

context.beginPath();
var gradient = context.createRadialGradient(
    centerPoint.x, centerPoint.y, originalRadius - 5,
    centerPoint.x, centerPoint.y, originalRadius);
gradient.addColorStop(0, 'rgba(0,0,0,0.2)');
gradient.addColorStop(0.80, 'silver');
gradient.addColorStop(0.90, 'silver');
gradient.addColorStop(1.0, 'rgba(150,150,150,0.9)');

context.strokeStyle = gradient;
context.lineWidth = 5;
context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
context.stroke();

4858美高梅 8

绘图直线:
  1. 安装画笔开端地方:context.moveTo(x,y)
  2. 安装画笔甘休地方:context.lineTo(x,y)
  3. 线条两边圆角:context.lineCap = "round"

context.strokeStyle = "red";
context.lineWidth = 2;
context.moveTo(100,100);
context.lineTo(500,100);
context.stroke();

4858美高梅 9

增加鼠标事件

为 canvas 增多鼠标移动事件

canvas.onmousemove = function (e) {
    ......
}

加多鼠标事件

为 canvas 增多鼠标移动事件

canvas.onmousemove = function (e) {
    ......
}

(一)创设绘图方法,获取参数

制图三角:方法便是绘制三条直线

制图多条连接线段时,不必每便重复定义起先点
画笔会停在上一段线段的终端,并默以为下二遍绘制的先导点

context.strokeStyle = "red";
context.lineWidth = 2;

context.moveTo(10,10);
context.lineTo(10,110);
context.lineTo(110,110);
context.lineTo(10,10);
context.stroke();

留意,此处用绘制直线的诀要,实行图片的绘图时;直线封闭处会冒出毛病,不会全盘关闭

4858美高梅 10

4858美高梅 11

改变坐标

鼠标事件获得坐标一般为显示屏的要么 window 的坐标,我们要求将其装换为
canvas 的坐标。getBoundingClientRect
用于获取页面中某些成分的左,上,右和下各自针锋相对浏览器视窗的岗位。

function windowToCanvas(x, y) {
    var bbox = canvas.getBoundingClientRect();
    return {x: x - bbox.left, y: y - bbox.top}
}

转移坐标

鼠标事件获得坐标一般为显示器的仍然 window 的坐标,大家须要将其装换为
canvas 的坐标。getBoundingClientRect
用于获取页面中有些成分的左,上,右和下独家针锋相对浏览器视窗的职位。

function windowToCanvas(x, y) {
    var bbox = canvas.getBoundingClientRect();
    return {x: x - bbox.left, y: y - bbox.top}
}
draw:function(x,y,r,j){ //绘图
 this.cObj.clearRect(0,0,400,400); //清空画布
 this.x=x; //滑块坐标x
 this.y=y; //滑块坐标y 
 this.r=r; //滑块移动路径半径
 this.j=j; //橙色圆弧结束弧度值
 //...
}
关闭方法:context.closePath()

拉长上边的关闭命令后,闭合处的弱点就会被修复
本条方法会自动将起点与末点相连,所以不必再将路线回到伊始点

context.strokeStyle = "red";
context.lineWidth = 2;

context.beginPath();
context.moveTo(10,10);
context.lineTo(10,110);
context.lineTo(110,110);
context.closePath();  //封闭路径后最后一个点就不用定义了
context.stroke();

4858美高梅 12

4858美高梅 13

修改鼠标准样品式

我们能够通过 css 来修改鼠标准样品式

#canvas {
    display: block;
    border: 1px solid red;
    margin: 0 auto;
    cursor: crosshair;
}

修改鼠标准样品式

大家能够通过 css 来修改鼠标准样品式

#canvas {
    display: block;
    border: 1px solid red;
    margin: 0 auto;
    cursor: crosshair;
}

(二)绘制内侧圆弧

绘制矩形

概念矩形:context.rect(x,y,w,h);

  1. x:起初地方x坐标(矩形左上角)
  2. y:初阶地方y坐标(矩形左上角)
  3. w:矩形宽
  4. h:矩形高

平昔绘制:省去了定义矩形的步调,依据定义的体制直接填充或描边

context.fillRect(x,y,w,h)
context.strokeRect(x,y,w,h)

橡皮擦功效:clearRect(x,y,w,h)

  1. 擦除矩形范围之内的内容
  2. 常用来擦除整套画布以完结动画效果

图表放大镜

大家或许基于 canvas
绘制一些图纸可能图像,假使四个因素的坐标离得相比较近,就会给成分的精选带来一些影响,举例大家画两条线,二个线的坐标是(200.5, 400) -> (200.5, 200),另多个线的坐标为
(201.5, 400) -> (201.5, 20),那么那两条线大约就会重叠在联合,如下图所示:
4858美高梅 14

运用图表放大镜的职能
4858美高梅 15

在线演示
  
源码

图片放大镜

作者们兴许依据 canvas
绘制一些图纸或然图像,若是三个成分的坐标离得相比近,就会给元素的精选带来一些震慑,比如大家画两条线,二个线的坐标是(200.5, 400) -> (200.5, 200),另3个线的坐标为
(201.5, 400) -> (201.5, 20),那么这两条线大概就会重叠在一齐,如下图所示:
4858美高梅 16

行使图表放大镜的功用
4858美高梅 17

在线演示
  
源码

this.cObj.beginPath();
this.cObj.lineWidth = 1;
this.cObj.arc(200,200,100,Math.PI*0.75,Math.PI*2.25,false); // 绘制内层圆弧
this.cObj.strokeStyle = '#0078b4';
this.cObj.stroke();
图形绘制格局

边框式绘制:

context.strokeStyle = "red";
context.lineWidth = 2;
context.rect(150,150,200,100);
context.stroke();

4858美高梅 18

填充式绘制:

context.fillStyle = 'yellow';
context.rect(150,150,200,100);
context.fill();

4858美高梅 19

原理

看似于地图中的图例,放大镜使用相比较正确的图例,如下图所示:
4858美高梅 20

在放大镜坐标连串中,原始的区域会变大,如下图所示
4858美高梅 21

原理

就像是于地图中的图例,放大镜使用较为规范的图例,如下图所示:
4858美高梅 22

在放大镜坐标种类中,原始的区域会变大,如下图所示
4858美高梅 23

(3)绘制外侧圆弧

填充+描边同时利用注意:

那多少个功用还要使用时,先后顺序的不及会导致效果的分裂

诚如是在填充后再去描边,如下效果

context.strokeStyle = "red";
context.lineWidth = 2;
context.rect(150,150,200,100);
context.fill();
context.stroke();

4858美高梅 24

若是是描边后再填写的话,填充效果会遮挡贰分一的边框

//线宽被遮挡一半
context.strokeStyle = "red";
context.lineWidth = 2;
context.rect(150,150,200,100);
context.stroke();
context.fill();

4858美高梅 25

绘制原始线段

第2创制一个线条对象

function Line(xStart, yStart, xEnd, yEnd, index, color) {
    // 起点x坐标
    this.xStart = xStart;
    // 起点y坐标
    this.yStart = yStart;
    // 终点x坐标
    this.xEnd = xEnd;
    // 终点y坐标
    this.yEnd = yEnd;
    // 用来标记是哪条线段
    this.index = index;
    // 线段颜色
    this.color = color;
}

初叶化线段

// 原始线段
var chartLines = new Array();
// 处于放大镜中的原始线段
var glassLines;
// 放大后的线段
var scaleGlassLines;
// 位于放大镜中的线段数量
var glassLineSize;

function initLines() {

    var line;
    line = new Line(200.5, 400, 200.5, 200, 0, "#888");
    chartLines.push(line);
    line = new Line(201.5, 400, 201.5, 20, 1, "#888");
    chartLines.push(line);


    glassLineSize = chartLines.length;
    glassLines = new Array(glassLineSize);
    for (var i = 0; i < glassLineSize; i++) {
        line = new Line(0, 0, 0, 0, i);
        glassLines[i] = line;
    }

    scaleGlassLines = new Array(glassLineSize);
    for (var i = 0; i < glassLineSize; i++) {
        line = new Line(0, 0, 0, 0, i);
        scaleGlassLines[i] = line;
    }
}

绘图线段

function drawLines() {
    var line;
    context.lineWidth = 1;

    for (var i = 0; i < chartLines.length; i++) {
        line = chartLines[i];
        context.beginPath();
        context.strokeStyle = line.color;
        context.moveTo(line.xStart, line.yStart);
        context.lineTo(line.xEnd, line.yEnd);
        context.stroke();
    }
}

绘制原始线段

首先创造3个线条对象

function Line(xStart, yStart, xEnd, yEnd, index, color) {
    // 起点x坐标
    this.xStart = xStart;
    // 起点y坐标
    this.yStart = yStart;
    // 终点x坐标
    this.xEnd = xEnd;
    // 终点y坐标
    this.yEnd = yEnd;
    // 用来标记是哪条线段
    this.index = index;
    // 线段颜色
    this.color = color;
}

开端化线段

// 原始线段
var chartLines = new Array();
// 处于放大镜中的原始线段
var glassLines;
// 放大后的线段
var scaleGlassLines;
// 位于放大镜中的线段数量
var glassLineSize;

function initLines() {

    var line;
    line = new Line(200.5, 400, 200.5, 200, 0, "#888");
    chartLines.push(line);
    line = new Line(201.5, 400, 201.5, 20, 1, "#888");
    chartLines.push(line);


    glassLineSize = chartLines.length;
    glassLines = new Array(glassLineSize);
    for (var i = 0; i < glassLineSize; i++) {
        line = new Line(0, 0, 0, 0, i);
        glassLines[i] = line;
    }

    scaleGlassLines = new Array(glassLineSize);
    for (var i = 0; i < glassLineSize; i++) {
        line = new Line(0, 0, 0, 0, i);
        scaleGlassLines[i] = line;
    }
}

绘图线段

function drawLines() {
    var line;
    context.lineWidth = 1;

    for (var i = 0; i < chartLines.length; i++) {
        line = chartLines[i];
        context.beginPath();
        context.strokeStyle = line.color;
        context.moveTo(line.xStart, line.yStart);
        context.lineTo(line.xEnd, line.yEnd);
        context.stroke();
    }
}
this.cObj.beginPath();
this.cObj.arc(200,200,120,Math.PI*0.75,Math.PI*2.25,false); // 绘制外侧圆弧
this.cObj.strokeStyle = '#c0c0c0';
this.cObj.lineCap = "round";
this.cObj.lineWidth = 20;
this.cObj.stroke();
绘制弧形

常用方法:context.arc(x,y,r,θ1,θ2,boolean)

  1. x:中心点x坐标
  2. y:中心点y坐标
  3. r:圆半径
  4. θ壹:起始角度
  5. θ贰:甘休角度
  6. 布尔值:false逆时针(默认),true顺时针

//画弧线
context.strokeStyle = "red";
context.lineWidth = 2;
context.arc(300,100,100,0,Math.PI/2,true)
context.stroke();

4858美高梅 26

//画圆
context.beginPath();
context.arc(300,200,100,0,Math.PI*2,true)
context.stroke();

4858美高梅 27

估测计算原始区域和放大镜区域

function calGlassRectangle(point) {
    originalRectangle.x = point.x - originalRadius;
    originalRectangle.y = point.y - originalRadius;
    originalRectangle.width = originalRadius * 2;
    originalRectangle.height = originalRadius * 2;

    scaleGlassRectangle.width = originalRectangle.width * scale;
    scaleGlassRectangle.height = originalRectangle.height * scale;
    scaleGlassRectangle.x = originalRectangle.x + originalRectangle.width / 2 - scaleGlassRectangle.width / 2;
    scaleGlassRectangle.y = originalRectangle.y + originalRectangle.height / 2 - scaleGlassRectangle.height / 2;

    // 将值装换为整数
    scaleGlassRectangle.width = parseInt(scaleGlassRectangle.width);
    scaleGlassRectangle.height = parseInt(scaleGlassRectangle.height);
    scaleGlassRectangle.x = parseInt(scaleGlassRectangle.x);
    scaleGlassRectangle.y = parseInt(scaleGlassRectangle.y);
}

计算原始区域和放大镜区域

function calGlassRectangle(point) {
    originalRectangle.x = point.x - originalRadius;
    originalRectangle.y = point.y - originalRadius;
    originalRectangle.width = originalRadius * 2;
    originalRectangle.height = originalRadius * 2;

    scaleGlassRectangle.width = originalRectangle.width * scale;
    scaleGlassRectangle.height = originalRectangle.height * scale;
    scaleGlassRectangle.x = originalRectangle.x + originalRectangle.width / 2 - scaleGlassRectangle.width / 2;
    scaleGlassRectangle.y = originalRectangle.y + originalRectangle.height / 2 - scaleGlassRectangle.height / 2;

    // 将值装换为整数
    scaleGlassRectangle.width = parseInt(scaleGlassRectangle.width);
    scaleGlassRectangle.height = parseInt(scaleGlassRectangle.height);
    scaleGlassRectangle.x = parseInt(scaleGlassRectangle.x);
    scaleGlassRectangle.y = parseInt(scaleGlassRectangle.y);
}

(4)绘制滑块

绘制文字

设置文字样式:context.font = 'italic size family'

  1. italic:斜体
  2. size:字体大小
  3. family:字体

设置文字内容:context.strokeText("text",x,y)

  1. “text”:中文字内容
  2. x:起始x坐标
  3. y:起始y坐标

context.lineWidth = 1;
context.strokeStyle = "green";
context.font = "italic 150px arial"
context.strokeText("我是文字",50,200);

4858美高梅 28

总计线段在新坐标连串的地方

由原理图大家知晓,放大镜中运用坐标系的图例要比原来坐标系特别标准,比如原本坐标系使用
1:100,那么放大镜坐标系使用
1:10,因而大家必要重新计算线段在放大镜坐标系中的地方。同时为了省事,大家将线段的原始坐标举行了倒车,减去原始区域起始的x值和y值,就要原始区域左上角的点作为为(0,0)

function calScaleLines() {
    var xStart = originalRectangle.x;
    var xEnd = originalRectangle.x + originalRectangle.width;
    var yStart = originalRectangle.y;
    var yEnd = originalRectangle.y + originalRectangle.height;
    var line, gLine, sgLine;
    var glassLineIndex = 0;
    for (var i = 0; i < chartLines.length; i++) {
        line = chartLines[i];

        // 判断线段是否在放大镜中
        if (line.xStart < xStart || line.xEnd > xEnd) {
            continue;
        }
        if (line.yEnd > yEnd || line.yStart < yStart) {
            continue;
        }

        gLine = glassLines[glassLineIndex];
        sgLine = scaleGlassLines[glassLineIndex];
        if (line.yEnd > yEnd) {
            gLine.yEnd = yEnd;
        }
        if (line.yStart < yStart) {
            gLine.yStart = yStart;
        }

        gLine.xStart = line.xStart - xStart;
        gLine.yStart = line.yStart - yStart;
        gLine.xEnd = line.xEnd - xStart;
        gLine.yEnd = line.yEnd - yStart;

        sgLine.xStart = parseInt(gLine.xStart * scale);
        sgLine.yStart = parseInt(gLine.yStart * scale);
        sgLine.xEnd = parseInt(gLine.xEnd * scale);
        sgLine.yEnd = parseInt(gLine.yEnd * scale);
        sgLine.color = line.color;
        glassLineIndex++;
    }
    glassLineSize = glassLineIndex;
}

测算线段在新坐标系列的职分

由原理图我们知晓,放大镜中动用坐标系的图例要比原来坐标系特别正确,例如原本坐标系使用
1:100,那么放大镜坐标系使用
1:10,因而大家须要再度计算线段在放大镜坐标系中的地方。同时为了省事,大家将线段的原来坐标实行了倒车,减去原始区域开端的x值和y值,就要原始区域左上角的点作为为(0,0)

function calScaleLines() {
    var xStart = originalRectangle.x;
    var xEnd = originalRectangle.x + originalRectangle.width;
    var yStart = originalRectangle.y;
    var yEnd = originalRectangle.y + originalRectangle.height;
    var line, gLine, sgLine;
    var glassLineIndex = 0;
    for (var i = 0; i < chartLines.length; i++) {
        line = chartLines[i];

        // 判断线段是否在放大镜中
        if (line.xStart < xStart || line.xEnd > xEnd) {
            continue;
        }
        if (line.yEnd > yEnd || line.yStart < yStart) {
            continue;
        }

        gLine = glassLines[glassLineIndex];
        sgLine = scaleGlassLines[glassLineIndex];
        if (line.yEnd > yEnd) {
            gLine.yEnd = yEnd;
        }
        if (line.yStart < yStart) {
            gLine.yStart = yStart;
        }

        gLine.xStart = line.xStart - xStart;
        gLine.yStart = line.yStart - yStart;
        gLine.xEnd = line.xEnd - xStart;
        gLine.yEnd = line.yEnd - yStart;

        sgLine.xStart = parseInt(gLine.xStart * scale);
        sgLine.yStart = parseInt(gLine.yStart * scale);
        sgLine.xEnd = parseInt(gLine.xEnd * scale);
        sgLine.yEnd = parseInt(gLine.yEnd * scale);
        sgLine.color = line.color;
        glassLineIndex++;
    }
    glassLineSize = glassLineIndex;
}

由于滑块是足以活动的此处滑块的地点运用了坐标参数xy,及滑块半径r作为可变参数

潜移默化样式

线性渐变:createLinearGradient(x一,y一,x二,y二)

  1. x1/y一:渐变发轫地点坐标
  2. x2/y二:渐变利落地点坐标

向阳渐变:createRadiusGradient(x壹,y一,r一,x二,y2,r2)

  1. x1/y1:渐变起先圆的圆心地点坐标
  2. r一:渐变起首圆半径
  3. x2/y二:渐变利落圆的圆心地点坐标
  4. r2:渐变利落圆半径

潜移默化颜色设置:addColorStop(%,”color”);

  1. %:渐变进程,用[0,1]里头的数字代表
  2. “color”:各样渐变阶段的水彩

var linearGradient = context.createLinearGradient(100,300,800,500);

linearGradient.addColorStop(0,"red");
linearGradient.addColorStop(0.4,"yellow");
linearGradient.addColorStop(0.8,"green");
linearGradient.addColorStop(1,"blue");

context.fillStyle = linearGradient;

context.font = "italic 150px arial"
context.fillText("我是文字",50,200);

4858美高梅 29

绘图放大镜中央点

绘制放大镜核心的瞄准器

function drawAnchor() {
    context.beginPath();
    context.lineWidth = 2;
    context.fillStyle = "#fff";
    context.strokeStyle = "#000";
    context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), 10, 0, Math.PI * 2, false);

    var radius = 15;
    context.moveTo(parseInt(centerPoint.x - radius), parseInt(centerPoint.y));
    context.lineTo(parseInt(centerPoint.x + radius), parseInt(centerPoint.y));
    context.moveTo(parseInt(centerPoint.x), parseInt(centerPoint.y - radius));
    context.lineTo(parseInt(centerPoint.x), parseInt(centerPoint.y + radius));
    //context.fill();
    context.stroke();
}

绘图放大镜宗旨点

制图放大镜中央的瞄准器

function drawAnchor() {
    context.beginPath();
    context.lineWidth = 2;
    context.fillStyle = "#fff";
    context.strokeStyle = "#000";
    context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), 10, 0, Math.PI * 2, false);

    var radius = 15;
    context.moveTo(parseInt(centerPoint.x - radius), parseInt(centerPoint.y));
    context.lineTo(parseInt(centerPoint.x + radius), parseInt(centerPoint.y));
    context.moveTo(parseInt(centerPoint.x), parseInt(centerPoint.y - radius));
    context.lineTo(parseInt(centerPoint.x), parseInt(centerPoint.y + radius));
    //context.fill();
    context.stroke();
}
this.cObj.beginPath();
this.cObj.moveTo(200,200);
this.cObj.arc(x,y,r,0,Math.PI*2,false); // 绘制滑块
this.cObj.fillStyle='#f15a4a';
this.cObj.fill();

this.cObj.beginPath();
this.cObj.moveTo(200,200);
this.cObj.arc(x,y,11,0,Math.PI*2,false); // 绘制滑块内侧白色区域
this.cObj.fillStyle='#ffffff';
this.cObj.fill();
绘制阴影

影子颜色:shadowColor = “color”;
黑影模糊度:shadowblur = number;
阴影偏移X:shadowOffsetX = number;
影子偏移Y:shadowOffsetY = number;

context.shadowColor = "black";
context.shadowBlur = 20;
context.shadowOffsetX = 10;
context.shadowOffsetY = 5;

context.strokeRect(100,100,100,100);

4858美高梅 30

绘制放大镜

function drawMagnifyingGlass() {

    calScaleLines();

    context.save();
    context.beginPath();
    context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
    context.clip();

    context.beginPath();
    context.fillStyle = "#fff";
    context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
    context.fill();

    context.lineWidth = 4;
    for (var i = 0; i < glassLineSize; i++) {
        context.beginPath();
        context.strokeStyle = scaleGlassLines[i].color;
        context.moveTo(scaleGlassRectangle.x + scaleGlassLines[i].xStart, scaleGlassRectangle.y + scaleGlassLines[i].yStart);
        context.lineTo(scaleGlassRectangle.x + scaleGlassLines[i].xEnd, scaleGlassRectangle.y + scaleGlassLines[i].yEnd);
        context.stroke();
    }
    context.restore();

    context.beginPath();
    var gradient = context.createRadialGradient(
        parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius - 5,
        parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius);

    gradient.addColorStop(0.50, 'silver');
    gradient.addColorStop(0.90, 'silver');
    gradient.addColorStop(1, 'black');
    context.strokeStyle = gradient;
    context.lineWidth = 5;
    context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius, 0, Math.PI * 2, false);
    context.stroke();

    drawAnchor();
}

制图放大镜

function drawMagnifyingGlass() {

    calScaleLines();

    context.save();
    context.beginPath();
    context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
    context.clip();

    context.beginPath();
    context.fillStyle = "#fff";
    context.arc(centerPoint.x, centerPoint.y, originalRadius, 0, Math.PI * 2, false);
    context.fill();

    context.lineWidth = 4;
    for (var i = 0; i < glassLineSize; i++) {
        context.beginPath();
        context.strokeStyle = scaleGlassLines[i].color;
        context.moveTo(scaleGlassRectangle.x + scaleGlassLines[i].xStart, scaleGlassRectangle.y + scaleGlassLines[i].yStart);
        context.lineTo(scaleGlassRectangle.x + scaleGlassLines[i].xEnd, scaleGlassRectangle.y + scaleGlassLines[i].yEnd);
        context.stroke();
    }
    context.restore();

    context.beginPath();
    var gradient = context.createRadialGradient(
        parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius - 5,
        parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius);

    gradient.addColorStop(0.50, 'silver');
    gradient.addColorStop(0.90, 'silver');
    gradient.addColorStop(1, 'black');
    context.strokeStyle = gradient;
    context.lineWidth = 5;
    context.arc(parseInt(centerPoint.x), parseInt(centerPoint.y), originalRadius, 0, Math.PI * 2, false);
    context.stroke();

    drawAnchor();
}

4858美高梅,(伍)绘制长度可变弧(灰色部分):

坐标转变

加多事件

拉长风云

是因为长度可变,那里把闭合弧度作为可变参数

连锁例子能够看本人的另一篇博客canvas石英表效果

鼠标拖动

鼠标移动到放大镜上,然后按下鼠标左键,能够拖动放大镜,不按鼠标左键或然不在放大镜区域都不得以拖动放大镜。
为了贯彻地点的成效,大家要贯彻三种事件 mousedown, mousemove,
‘mouseup’,
当鼠标按下时,检验是不是在放大镜区域,假设在,设置放大镜能够移动。鼠标移动时更新放大镜One plus点的坐标。鼠标放开时,设置放大镜不得以被活动。

canvas.onmousedown = function (e) {
    var point = windowToCanvas(e.clientX, e.clientY);
    var x1, x2, y1, y2, dis;

    x1 = point.x;
    y1 = point.y;
    x2 = centerPoint.x;
    y2 = centerPoint.y;
    dis = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);
    if (dis < Math.pow(originalRadius, 2)) {
        lastPoint.x = point.x;
        lastPoint.y = point.y;
        moveGlass = true;
    }
}

canvas.onmousemove = function (e) {
    if (moveGlass) {
        var xDis, yDis;
        var point = windowToCanvas(e.clientX, e.clientY);
        xDis = point.x - lastPoint.x;
        yDis = point.y - lastPoint.y;
        centerPoint.x += xDis;
        centerPoint.y += yDis;
        lastPoint.x = point.x;
        lastPoint.y = point.y;
        draw();
    }
}

canvas.onmouseup = function (e) {
    moveGlass = false;
}

鼠标拖动

鼠标移动到放大镜上,然后按下鼠标左键,能够拖动放大镜,不按鼠标左键或然不在放大镜区域都不可以拖动放大镜。
为了促成地点的功力,大家要落成3种事件 mousedown, mousemove,
‘mouseup’,
当鼠标按下时,检查测试是或不是在放大镜区域,假使在,设置放大镜能够活动。鼠标移动时更新放大镜华为点的坐标。鼠标松手时,设置放大镜不得以被移位。

canvas.onmousedown = function (e) {
    var point = windowToCanvas(e.clientX, e.clientY);
    var x1, x2, y1, y2, dis;

    x1 = point.x;
    y1 = point.y;
    x2 = centerPoint.x;
    y2 = centerPoint.y;
    dis = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);
    if (dis < Math.pow(originalRadius, 2)) {
        lastPoint.x = point.x;
        lastPoint.y = point.y;
        moveGlass = true;
    }
}

canvas.onmousemove = function (e) {
    if (moveGlass) {
        var xDis, yDis;
        var point = windowToCanvas(e.clientX, e.clientY);
        xDis = point.x - lastPoint.x;
        yDis = point.y - lastPoint.y;
        centerPoint.x += xDis;
        centerPoint.y += yDis;
        lastPoint.x = point.x;
        lastPoint.y = point.y;
        draw();
    }
}

canvas.onmouseup = function (e) {
    moveGlass = false;
}
this.cObj.beginPath();
this.cObj.arc(200,200,120,Math.PI*0.75,this.j,false); // 可变圆弧
this.cObj.strokeStyle = '#f15a4a';
this.cObj.lineCap = "round";
this.cObj.lineWidth = 20;
this.cObj.stroke();
坐标系平移:translate(x,y)
  1. 便是将坐标系的00点调换来(x,y)地方

鼠标双击

当移动到相应的线条上时,鼠标双击能够选用该线段,将该线段的颜料变为灰湖绿。

canvas.ondblclick = function (e) {
    var xStart, xEnd, yStart, yEnd;
    var clickPoint = {};
    clickPoint.x = scaleGlassRectangle.x + scaleGlassRectangle.width / 2;
    clickPoint.y = scaleGlassRectangle.y + scaleGlassRectangle.height / 2;
    var index = -1;

    for (var i = 0; i < scaleGlassLines.length; i++) {
        var scaleLine = scaleGlassLines[i];

        xStart = scaleGlassRectangle.x + scaleLine.xStart - 3;
        xEnd = scaleGlassRectangle.x + scaleLine.xStart + 3;
        yStart = scaleGlassRectangle.y + scaleLine.yStart;
        yEnd = scaleGlassRectangle.y + scaleLine.yEnd;

        if (clickPoint.x > xStart && clickPoint.x < xEnd && clickPoint.y < yStart && clickPoint.y > yEnd) {
            scaleLine.color = "#f00";
            index = scaleLine.index;
            break;
        }
    }

    for (var i = 0; i < chartLines.length; i++) {
        var line = chartLines[i];
        if (line.index == index) {
            line.color = "#f00";
        } else {
            line.color = "#888";
        }
    }

    draw();
}

鼠标双击

当移动到相应的线条上时,鼠标双击能够选择该线段,将该线段的水彩变为蓝灰。

canvas.ondblclick = function (e) {
    var xStart, xEnd, yStart, yEnd;
    var clickPoint = {};
    clickPoint.x = scaleGlassRectangle.x + scaleGlassRectangle.width / 2;
    clickPoint.y = scaleGlassRectangle.y + scaleGlassRectangle.height / 2;
    var index = -1;

    for (var i = 0; i < scaleGlassLines.length; i++) {
        var scaleLine = scaleGlassLines[i];

        xStart = scaleGlassRectangle.x + scaleLine.xStart - 3;
        xEnd = scaleGlassRectangle.x + scaleLine.xStart + 3;
        yStart = scaleGlassRectangle.y + scaleLine.yStart;
        yEnd = scaleGlassRectangle.y + scaleLine.yEnd;

        if (clickPoint.x > xStart && clickPoint.x < xEnd && clickPoint.y < yStart && clickPoint.y > yEnd) {
            scaleLine.color = "#f00";
            index = scaleLine.index;
            break;
        }
    }

    for (var i = 0; i < chartLines.length; i++) {
        var line = chartLines[i];
        if (line.index == index) {
            line.color = "#f00";
        } else {
            line.color = "#888";
        }
    }

    draw();
}

迄今截止绘图方法成功,调用drow方法并传到参数滑块坐标、半径和拖动弧度(x,y,r,j)就能够成功图片的绘图。

坐标系旋转:rotate(θ)
  1. 将坐标系旋转θ度
  2. θ > 0时顺时针旋转,θ < 0时逆时针转动

键盘事件

因为线段离得比较近,所以使用鼠标移动很难准确的当选线段,那里运用键盘的w,
a, s, d 来张开标准移动

document.onkeyup = function (e) {
    if (e.key == 'w') {
        centerPoint.y = intAdd(centerPoint.y, -0.2);
    }
    if (e.key == 'a') {
        centerPoint.x = intAdd(centerPoint.x, -0.2);
    }
    if (e.key == 's') {
        centerPoint.y = intAdd(centerPoint.y, 0.2);
    }
    if (e.key == 'd') {
        centerPoint.x = intAdd(centerPoint.x, 0.2);
    }
    draw();
}

** 参考资料 **
HTML5-MagnifyingGlass

键盘事件

因为线段离得比较近,所以利用鼠标移动很难正确的当选线段,那里运用键盘的w,
a, s, d 来开始展览精确移动

document.onkeyup = function (e) {
    if (e.key == 'w') {
        centerPoint.y = intAdd(centerPoint.y, -0.2);
    }
    if (e.key == 'a') {
        centerPoint.x = intAdd(centerPoint.x, -0.2);
    }
    if (e.key == 's') {
        centerPoint.y = intAdd(centerPoint.y, 0.2);
    }
    if (e.key == 'd') {
        centerPoint.x = intAdd(centerPoint.x, 0.2);
    }
    draw();
}

** 参考资料 **
HTML5-MagnifyingGlass

4、绘图方法分析

坐标系缩放:scale(x,y)
  1. 将坐标系x方向放大x倍
  2. 将坐标系y方向放大y倍

在意:因为坐标系在通过转换之后,之后重新绘制的图纸都会以这些新的坐标系为参照;所以在绘制的时候会丰盛的难为

缓慢解决方案如下:

save():保存当前坐标系

restore():读取保存的坐标系

  1. 历次在进展坐标系转换在此之前,先利用save()将原始坐标系保存下来
  2. 在进展更动之后,再使用restore()将坐标系苏醒为初阶坐标系
  3. 每个restore()对应相应的三个save(),所以在大局中保留3遍随后Infinitirestore()的做法是不行的

(1)那里首先创制以canvas左上角为原点显示屏坐标系,前面包车型大巴绘图都将依靠该坐标系,坐标图像如下:

制图贝塞尔曲线/三回曲线

4858美高梅 31

连带例子能够看自个儿另一篇博客canvas随拖动变化的贝塞尔曲线

编写制定获取当前光标地点点相对canvas坐标系(lx,ly)的方式:即当前坐标点减去canvas偏移距离

先用moveTo(x,y)设置初始点坐标
getx:function(ev){ //获取鼠标在canvas内坐标x
 return ev.clientX-this.obj.getBoundingClientRect().left;
 },
 gety:function(ev){ //获取鼠标在canvas内坐标y
 return ev.clientY-this.obj.getBoundingClientRect().top;
 }
贝塞尔曲线:bezierCurveTo(cpx一,cpy一,cpx贰,cpy2,dx,dy)
  1. cpx1/xpy1:控制点1坐标
  2. cpx2/xpy2:控制点2坐标
  3. dx/dy:终点坐标

(二)为便利构建圆的方程,那里建立1个以canvas中央为原点的坐标系,如下图,在实质上接纳draw方法绘图时行使的是海水绿的坐标系,在动用圆的不二等秘书诀管理是大家选拔莲红的坐标系

1回曲线quadraticCurveTo(cpx,cpy,dx,dy)
  1. cpx/xpy:调整点坐标
  2. dx/dy:终点坐标

context.beginPath();
context.moveTo(300,100);
//贝塞尔曲线
context.bezierCurveTo(200,100,300,300,200,300);
context.stroke()

//二次曲线
context.moveTo(300,300);
context.quadraticCurveTo(400,150,500,300);
context.stroke();

4858美高梅 32

4858美高梅 33

上面加多坐标转化方法,

荧屏坐标(高粱红坐标)->宗旨坐标(土褐坐标)

spotchange:function(a){ //屏幕坐标转化为中心坐标 
 var target={};
 if(a.x<200 && a.y<200){      //二象限
 target.x=-(200-a.x); 
 target.y=200-a.y; 
 }else if(a.x>200 && a.y<200){  //一象限 
 target.x=a.x-200; 
 target.y=200-a.y; 
 }else if(a.x>200 && a.y>200){  //四象限
 target.x=a.x-200;
 target.y=-(a.y-200) 
 }else if(a.x<200 && a.y>200){  //三象限
 target.x=-(200-a.x); 
 target.y=-(a.y-200); 
 } 
 return target; 
},

中央坐标(中绿坐标)->荧屏坐标(灰白坐标)

respotchange:function(a){ //中心坐标转化为屏幕坐标
 var target={};
 if(a.x>0 && a.y>0){
 target.x=200+a.x;
 target.y=(200-a.y);
 }else if(a.x<0 && a.y>0){
 target.x=200+a.x;
 target.y=200-a.y;
 }else if(a.x<0 && a.y<0){
 target.x=200+a.x;
 target.y=-(a.y-200)
 }else if(a.x>0 && a.y<0){
 target.x=200+a.x;
 target.y=-(a.y-200);
 }
 return target;
 },

(3)滑块路线及职分计算方式

4858美高梅 34

 **先是不考虑xy正负,**

  **计量光标地点点的正切值**

  tanφ = ly/lx;

  可知φ

  φ=arctan(tanφ)

  据他们说圆的参数方程,可获取光标点对应淡黄路线地方坐标为

  x=rcosφ

  y=rsinφ

(4)**据说地点思路编写获取坐标地点方法,那里增添了xy和弧度值正负管理方法和可拖动弧度范围**

getmoveto:function(lx,ly){
 if(!this.p.isDown){ //是否可移动
 return false;
 }
 var tem={}; //存放目标坐标位置
 tem.o=Math.atan(ly/lx); //鼠标移动点圆形角
 tem.x=this.pathr*Math.cos(tem.o);
 tem.y=this.pathr*Math.sin(tem.o);
 if(lx<0){ //坐标点处理(正负)
 tem.x=-tem.x;
 tem.y=-tem.y;
 }
 if(lx>0){ //弧度值处理
 tem.z=-Math.atan(tem.y/tem.x)+Math.PI*2;
 }else{
 tem.z=-Math.atan(tem.y/tem.x)+Math.PI;
 }
 if(tem.z>7.06){ //最大值
 tem.z=7.06;
 tem.x=this.pathr*Math.cos(Math.PI*2.25);
 tem.y=-this.pathr*Math.sin(Math.PI*2.25);
 }
 if(tem.z<2.4){ //最小值
 tem.z=2.4;
 tem.x=this.pathr*Math.cos(Math.PI*0.75);
 tem.y=-this.pathr*Math.sin(Math.PI*0.75);
 }
 return tem;
 },

(伍)以上办法在canvas内任意点均可看做滑块拖动的目的点,那里编写cheack方法,将限量可拖动地点限制在3个光景的环形里

check:function(x,y){ //限制可拖动范围
 var xx=x*x;
 var yy=y*y;
 var rr=114*114; //最小
 var rrr=126*126; //最大
 if(xx+yy>rr && xx+yy<rrr){
 return true;
 }
 return false;
 },

伍、事件措施编写

(1)鼠标按下进行方法OnMouseDown

此处运用了getx和gety获取光标相对canvas坐标,并认清鼠标是或不是移动到了滑块上方地方内,(this.p是时下绘制对象,p.x即滑块横坐标,p.x即当前纵坐标,p.r即滑块最大半径),假设光标在滑块上方则设置isDown为TRUE,反正照旧,前边大家会经过isDown来推断是不是进行活动滑块的格局:

OnMouseDown:function(evt){
 var X=this.getx(evt); //获取当前鼠标位置横坐标
 var Y=this.gety(evt); //获取当前鼠标位置纵坐标
 var minX=this.p.x-this.p.r; 
 var maxX=this.p.x+this.p.r;
 var minY=this.p.y-this.p.r;
 var maxY=this.p.y+this.p.r;
 if(minX<X && X<maxX && minY<Y && Y<maxY){ //判断鼠标是否在滑块上 
  this.p.isDown=true; 
 }else{
  this.p.isDown=false;
 }
}

(贰)鼠标按下后移动时滑块的点子:

OnMouseMove:function(evt){ //
 if(this.p.isDown){ //是否在滑块上按下鼠标
  var a={};  //存放当前鼠标坐标
  a.x=this.getx(evt); //坐标转化
  a.y=this.gety(evt);
  var b=this.spotchange(a); //坐标转化
  var co=this.getmoveto(b.x,b.y); //获取要移动到的坐标点
  if(this.check(b.x,b.y)){ //判断移动目标点是否在可拖动范围
  var co=this.getmoveto(b.x,b.y); //获取到移动的目标位置坐标()
  var tar=this.respotchange(co); //坐标转化
  var o=co.z;
  this.p.draw(tar.x,tar.y,this.p.r,o); //绘图
  }
 }
 },

(3)鼠标释放方法

OnMouseUp:function(){ //鼠标释放
 this.p.isDown=false
}, 

(四)最后将有所办法和事件绑定

event:function(){ //事件绑定
 this.obj.addEventListener("mousedown",this.OnMouseDown.bind(this),false);
 this.obj.addEventListener("mousemove",this.OnMouseMove.bind(this),false);
 this.obj.addEventListener("mouseup",this.OnMouseUp.bind(this),false);
 },

迄今截至可拖动滑块基本办法编写成功

如上便是本文的全体内容,希望本文的始末对大家的学习或许职业能推动一定的鼎力相助,同时也期待多多援助脚本之家!

你可能感兴趣的篇章:

  • canvas实现环形进程条效果
  • canvas达成简易的圆环进度条效果
  • canvas绘制环形进度条
  • Android使用Canvas绘制圆形进程条效果

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有