Created
January 21, 2016 09:43
-
-
Save targetkiller/50f2776a61e53f3b57fb to your computer and use it in GitHub Desktop.
一个小球页面
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>拖拽小点点</title> | |
<style type="text/css"> | |
body{ | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
overflow: hidden; | |
} | |
#canvas{ | |
z-index: 1; | |
position: absolute; | |
} | |
#showHelp{ | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 70px; | |
height: 30px; | |
line-height: 30px; | |
text-align: center; | |
background-color: rgba(10,10,10,0.5); | |
color: #fff; | |
font-size: 12px; | |
text-decoration: none; | |
z-index: 2; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas id="canvas"></canvas> | |
<a href="javascript:;" id="showHelp">辅助线</a> | |
<script type="text/javascript"> | |
// Tween.js | |
(function () { | |
if ('performance' in window === false) { | |
window.performance = {}; | |
} | |
// IE 8 | |
Date.now = (Date.now || function () { | |
return new Date().getTime(); | |
}); | |
if ('now' in window.performance === false) { | |
var offset = window.performance.timing && window.performance.timing.navigationStart ? window.performance.timing.navigationStart: Date.now(); | |
window.performance.now = function () { | |
return Date.now() - offset; | |
}; | |
} | |
})(); | |
var TWEEN = TWEEN || (function () { | |
var _tweens = []; | |
return { | |
getAll: function () { | |
return _tweens; | |
}, | |
removeAll: function () { | |
_tweens = []; | |
}, | |
add: function (tween) { | |
_tweens.push(tween); | |
}, | |
remove: function (tween) { | |
var i = _tweens.indexOf(tween); | |
if (i !== -1) { | |
_tweens.splice(i, 1); | |
} | |
}, | |
update: function (time) { | |
if (_tweens.length === 0) { | |
return false; | |
} | |
var i = 0; | |
time = time !== undefined ? time : window.performance.now(); | |
while (i < _tweens.length) { | |
if (_tweens[i].update(time)) { | |
i++; | |
} else { | |
_tweens.splice(i, 1); | |
} | |
} | |
return true; | |
} | |
}; | |
})(); | |
TWEEN.Tween = function (object) { | |
var _object = object; | |
var _valuesStart = {}; | |
var _valuesEnd = {}; | |
var _valuesStartRepeat = {}; | |
var _duration = 1000; | |
var _repeat = 0; | |
var _yoyo = false; | |
var _isPlaying = false; | |
var _reversed = false; | |
var _delayTime = 0; | |
var _startTime = null; | |
var _easingFunction = TWEEN.Easing.Linear.None; | |
var _interpolationFunction = TWEEN.Interpolation.Linear; | |
var _chainedTweens = []; | |
var _onStartCallback = null; | |
var _onStartCallbackFired = false; | |
var _onUpdateCallback = null; | |
var _onCompleteCallback = null; | |
var _onStopCallback = null; | |
// Set all starting values present on the target object | |
for (var field in object) { | |
_valuesStart[field] = parseFloat(object[field], 10); | |
} | |
this.to = function (properties, duration) { | |
if (duration !== undefined) { | |
_duration = duration; | |
} | |
_valuesEnd = properties; | |
return this; | |
}; | |
this.start = function (time) { | |
TWEEN.add(this); | |
_isPlaying = true; | |
_onStartCallbackFired = false; | |
_startTime = time !== undefined ? time : window.performance.now(); | |
_startTime += _delayTime; | |
for (var property in _valuesEnd) { | |
// Check if an Array was provided as property value | |
if (_valuesEnd[property] instanceof Array) { | |
if (_valuesEnd[property].length === 0) { | |
continue; | |
} | |
// Create a local copy of the Array with the start value at the front | |
_valuesEnd[property] = [_object[property]].concat(_valuesEnd[property]); | |
} | |
// If `to()` specifies a property that doesn't exist in the source object, | |
// we should not set that property in the object | |
if (_valuesStart[property] === undefined) { | |
continue; | |
} | |
_valuesStart[property] = _object[property]; | |
if ((_valuesStart[property] instanceof Array) === false) { | |
_valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings | |
} | |
_valuesStartRepeat[property] = _valuesStart[property] || 0; | |
} | |
return this; | |
}; | |
this.stop = function () { | |
if (!_isPlaying) { | |
return this; | |
} | |
TWEEN.remove(this); | |
_isPlaying = false; | |
if (_onStopCallback !== null) { | |
_onStopCallback.call(_object); | |
} | |
this.stopChainedTweens(); | |
return this; | |
}; | |
this.stopChainedTweens = function () { | |
for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) { | |
_chainedTweens[i].stop(); | |
} | |
}; | |
this.delay = function (amount) { | |
_delayTime = amount; | |
return this; | |
}; | |
this.repeat = function (times) { | |
_repeat = times; | |
return this; | |
}; | |
this.yoyo = function (yoyo) { | |
_yoyo = yoyo; | |
return this; | |
}; | |
this.easing = function (easing) { | |
_easingFunction = easing; | |
return this; | |
}; | |
this.interpolation = function (interpolation) { | |
_interpolationFunction = interpolation; | |
return this; | |
}; | |
this.chain = function () { | |
_chainedTweens = arguments; | |
return this; | |
}; | |
this.onStart = function (callback) { | |
_onStartCallback = callback; | |
return this; | |
}; | |
this.onUpdate = function (callback) { | |
_onUpdateCallback = callback; | |
return this; | |
}; | |
this.onComplete = function (callback) { | |
_onCompleteCallback = callback; | |
return this; | |
}; | |
this.onStop = function (callback) { | |
_onStopCallback = callback; | |
return this; | |
}; | |
this.update = function (time) { | |
var property; | |
var elapsed; | |
var value; | |
if (time < _startTime) { | |
return true; | |
} | |
if (_onStartCallbackFired === false) { | |
if (_onStartCallback !== null) { | |
_onStartCallback.call(_object); | |
} | |
_onStartCallbackFired = true; | |
} | |
elapsed = (time - _startTime) / _duration; | |
elapsed = elapsed > 1 ? 1 : elapsed; | |
value = _easingFunction(elapsed); | |
for (property in _valuesEnd) { | |
// Don't update properties that do not exist in the source object | |
if (_valuesStart[property] === undefined) { | |
continue; | |
} | |
var start = _valuesStart[property] || 0; | |
var end = _valuesEnd[property]; | |
if (end instanceof Array) { | |
_object[property] = _interpolationFunction(end, value); | |
} else { | |
// Parses relative end values with start as base (e.g.: +10, -3) | |
if (typeof (end) === 'string') { | |
if (end.startsWith('+') || end.startsWith('-')) { | |
end = start + parseFloat(end, 10); | |
} else { | |
end = parseFloat(end, 10); | |
} | |
} | |
// Protect against non numeric properties. | |
if (typeof (end) === 'number') { | |
_object[property] = start + (end - start) * value; | |
} | |
} | |
} | |
if (_onUpdateCallback !== null) { | |
_onUpdateCallback.call(_object, value); | |
} | |
if (elapsed === 1) { | |
if (_repeat > 0) { | |
if (isFinite(_repeat)) { | |
_repeat--; | |
} | |
// Reassign starting values, restart by making startTime = now | |
for (property in _valuesStartRepeat) { | |
if (typeof (_valuesEnd[property]) === 'string') { | |
_valuesStartRepeat[property] = _valuesStartRepeat[property] + parseFloat(_valuesEnd[property], 10); | |
} | |
if (_yoyo) { | |
var tmp = _valuesStartRepeat[property]; | |
_valuesStartRepeat[property] = _valuesEnd[property]; | |
_valuesEnd[property] = tmp; | |
} | |
_valuesStart[property] = _valuesStartRepeat[property]; | |
} | |
if (_yoyo) { | |
_reversed = !_reversed; | |
} | |
_startTime = time + _delayTime; | |
return true; | |
} else { | |
if (_onCompleteCallback !== null) { | |
_onCompleteCallback.call(_object); | |
} | |
for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) { | |
// Make the chained tweens start exactly at the time they should, | |
// even if the `update()` method was called way past the duration of the tween | |
_chainedTweens[i].start(_startTime + _duration); | |
} | |
return false; | |
} | |
} | |
return true; | |
}; | |
}; | |
TWEEN.Easing = { | |
Linear: { | |
None: function (k) { | |
return k; | |
} | |
}, | |
Quadratic: { | |
In: function (k) { | |
return k * k; | |
}, | |
Out: function (k) { | |
return k * (2 - k); | |
}, | |
InOut: function (k) { | |
if ((k *= 2) < 1) { | |
return 0.5 * k * k; | |
} | |
return - 0.5 * (--k * (k - 2) - 1); | |
} | |
}, | |
Cubic: { | |
In: function (k) { | |
return k * k * k; | |
}, | |
Out: function (k) { | |
return --k * k * k + 1; | |
}, | |
InOut: function (k) { | |
if ((k *= 2) < 1) { | |
return 0.5 * k * k * k; | |
} | |
return 0.5 * ((k -= 2) * k * k + 2); | |
} | |
}, | |
Quartic: { | |
In: function (k) { | |
return k * k * k * k; | |
}, | |
Out: function (k) { | |
return 1 - (--k * k * k * k); | |
}, | |
InOut: function (k) { | |
if ((k *= 2) < 1) { | |
return 0.5 * k * k * k * k; | |
} | |
return - 0.5 * ((k -= 2) * k * k * k - 2); | |
} | |
}, | |
Quintic: { | |
In: function (k) { | |
return k * k * k * k * k; | |
}, | |
Out: function (k) { | |
return --k * k * k * k * k + 1; | |
}, | |
InOut: function (k) { | |
if ((k *= 2) < 1) { | |
return 0.5 * k * k * k * k * k; | |
} | |
return 0.5 * ((k -= 2) * k * k * k * k + 2); | |
} | |
}, | |
Sinusoidal: { | |
In: function (k) { | |
return 1 - Math.cos(k * Math.PI / 2); | |
}, | |
Out: function (k) { | |
return Math.sin(k * Math.PI / 2); | |
}, | |
InOut: function (k) { | |
return 0.5 * (1 - Math.cos(Math.PI * k)); | |
} | |
}, | |
Exponential: { | |
In: function (k) { | |
return k === 0 ? 0 : Math.pow(1024, k - 1); | |
}, | |
Out: function (k) { | |
return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k); | |
}, | |
InOut: function (k) { | |
if (k === 0) { | |
return 0; | |
} | |
if (k === 1) { | |
return 1; | |
} | |
if ((k *= 2) < 1) { | |
return 0.5 * Math.pow(1024, k - 1); | |
} | |
return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2); | |
} | |
}, | |
Circular: { | |
In: function (k) { | |
return 1 - Math.sqrt(1 - k * k); | |
}, | |
Out: function (k) { | |
return Math.sqrt(1 - (--k * k)); | |
}, | |
InOut: function (k) { | |
if ((k *= 2) < 1) { | |
return - 0.5 * (Math.sqrt(1 - k * k) - 1); | |
} | |
return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); | |
} | |
}, | |
Elastic: { | |
In: function (k) { | |
var s; | |
var a = 0.1; | |
var p = 0.4; | |
if (k === 0) { | |
return 0; | |
} | |
if (k === 1) { | |
return 1; | |
} | |
if (!a || a < 1) { | |
a = 1; | |
s = p / 4; | |
} else { | |
s = p * Math.asin(1 / a) / (2 * Math.PI); | |
} | |
return - (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); | |
}, | |
Out: function (k) { | |
var s; | |
var a = 0.1; | |
var p = 0.4; | |
if (k === 0) { | |
return 0; | |
} | |
if (k === 1) { | |
return 1; | |
} | |
if (!a || a < 1) { | |
a = 1; | |
s = p / 4; | |
} else { | |
s = p * Math.asin(1 / a) / (2 * Math.PI); | |
} | |
return (a * Math.pow(2, - 10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1); | |
}, | |
InOut: function (k) { | |
var s; | |
var a = 0.1; | |
var p = 0.4; | |
if (k === 0) { | |
return 0; | |
} | |
if (k === 1) { | |
return 1; | |
} | |
if (!a || a < 1) { | |
a = 1; | |
s = p / 4; | |
} else { | |
s = p * Math.asin(1 / a) / (2 * Math.PI); | |
} | |
if ((k *= 2) < 1) { | |
return - 0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); | |
} | |
return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; | |
} | |
}, | |
Back: { | |
In: function (k) { | |
var s = 1.70158; | |
return k * k * ((s + 1) * k - s); | |
}, | |
Out: function (k) { | |
var s = 1.70158; | |
return --k * k * ((s + 1) * k + s) + 1; | |
}, | |
InOut: function (k) { | |
var s = 1.70158 * 1.525; | |
if ((k *= 2) < 1) { | |
return 0.5 * (k * k * ((s + 1) * k - s)); | |
} | |
return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); | |
} | |
}, | |
Bounce: { | |
In: function (k) { | |
return 1 - TWEEN.Easing.Bounce.Out(1 - k); | |
}, | |
Out: function (k) { | |
if (k < (1 / 2.75)) { | |
return 7.5625 * k * k; | |
} else if (k < (2 / 2.75)) { | |
return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; | |
} else if (k < (2.5 / 2.75)) { | |
return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; | |
} else { | |
return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; | |
} | |
}, | |
InOut: function (k) { | |
if (k < 0.5) { | |
return TWEEN.Easing.Bounce.In(k * 2) * 0.5; | |
} | |
return TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5; | |
} | |
} | |
}; | |
TWEEN.Interpolation = { | |
Linear: function (v, k) { | |
var m = v.length - 1; | |
var f = m * k; | |
var i = Math.floor(f); | |
var fn = TWEEN.Interpolation.Utils.Linear; | |
if (k < 0) { | |
return fn(v[0], v[1], f); | |
} | |
if (k > 1) { | |
return fn(v[m], v[m - 1], m - f); | |
} | |
return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); | |
}, | |
Bezier: function (v, k) { | |
var b = 0; | |
var n = v.length - 1; | |
var pw = Math.pow; | |
var bn = TWEEN.Interpolation.Utils.Bernstein; | |
for (var i = 0; i <= n; i++) { | |
b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); | |
} | |
return b; | |
}, | |
CatmullRom: function (v, k) { | |
var m = v.length - 1; | |
var f = m * k; | |
var i = Math.floor(f); | |
var fn = TWEEN.Interpolation.Utils.CatmullRom; | |
if (v[0] === v[m]) { | |
if (k < 0) { | |
i = Math.floor(f = m * (1 + k)); | |
} | |
return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); | |
} else { | |
if (k < 0) { | |
return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); | |
} | |
if (k > 1) { | |
return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); | |
} | |
return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); | |
} | |
}, | |
Utils: { | |
Linear: function (p0, p1, t) { | |
return (p1 - p0) * t + p0; | |
}, | |
Bernstein: function (n, i) { | |
var fc = TWEEN.Interpolation.Utils.Factorial; | |
return fc(n) / fc(i) / fc(n - i); | |
}, | |
Factorial: (function () { | |
var a = [1]; | |
return function (n) { | |
var s = 1; | |
if (a[n]) { | |
return a[n]; | |
} | |
for (var i = n; i > 1; i--) { | |
s *= i; | |
} | |
a[n] = s; | |
return s; | |
}; | |
})(), | |
CatmullRom: function (p0, p1, p2, p3, t) { | |
var v0 = (p2 - p0) * 0.5; | |
var v1 = (p3 - p1) * 0.5; | |
var t2 = t * t; | |
var t3 = t * t2; | |
return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; | |
} | |
} | |
}; | |
// UMD (Universal Module Definition) | |
(function (root) { | |
if (typeof define === 'function' && define.amd) { | |
// AMD | |
define([], function () { | |
return TWEEN; | |
}); | |
} else if (typeof module !== 'undefined' && typeof exports === 'object') { | |
// Node.js | |
module.exports = TWEEN; | |
} else if (root !== undefined) { | |
// Global variable | |
root.TWEEN = TWEEN; | |
} | |
})(this); | |
// ===配置=== | |
var sw = document.documentElement.clientWidth; | |
var sh = document.documentElement.clientHeight; | |
var dpr = window.devicePixelRatio;//适配高清屏 | |
var oX = sw/2; | |
var oY = sh/2; | |
var oRadius = 30;//中心圆半径 | |
var oColor = '#ff0000';//中心圆颜色 | |
var base_angle = Math.PI;//基准弧度 | |
var distance_angle = Math.PI / 800;//每px距离转化的弧度 | |
var distance_angle_limit = Math.PI * 3/4;//最大基准弧度 | |
var helpColor = '#aaa'; | |
var canvas = document.getElementById('canvas'); | |
var ctx = canvas.getContext('2d'); | |
var showHelp = document.getElementById('showHelp'); | |
var is_showHelp = false; | |
var is_canMove = true;//是否能拖动 | |
var move_rest = 20;//拖动的边缘容差 | |
var bounce_duration_time = 600; | |
var bounce_animate_type = TWEEN.Easing.Elastic.Out; | |
var last_x,last_y,last_angle,last_distance,coords,tween; | |
// ===函数=== | |
window.requestAnimFrame = (function(){ | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
function( callback ){ | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
// 画圆 | |
function makeCircle(x,y,r,a,c,color) { | |
ctx.beginPath(); | |
ctx.arc(x*dpr,y*dpr,r*dpr,a,c); | |
ctx.fillStyle = color; | |
ctx.closePath(); | |
ctx.fill(); | |
}; | |
// 每次重绘函数 | |
function draw(){ | |
// 重设画布 | |
ctx.clearRect(0,0,sw*dpr,sh*dpr); | |
// 画圆点 | |
makeCircle(oX,oY,oRadius,0,2*Math.PI,oColor); | |
} | |
// 辅助线 | |
function drawHelpLine(a1_x,a1_y,a2_x,a2_y,b1_x,b1_y,b2_x,b2_y){ | |
ctx.strokeStyle = helpColor; | |
ctx.lineWidth = 0.5; | |
ctx.beginPath(); | |
ctx.moveTo(a1_x*dpr,a1_y*dpr); | |
ctx.lineTo(b1_x*dpr,b1_y*dpr); | |
ctx.moveTo(a2_x*dpr,a2_y*dpr); | |
ctx.lineTo(b2_x*dpr,b2_y*dpr); | |
ctx.stroke(); | |
ctx.closePath(); | |
} | |
// 画贝塞尔曲线 | |
function drawBezier(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6){ | |
ctx.filleStyle = oColor; | |
ctx.beginPath(); | |
ctx.moveTo(x1*dpr,y1*dpr); | |
ctx.quadraticCurveTo(x3*dpr,y3*dpr,x2*dpr,y2*dpr); | |
ctx.lineTo(x5*dpr,y5*dpr); | |
ctx.quadraticCurveTo(x6*dpr,y6*dpr,x4*dpr,y4*dpr); | |
ctx.lineTo(x1*dpr,y1*dpr); | |
ctx.fill(); | |
ctx.closePath(); | |
} | |
// 放手回弹圆形 | |
function bounceCircle(){ | |
coords = { x: last_x, y: last_y }; | |
tween = new TWEEN.Tween(coords) | |
.to({ x: oX, y: oY }, bounce_duration_time) | |
.easing(bounce_animate_type) | |
.onUpdate(bounceUpdate) | |
.start(); | |
bounceAnimate(); | |
} | |
function bounceAnimate(time) { | |
requestAnimationFrame(bounceAnimate); | |
TWEEN.update(time); | |
} | |
function bounceUpdate(){ | |
// 弹行速度 | |
x = coords.x; | |
y = coords.y; | |
var distance = Math.sqrt(Math.pow(x-oX,2)+Math.pow(y-oY,2)); | |
var Bangle = base_angle - distance*distance_angle; | |
if(Bangle < distance_angle_limit){Bangle = distance_angle_limit;} | |
// 计算拖拽水平夹角 | |
var angle = last_angle; | |
var dis_x1 = Math.cos(Math.abs(Bangle/2-angle))*oRadius; | |
var dis_y1 = Math.sin(Bangle/2-angle)*oRadius; | |
var dis_x2 = Math.cos(Math.abs(Math.PI-Bangle/2-angle))*oRadius; | |
var dis_y2 = Math.sin(Math.PI-Bangle/2-angle)*oRadius; | |
// 求四个交点 | |
var a1_x,a1_y,a2_x,a2_y,b1_x,b1_y,b2_x,b2_y,c1_x,c1_y,c2_x,c2_y; | |
// 求四个交点 | |
var a1_x,a1_y,a2_x,a2_y,b1_x,b1_y,b2_x,b2_y,c1_x,c1_y,c2_x,c2_y; | |
// 第一象限 | |
if(x>oX&&y<oY){ | |
// 圆A的两个点 | |
a1_x = oX-dis_x2; | |
a1_y = oY-dis_y2; | |
a2_x = oX+dis_x1; | |
a2_y = oY+dis_y1; | |
// 圆B的两个点 | |
b1_x = x-dis_x1; | |
b1_y = y-dis_y1; | |
b2_x = x+dis_x2; | |
b2_y = y+dis_y2; | |
} | |
// 第二象限 | |
else if(x<oX&&y<oY){ | |
// 圆A的两个点 | |
a1_x = oX-dis_x1; | |
a1_y = oY+dis_y1; | |
a2_x = oX+dis_x2; | |
a2_y = oY-dis_y2; | |
// 圆B的两个点 | |
b1_x = x-dis_x2; | |
b1_y = y+dis_y2; | |
b2_x = x+dis_x1; | |
b2_y = y-dis_y1; | |
} | |
// 第三象限 | |
else if(x<oX&&y>oY){ | |
// 圆A的两个点 | |
a1_x = oX+dis_x2; | |
a1_y = oY+dis_y2; | |
a2_x = oX-dis_x1; | |
a2_y = oY-dis_y1; | |
// 圆B的两个点 | |
b1_x = x+dis_x1; | |
b1_y = y+dis_y1; | |
b2_x = x-dis_x2; | |
b2_y = y-dis_y2; | |
} | |
// 第四象限 | |
else if(x>oX&&y>oY){ | |
// 圆A的两个点 | |
a1_x = oX+dis_x1; | |
a1_y = oY-dis_y1; | |
a2_x = oX-dis_x2; | |
a2_y = oY+dis_y2; | |
// 圆B的两个点 | |
b1_x = x+dis_x2; | |
b1_y = y-dis_y2; | |
b2_x = x-dis_x1; | |
b2_y = y+dis_y1; | |
} | |
// 贝塞尔曲线控制点 | |
c1_x = (b2_x+a1_x)/2; | |
c1_y = (b2_y+a1_y)/2; | |
c2_x = (b1_x+a2_x)/2; | |
c2_y = (b1_y+a2_y)/2; | |
// 贝塞尔曲线控制点 | |
c1_x = (b2_x+a1_x)/2; | |
c1_y = (b2_y+a1_y)/2; | |
c2_x = (b1_x+a2_x)/2; | |
c2_y = (b1_y+a2_y)/2; | |
draw(); | |
makeCircle(x,y,oRadius,0,2*Math.PI,oColor); | |
drawBezier(a1_x,a1_y,b1_x,b1_y,c1_x,c1_y,a2_x,a2_y,b2_x,b2_y,c2_x,c2_y); | |
} | |
// ===绑定=== | |
// 绑定拖拽 | |
showHelp.addEventListener('click',function(e){ | |
e.preventDefault(); | |
if(is_showHelp){ | |
is_showHelp = false; | |
} | |
else{ | |
is_showHelp = true; | |
} | |
}); | |
canvas.addEventListener('touchstart',function(e){ | |
e.preventDefault(); | |
var x = e.touches[0].clientX; | |
var y = e.touches[0].clientY; | |
// 计算是否在圆内 | |
var distance = Math.sqrt(Math.pow(x-oX,2)+Math.pow(y-oY,2)); | |
// 圆外无法拖动 | |
is_canMove = (distance-move_rest) > oRadius ? false : true; | |
}); | |
canvas.addEventListener('touchmove',function(e){ | |
e.preventDefault(); | |
if(!is_canMove){ | |
return; | |
} | |
var x = e.touches[0].clientX; | |
var y = e.touches[0].clientY; | |
// 计算两点间距离 | |
var distance = Math.sqrt(Math.pow(x-oX,2)+Math.pow(y-oY,2)); | |
var Bangle = base_angle - distance*distance_angle; | |
if(Bangle < distance_angle_limit){Bangle = distance_angle_limit;} | |
// 计算拖拽水平夹角 | |
var angle = Math.atan(Math.abs(y - oY)/Math.abs(x - oX)); | |
var dis_x1 = Math.cos(Math.abs(Bangle/2-angle))*oRadius; | |
var dis_y1 = Math.sin(Bangle/2-angle)*oRadius; | |
var dis_x2 = Math.cos(Math.abs(Math.PI-Bangle/2-angle))*oRadius; | |
var dis_y2 = Math.sin(Math.PI-Bangle/2-angle)*oRadius; | |
// 记录最新点 | |
last_x = x; | |
last_y = y; | |
last_angle = angle; | |
last_distance = distance; | |
// 求四个交点 | |
var a1_x,a1_y,a2_x,a2_y,b1_x,b1_y,b2_x,b2_y,c1_x,c1_y,c2_x,c2_y; | |
// 第一象限 | |
if(x>oX&&y<oY){ | |
// 圆A的两个点 | |
a1_x = oX-dis_x2; | |
a1_y = oY-dis_y2; | |
a2_x = oX+dis_x1; | |
a2_y = oY+dis_y1; | |
// 圆B的两个点 | |
b1_x = x-dis_x1; | |
b1_y = y-dis_y1; | |
b2_x = x+dis_x2; | |
b2_y = y+dis_y2; | |
} | |
// 第二象限 | |
else if(x<oX&&y<oY){ | |
// 圆A的两个点 | |
a1_x = oX-dis_x1; | |
a1_y = oY+dis_y1; | |
a2_x = oX+dis_x2; | |
a2_y = oY-dis_y2; | |
// 圆B的两个点 | |
b1_x = x-dis_x2; | |
b1_y = y+dis_y2; | |
b2_x = x+dis_x1; | |
b2_y = y-dis_y1; | |
} | |
// 第三象限 | |
else if(x<oX&&y>oY){ | |
// 圆A的两个点 | |
a1_x = oX+dis_x2; | |
a1_y = oY+dis_y2; | |
a2_x = oX-dis_x1; | |
a2_y = oY-dis_y1; | |
// 圆B的两个点 | |
b1_x = x+dis_x1; | |
b1_y = y+dis_y1; | |
b2_x = x-dis_x2; | |
b2_y = y-dis_y2; | |
} | |
// 第四象限 | |
else if(x>oX&&y>oY){ | |
// 圆A的两个点 | |
a1_x = oX+dis_x1; | |
a1_y = oY-dis_y1; | |
a2_x = oX-dis_x2; | |
a2_y = oY+dis_y2; | |
// 圆B的两个点 | |
b1_x = x+dis_x2; | |
b1_y = y-dis_y2; | |
b2_x = x-dis_x1; | |
b2_y = y+dis_y1; | |
} | |
// 贝塞尔曲线控制点 | |
c1_x = (b2_x+a1_x)/2; | |
c1_y = (b2_y+a1_y)/2; | |
c2_x = (b1_x+a2_x)/2; | |
c2_y = (b1_y+a2_y)/2; | |
console.log('两点间距离:'+distance); | |
console.log('与x轴夹角:'+angle*180/Math.PI); | |
console.log('圆A点p1:('+a1_x+','+a1_y+')'); | |
console.log('圆A点p2:('+a2_x+','+a2_y+')'); | |
console.log('圆B点p1:('+b1_x+','+b1_y+')'); | |
console.log('圆B点p2:('+b2_x+','+b2_y+')'); | |
draw(); | |
makeCircle(x,y,oRadius,0,2*Math.PI,oColor); | |
drawBezier(a1_x,a1_y,b1_x,b1_y,c1_x,c1_y,a2_x,a2_y,b2_x,b2_y,c2_x,c2_y); | |
if(is_showHelp){ | |
drawHelpLine(a1_x,a1_y,a2_x,a2_y,b1_x,b1_y,b2_x,b2_y); | |
} | |
}); | |
canvas.addEventListener('touchend',function(e){ | |
e.preventDefault(); | |
if(!is_canMove){ | |
return; | |
} | |
bounce_distance = last_distance; | |
bounceCircle(); | |
}); | |
// ===调用=== | |
// 基本画圆 | |
canvas.setAttribute('style', ';height:' + sh + 'px;width:' + sw + 'px;'); | |
ctx.canvas.width = sw*dpr; | |
ctx.canvas.height = sh*dpr; | |
draw(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment