HTML5 + 자바 스크립트 + CSS
그래서 오래 전에 그것을했습니다 (파일의 마지막 수정 날짜는 2012 년 9 월 21 일입니다). 내가 그것을 유지 다행입니다. 불행히도 현재 상태에서 4 개의 제어점 만 지원하지만 현재 노력하고 있습니다.
편집 : UI는 4 개의 제어점 만 지원하지만 기본 기능 ( animateConstruction
)은 임의의 수의 제어점을 지원합니다. 코드가 매우 비효율적이므로 10 이상을 수행하지 않는 것이 좋습니다. (25로 시도했지만 작업 관리자를 사용하여 탭을 종료해야했습니다) 이것이 유효한 제출로 간주되면 코드를 개정 할 계획이 아닙니다.
참고 : 나는 당시 순진한 취미가였습니다. 세미콜론 부족 및 사용을 포함하여 여러 수준에서 코드가 잘못되었습니다 eval
.
사용
코드를 .html 파일로 저장하고 Chrome 또는 JSfiddle 에서 엽니 다.
4 개 이하의 제어점이 필요하면 오른쪽에 매개 변수를 입력 한 다음 "건설 모드"를 선택하고 왼쪽 하단에서 "애니메이션"을 누르십시오.
더 많은 제어점이 필요하면 animateConstruction
함수를 호출하십시오 . 인수로 좌표 배열 (2 항목 배열)을 사용합니다. (예 :) animateConstruction([[0,0],[500,0],[0,500]]
. 그리기 영역은 500x500이며 좌표계는 HTML 캔버스 요소를 따릅니다 (왼쪽 상단, x 축은 오른쪽, y 축은 아래쪽)
바이올린의 경우 왼쪽 아래에 텍스트 상자를 추가했습니다. 세미콜론으로 구분 된 좌표를 입력하고 (기본값은 예) Go를 누릅니다.
피들 버전의 차이점
- 텍스트 상자
- 기본 애니메이션 단계가 100으로 감소
- 보조 커브는 기본적으로 꺼져 있습니다
암호
<html>
<head>
<style>
span.h{
display: inline-block;
text-align: center;
text-decoration: underline;
font: bold 1em Arial;
}
input[type="color"]{
-webkit-appearance: button-bevel;
vertical-align: -7px;
width: 21px;
height: 27px;
}
input[type="color"][disabled]{background: #FFF}
td{position:relative; padding:1px; text-align:center}
table[class] td{text-align:left}
td.t{padding:1px 5px; width:46px;}
table input[type="checkbox"]{visibility:hidden}
tr:hover input[type="checkbox"]{visibility:visible}
</style>
<script type='text/javascript'>
function Bezier(c){
if(c.length==2) return function(t){return [c[0][0]+t*(c[1][0]-c[0][0]),c[0][1]+t*(c[1][1]-c[0][1])]}
else return function(t){return Bezier([Bezier(c.slice(0,-1))(t),Bezier(c.slice(1))(t)])(t)}
}
function Bezier2(f1,f2){
return function(t){return Bezier([f1(t),f2(t)])(t)}
}
//============================================
var c = null
var settings = {'guide':{'show':[true,true,true,true], 'color':['#EEEEEE','#00FF00','#0000FF','#FF00FF'], 'width':[10,1,1,1]}, 'curve':{'show':[true,true,true,true], 'color':['#EEEEEE','#00FF00','#0000FF','#FF00FF'], 'width':[10,3,3,3]}, 'main':{'show':true, 'color':'#FF0000', 'width':10}, 'sample': 100, 'steps':200, 'stepTime':10, 'mode':'Bezier', 'coords':[[0,500],[125,450],[125,0],[500,0]]}
var itv = 0
window.addEventListener('load',function(){
c = $('c').getContext('2d')
c.lineCap = 'round'
c.lineJoin = 'round'
draw(settings.coords,1)
},true)
function get(k,i){
var t = settings
if(k.constructor == Array) k.forEach(function(e){t = t[e]})
return t.length>i ? t[i] : t.slice(-1)[0]
}
function frame(coords){
c.strokeStyle = settings.curve.color[0]
c.lineWidth = settings.guide.width[0]
c.beginPath()
c.moveTo.apply(c,coords[0])
coords.slice(1).forEach(function(e){c.lineTo.apply(c,e)})
c.stroke()
}
function transf(c){
var t = []
c.forEach(function(e){t.push([e[0]+5,e[1]+5])})
return t
}
//============================================
function drawBezier(coords,t){
if(t===undefined) t = 1
coords = transf(coords)
c.clearRect(0,0,510,510)
frame(coords)
c.beginPath()
c.strokeStyle = settings.main.color
c.lineWidth = settings.main.width
c.moveTo.apply(c,coords[0])
for(var i=0;i<=t*settings.sample;i++) c.lineTo.apply(c,Bezier(coords)(i/settings.sample))
c.stroke()
}
function animateBezier(coords){
var s = settings.steps
var cur = ($('t').value==1 ? ($('t').value=$('T').innerHTML=(0).toFixed(3))*1 : $('t').value*s)+1
var b = drawBezier(coords,$('t').value*1)
itv = setInterval(function(){
$("T").innerHTML = ($("t").value = cur/s).toFixed(3)
drawBezier(coords,cur++/s,b)
if(cur>s) clearInterval(itv)
},settings.stepTime)
}
//============================================
function drawBezier2(coords,t){
if(t===undefined) t = 1
c.beginPath()
c.strokeStyle = get(['curve','color'],coords.length-1)
c.lineWidth = get(['curve','width'],coords.length-1)
c.moveTo.apply(c,coords[0])
for(var i=0;i<=t*100;i++) c.lineTo.apply(c,Bezier(coords)(i/100))
c.stroke()
}
function drawConstruction(coords,t,B){
coords = transf(coords)
if(t===undefined) t = 0.5
var b = B===undefined ? [[]] : B
coords.forEach(function(e){b[0].push(function(t){return e})})
c.clearRect(0,0,510,510)
frame(coords)
for(var i=1;i<coords.length;i++){
if(B===undefined) b.push([])
with(c){
for(var j=0;j<coords.length-i;j++){
if(B===undefined) b[i].push(Bezier2(b[i-1][j],b[i-1][j+1]))
if(i!=coords.length-1 && get(['curve','show'],i-1) || i==coords.length-1 && settings.main.show){
strokeStyle = i==coords.length-1?settings.main.color:get(['curve','color'],i-1)
lineWidth = i==coords.length-1?settings.main.width:get(['curve','width'],i-1)
beginPath()
moveTo.apply(c,b[i][j](0))
for(var k=0;k<=t*settings.sample;k++) lineTo.apply(c,b[i][j](k/settings.sample))
stroke()
}
if(i && i!=coords.length-1 && get(['guide','show'],i)){
strokeStyle = i==coords.length-1?settings.main.color:get(['guide','color'],i)
lineWidth = i==coords.length-1?settings.main.width:get(['guide','width'],i)
beginPath()
if(i!=coords.length-1) arc.apply(c,b[i][j](t).concat([settings.curve.width[0]/2,0,2*Math.PI]))
stroke()
}
}
if(i && i!=coords.length-1 && get(['guide','show'],i)){
beginPath()
moveTo.apply(c,b[i][0](t))
for(var j=1;j<coords.length-i;j++) lineTo.apply(c,b[i][j](t))
stroke()
}
}
}
return b
}
function animateConstruction(coords){
var s = settings.steps
var cur = ($('t').value==1 ? ($('t').value=$('T').innerHTML=(0).toFixed(3))*1 : $('t').value*s)+1
var b = drawConstruction(coords,$('t').value*1)
itv = setInterval(function(){
$("T").innerHTML = ($("t").value = cur/s).toFixed(3)
drawConstruction(coords,cur++/s,b)
if(cur>s) clearInterval(itv)
},settings.stepTime)
}
//============================================
function draw(coords,t){clearInterval(itv); return window['draw'+settings.mode](coords,t)}
function animate(coords){clearInterval(itv); return window['animate'+settings.mode](coords);}
//============================================
function $(id){return document.getElementById(id)}
function v(o,p){
for(var i in o){
var k = (p||[]).concat([i]).join('-')
var t
if((t = o[i].constructor) == Object || t == Array) v(o[i],[k])
else if(t = $(k)){
if(t.type=='checkbox') t.checked = o[i]
else if(t.type=='radio'){
for(var j=0, t=document.getElementsByName(t.name); j<t.length; j++) if(t[j].value == o[i]){
t[j].checked = true
break
}
}else t.value = o[i]
}else if(t = $((i==0?'x':'y') + p[0].slice(-1))) t.value = o[i]
}
}
document.addEventListener('load',function(){
v(settings)
$('t').setAttribute('step',1/settings.steps)
var t = document.getElementsByTagName('input')
for(i=0;i<t.length;i++) t[i].addEventListener('change',function(){
var t
if((t=this.id.split('-')).length > 1){
var t1 = function(T){
var t = 'settings'
T.forEach(function(e){t += '[' + (isNaN(e)?'"'+e+'"':e) +']'})
eval(t + '=' + (this.type=='text'?this.value:(this.type=='checkbox'?this.checked:'"'+this.value+'"')))
$(T.join('-')).value = this.value
}
t1.call(this,t)
if(t[0]=='curve' && t[1]=='color' && $('u').checked==true) t1.call(this,['guide'].concat(t.slice(1)))
}else if(this.id == 'u'){
for(i=0;t=$('guide-color-'+i);i++){
t.disabled = this.checked
t.value = settings.guide.color[i] = this.checked?settings.curve.color[i]:t.value
}
}else if(this.id == 't'){
$('T').innerHTML = (this.value*1).toFixed(3)
draw(settings.coords,this.value*1)
}else if(t = /([xy])(\d+)/.exec(this.id)) settings.coords[t[2]*1][t[1]=='x'?0:1] = this.value*1
else settings[this.id] = this.value
if(this.id == 'steps') $("t").setAttribute("step",1/settings.steps)
},true)
},true)
</script>
</head>
<body>
<canvas style='float:left' width='510' height='510' id='c'>
</canvas>
<div style='padding-left:550px; font-family:Arial'>
<span class='h' style='width:123px'>Control Points</span><br />
(<input type='text' id='x0' size='3' maxlength='3' />,<input type='text' id='y0' size='3' maxlength='3' />)<br />
(<input type='text' id='x1' size='3' maxlength='3' />,<input type='text' id='y1' size='3' maxlength='3' />)<br />
(<input type='text' id='x2' size='3' maxlength='3' />,<input type='text' id='y2' size='3' maxlength='3' />)<br />
(<input type='text' id='x3' size='3' maxlength='3' />,<input type='text' id='y3' size='3' maxlength='3' />)<br /><br />
<span class='h' style='width:200px'>Appearance</span><br />
<span style='font-weight:bold'>Guide lines</span><br />
<input type='checkbox' checked='checked' id='u' onchange='' /> Use curve colors<br />
<table style='border-collapse:collapse'>
<tr><td><input type='checkbox' id='guide-show-0' /></td><td><input type='color' id='guide-color-0' disabled='disabled' /></td><td class='t'>Frame</td><td><input type='text' id='guide-width-0' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-1' /></td><td><input type='color' id='guide-color-1' disabled='disabled' /></td><td class='t'>1</td><td><input type='text' id='guide-width-1' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-2' /></td><td><input type='color' id='guide-color-2' disabled='disabled' /></td><td class='t'>2</td><td><input type='text' id='guide-width-2' size='2' maxlength='2' /></td></tr>
<tr><td><input type='checkbox' id='guide-show-3' /></td><td><input type='color' id='guide-color-3' disabled='disabled' /></td><td class='t'>3</td><td><input type='text' id='guide-width-3' size='2' maxlength='2' /></td></tr>
</table>
<span style='font-weight:bold'>Curves</span>
<table style='border-collapse:collapse'>
<tr><td><input type='checkbox' id='curve-show-0' /></td><td><input type='color' id='curve-color-0' /></td><td class='t'>1</td><td><input type='text' id='curve-width-0' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-1' /></td><td><input type='color' id='curve-color-1' /></td><td class='t'>2</td><td><input type='text' id='curve-width-1' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-2' /></td><td><input type='color' id='curve-color-2' /></td><td class='t'>3</td><td><input type='text' id='curve-width-2' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='curve-show-3' /></td><td><input type='color' id='curve-color-3' /></td><td class='t'>4</td><td><input type='text' id='curve-width-3' size='2' maxlength='2' /></td></td></tr>
<tr><td><input type='checkbox' id='main-show' /></td><td><input type='color' id='main-color' /></td><td class='t'>Main</td><td><input type='text' id='main-width' size='2' maxlength='2' /></td></td></tr>
</table><br />
<span class='h' style='width:300px'>Graphing & Animation</span><br />
<table class>
<tr><td>Sample points:</td><td><input type='text' id='sample' /></td></tr>
<tr><td>Animation steps:</td><td><input type='text' id='steps' /></td></tr>
<tr><td>Step time:</td><td><input type='text' id='stepTime' />ms</td></tr>
</table>
<div style='position:absolute; top:526px; left:8px; width:510px; height:100px;'>
<input type='range' id='t' max='1' min='0' style='width:450px' value='1' /> <span id='T' style='vertical-align: 6px'>1.000</span><br />
<input type='button' onclick='draw(settings.coords,$("t").value*1)' value='Draw' /><input type='button' onclick='animate(settings.coords)' value='Animate' />
<input type='radio' id='mode' name='mode' value='Bezier' />Basic Mode <input type='radio' id='mode' name='mode' value='Construction' />Construction Mode
</div>
</body>
</html>