2010-06-23 10 views
10

모든 HTML5 및 자바 스크립트에서 스케치 응용 프로그램을 실행했으며 마지막으로 수행 한 작업을 실행 취소 할 수 있도록 실행 취소 단추를 만드는 방법이 궁금합니다. 어떤 생각?HTML5 Canvas에 실행 취소 기능을 추가하는 방법은 무엇입니까?

+1

[명령 패턴] (http://en.wikipedia.org/wiki/Command_pattern)을 확인하십시오 – Anurag

+1

왜 태그에 java 및 objective-c가 있습니까? –

답변

13

모든 수정 사항을 데이터 구조에 저장해야합니다. 그런 다음 사용자가 을 실행 취소하려는 경우 최신 수정 사항을 삭제할 수 있습니다. 그런 다음 데이터 구조에서 다시 모든 그리기 작업을 다시 칠합니다.

+0

보이지 않는 DIV 요소에 캔버스 정보를 나타내는 JSON 데이터 구조를 저장하여이 작업을 수행하는 방법의 예는 http://whiffdoc.appspot.com/tests/schema/diagram을 참조하십시오. (소스 페이지에서 링크를 따라) –

+1

@AaronWatters,이 링크는 나를 404 페이지로 안내합니다. 업데이트 된 링크가 있습니까? – link2pk

3

http://arthurclemens.github.io/Javascript-Undo-Manager/에서 캔버스 요소로 실행 취소의 작동 예제가 있습니다. 수정을하면 실행 취소 관리자에게 실행 취소 및 다시 실행 메소드를 제공합니다. 실행 취소 스택의 위치 추적은 자동으로 수행됩니다. 소스 코드는 Github에 있습니다.

+0

예제가 좋아 보인다! 공유 해 주셔서 감사합니다. –

+0

은 Chrome에서 좋아 보이지만 Firefox에서는 작동하지 않습니다. – waspinator

+0

데모에서 몇 가지 작은 드로잉 버그를 수정했습니다. –

1

다른 옵션은 객체를 조작해야하는 경우 캔버스 API를 유지하는 라이브러리를 사용하여 캔버스를 SVG로 변환하는 것입니다. SVGKit

당신이 SVG가되면, 전체 캔버스를 다시 그릴 필요없이 객체 등을 제거하는 것이 훨씬 쉽습니다 :

적어도 하나의 라이브러리는이 시간 (11 월 2011)에 존재한다.

+2

아니면 그는 [fabric.js] (http://kangax.github.com/fabric.js/)와 같은 캔버스 추상화 라이브러리를 사용하여 프로그래밍 방식으로 캔버스의 객체로 작업 할 수 있습니다. – kangax

+0

우수 @kangax. 저는 궁금합니다. 수백 개의 노드가있는 캔버스에서 객체를 편집 할 때 fabric.j가 SVGKit과 성능면에서 어떻게 비교 될 것이라고 생각합니까? –

+0

SVGKit과 비교하는 방법을 잘 모르겠지만 많은 수의 개체 캔버스는 SVG보다 더 뛰어난 경향이 있습니다. 라파엘 (SVG 기반)과 패브릭 (캔버스 기반)을 비교 한 몇 가지 벤치 마크를 살펴보십시오. http://fabricjs.com/benchmarks/ – kangax

0

다음은 저에게 적합한 해결책입니다. 나는 파이어 폭스와 크롬의 최신 버전에서 그것을 시험해 보았다. 그리고 그것은 그 2 개의 브라우저에서 정말로 잘 작동한다.

var isFirefox = typeof InstallTrigger !== 'undefined'; 
var ctx = document.getElementById('myCanvas').getContext("2d"); 
var CanvasLogBook = function() { 
    this.index = 0; 
    this.logs = []; 
    this.logDrawing(); 
}; 
CanvasLogBook.prototype.sliceAndPush = function(imageObject) { 
    var array; 
    if (this.index == this.logs.length-1) { 
     this.logs.push(imageObject); 
     array = this.logs; 
    } else { 
     var tempArray = this.logs.slice(0, this.index+1); 
     tempArray.push(imageObject); 
     array = tempArray; 
    } 
    if (array.length > 1) { 
     this.index++; 
    } 
    return array; 
}; 
CanvasLogBook.prototype.logDrawing = function() { 
    if (isFirefox) { 
     var image = new Image(); 
     image.src = document.getElementById('myCanvas').toDataURL(); 
     this.logs = this.sliceAndPush(image); 
    } else { 
     var imageData = document.getElementById('myCanvas').toDataURL(); 
     this.logs = this.sliceAndPush(imageData); 
    } 
}; 
CanvasLogBook.prototype.undo = function() { 
    ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height()); 
    if (this.index > 0) { 
     this.index--; 
     this.showLogAtIndex(this.index); 
    } 
}; 
CanvasLogBook.prototype.redo = function() { 
    if (this.index < this.logs.length-1) { 
     ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height()); 
     this.index++; 
     this.showLogAtIndex(this.index); 
    } 
}; 
CanvasLogBook.prototype.showLogAtIndex = function(index) { 
    ctx.clearRect(0, 0, $('#myCanvas').width(), $('#myCanvas').height()); 
    if (isFirefox) { 
     var image = this.logs[index]; 
     ctx.drawImage(image, 0, 0); 
    } else { 
     var image = new Image(); 
     image.src = this.logs[index]; 
     ctx.drawImage(image, 0, 0); 
    } 
}; 
var canvasLogBook = new CanvasLogBook(); 

그래서 당신은 당신이 실행 기능 canvasLogBook.logDrawing()는 캔버스의 스냅 샷이 저장됩니다 후 어떤 일을 그린 다음 canvasLogBook.undo()를 호출 할 때마다 취소하고 canvasLogBook.redo하기() 다시 할 수 있습니다.

+0

jQuery에 의존하지 않고'isFirefox' 부울을 제거하면 좋은 대답이 될 것입니다 :) – A1rPun

관련 문제