私はFabric.jsキャンバスを持っており、ソフトウェアパッケージが通常「手動」ツールで実行するフルキャンバスパンを実装したいと考えています。いずれかのマウスボタンを押してから、マウスボタンを押しながらキャンバス上を移動すると、キャンバスの表示部分が変化します。
あなたは このビデオで 私が達成したいことを見ることができます。
この機能を実装するために、次のコードを記述しました。
$(canvas.wrapperEl).on('mousemove', function(evt) {
if (evt.button == 2) { // 2 is the right mouse button
canvas.absolutePan({
x: evt.clientX,
y: evt.clientY
});
}
});
しかし、それは機能しません。あなたは このビデオで 何が起こるかを見ることができます。
コードを順番に変更するにはどうすればよいですか?
パンが最初のビデオのように機能するようにするには?
イベントハンドラーがイベントを消費するには?これにより、ユーザーがマウスの右ボタンを押すか離したときにコンテキストメニューが表示されなくなります。
マウスの動きに応じてファブリックキャンバスをパンする簡単な方法は、マウスイベント間のカーソルの変位を計算してrelativePan
に渡すことです。
前のマウスイベントのscreenX
プロパティとscreenY
プロパティを使用して、現在のマウスイベントの相対位置を計算する方法を確認します。
function startPan(event) {
if (event.button != 2) {
return;
}
var x0 = event.screenX,
y0 = event.screenY;
function continuePan(event) {
var x = event.screenX,
y = event.screenY;
fc.relativePan({ x: x - x0, y: y - y0 });
x0 = x;
y0 = y;
}
function stopPan(event) {
$(window).off('mousemove', continuePan);
$(window).off('mouseup', stopPan);
};
$(window).mousemove(continuePan);
$(window).mouseup(stopPan);
$(window).contextmenu(cancelMenu);
};
function cancelMenu() {
$(window).off('contextmenu', cancelMenu);
return false;
}
$(canvasWrapper).mousedown(startPan);
mousedown
でパンを開始し、mousemove
でパンを続行します。 mouseup
では、パンをキャンセルします。また、mouseup
- cancelling関数自体をキャンセルします。
右クリックメニューはコンテキストメニューとも呼ばれ、false
を返すとキャンセルされます。メニューキャンセル機能もそれ自体をキャンセルします。したがって、後でキャンバスラッパーの外側をクリックすると、コンテキストメニューが機能します。
このアプローチを示すページは次のとおりです。
http://michaellaszlo.com/so/fabric-pan/
ファブリックキャンバス上に3つの画像が表示されます(画像の読み込みには1〜2時間がかかる場合があります)。標準のファブリック機能を使用できるようになります。画像を左クリックすると、画像を移動したり、拡大したり、回転したりできます。ただし、キャンバスコンテナー内で右クリックすると、ファブリックキャンバス全体をマウスでパンします。
Fabric.js Canvas panningを使用したGithubの例があります: https://sabatinomasala.github.io/fabric-clipping-demo/
パン動作を担当するコードは次のとおりです: https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js
これはfabric.Canvas.prototype
の単純な拡張機能であり、キャンバス上の「ドラッグモード」を次のように切り替えることができます。
canvas.toggleDragMode(true); // Start panning
canvas.toggleDragMode(false); // Stop panning
次のスニペットをご覧ください。コード全体でドキュメントを利用できます。
const STATE_IDLE = 'idle';
const STATE_PANNING = 'panning';
fabric.Canvas.prototype.toggleDragMode = function(dragMode) {
// Remember the previous X and Y coordinates for delta calculations
let lastClientX;
let lastClientY;
// Keep track of the state
let state = STATE_IDLE;
// We're entering dragmode
if (dragMode) {
// Discard any active object
this.discardActiveObject();
// Set the cursor to 'move'
this.defaultCursor = 'move';
// Loop over all objects and disable events / selectable. We remember its value in a temp variable stored on each object
this.forEachObject(function(object) {
object.prevEvented = object.evented;
object.prevSelectable = object.selectable;
object.evented = false;
object.selectable = false;
});
// Remove selection ability on the canvas
this.selection = false;
// When MouseUp fires, we set the state to idle
this.on('mouse:up', function(e) {
state = STATE_IDLE;
});
// When MouseDown fires, we set the state to panning
this.on('mouse:down', (e) => {
state = STATE_PANNING;
lastClientX = e.e.clientX;
lastClientY = e.e.clientY;
});
// When the mouse moves, and we're panning (mouse down), we continue
this.on('mouse:move', (e) => {
if (state === STATE_PANNING && e && e.e) {
// let delta = new fabric.Point(e.e.movementX, e.e.movementY); // No Safari support for movementX and movementY
// For cross-browser compatibility, I had to manually keep track of the delta
// Calculate deltas
let deltaX = 0;
let deltaY = 0;
if (lastClientX) {
deltaX = e.e.clientX - lastClientX;
}
if (lastClientY) {
deltaY = e.e.clientY - lastClientY;
}
// Update the last X and Y values
lastClientX = e.e.clientX;
lastClientY = e.e.clientY;
let delta = new fabric.Point(deltaX, deltaY);
this.relativePan(delta);
this.trigger('moved');
}
});
} else {
// When we exit dragmode, we restore the previous values on all objects
this.forEachObject(function(object) {
object.evented = (object.prevEvented !== undefined) ? object.prevEvented : object.evented;
object.selectable = (object.prevSelectable !== undefined) ? object.prevSelectable : object.selectable;
});
// Reset the cursor
this.defaultCursor = 'default';
// Remove the event listeners
this.off('mouse:up');
this.off('mouse:down');
this.off('mouse:move');
// Restore selection ability on the canvas
this.selection = true;
}
};
// Create the canvas
let canvas = new fabric.Canvas('fabric')
canvas.backgroundColor = '#f1f1f1';
// Add a couple of rects
let rect = new fabric.Rect({
width: 100,
height: 100,
fill: '#f00'
});
canvas.add(rect)
rect = new fabric.Rect({
width: 200,
height: 200,
top: 200,
left: 200,
fill: '#f00'
});
canvas.add(rect)
// Handle dragmode change
let dragMode = false;
$('#dragmode').change(_ => {
dragMode = !dragMode;
canvas.toggleDragMode(dragMode);
});
<div>
<label for="dragmode">
Enable panning
<input type="checkbox" id="dragmode" name="dragmode" />
</label>
</div>
<canvas width="300" height="300" id="fabric"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.15/fabric.min.js"></script>
FabricJSについてはわかりませんが、次のように考えられます。
それが最初のビデオのように機能するために:
CSSのcursor
プロパティを利用することで、JavaScriptを使用してmousedown
およびmouseup
イベントでプロパティを切り替えることができます。
イベントハンドラーがイベントを消費します(ユーザーがマウスの右ボタンを離したときにコンテキストメニューが表示されないようにします)。
JavaScriptを使用して、false
イベントでcontextmenu
を返します
コード:少し問題あり (*)
jQueryを使用 JS Fiddle 1
_$('#test').on('mousedown', function(e){
if (e.button == 2) {
// if right-click, set cursor shape to grabbing
$(this).css({'cursor':'grabbing'});
}
}).on('mouseup', function(){
// set cursor shape to default
$(this).css({'cursor':'default'});
}).on('contextmenu', function(){
//disable context menu on right click
return false;
});
_
未加工のJavaScriptを使用 JS Fiddle 2
_var test = document.getElementById('test');
test.addEventListener('mousedown', function(e){
if (e.button == 2) {
// if right-click, set cursor shape to grabbing
this.style.cursor = 'grabbing';
}
});
test.addEventListener('mouseup', function(){
// set cursor shape to default
this.style.cursor = 'default';
});
test.oncontextmenu = function(){
//disable context menu on right click
return false;
}
_
(*)問題:
上記のスニペットは正常に動作しますが、Firefox-またはOperaで上記のフィドルをチェックすると、チェックインすると正しい動作が表示され、クロスブラウザの問題が発生しますChrome and IE11-それをEdgeまたはSafariでチェックしなかった-私はChromeおよび= IE grabbing
カーソル形状をサポートしないため、上記のコードスニペットで、カーソル行を次のように変更します。
jQuery:$(this).css({'cursor':'move'});
JS Fiddle
生のjavascript:_this.style.cursor = 'move';
_ JS Fiddle 4
これで作業コードができましたが、ハンドカーソルはありません。しかし、次の解決策があります:-
解決策:
ChromeとSafariは、grab
とgrabbing
をサポートし、次のような_-webkit-
_プレフィックスを付けます。
_$(this).css({'cursor': '-webkit-grabbing'});
_
ただし、最初にブラウザのスニッフィングを行う必要があります。Firefoxの場合はデフォルトの標準コード、ChromeおよびSafariの場合は_-webkit-
_接頭辞を付けると、IEゲーム外です。
this example を見て、Chrome、Safari、Firefox、Opera and IE cursor: url(foo.bar)
が機能し、[〜#〜]すべての[〜#〜]ブラウザでサポートされていることがわかります。Chrome、Safari、 FirefoxおよびOperaは黄色の笑顔の画像_smiley.gif
_を示しますが、IEは赤いボールカーソルurl(myBall.cur)
を示します。
ですから、これを使って、この手の画像をつかむことができると思います
またはこれ:
上記のようなpng
またはgif
形式の画像は、IEが_.cur
_をサポートする)を除くすべてのブラウザで使用できるため、 _.cur
_に変換する方法を見つけてください。Google検索では convert image to cur の多くの結果が表示されます
注意ただし、これはcursor:url(smiley.gif),url(myBall.cur),auto;
-コンマで区切られたフォールバックサポートを使用すると、上記のW3Schoolsの例でうまく機能し、JavaScriptで同じように機能させることができませんでした。$(this).css({'cursor': 'grabbing, move'});
を試しましたが、機能しませんでした。 CSSクラスとしてもやってみました
_.myCursor{ cursor: grabbing, -webkit-grabbing, move; }
_
次に、jQuery $(this).addClass('myCursor');
を使用しますが、使用できません。
したがって、2番目のソリューションを実行する場合でも、両方のソリューションのハイブリッドフィックスを実行する場合でも、ブラウザをスニッフィングする必要があります これは私のコードです これは私ですブラウザを検出するために数回使用しましたが、この投稿の時点ではうまく機能していましたが、「モバイル」と「Kindle」のパーツは必要ありません。
_// Detecting browsers
$UA = navigator.userAgent;
if ($UA.match(/firefox/i)) {
$browser = 'Firefox';
} else if ($UA.indexOf('Trident') != -1 && $UA.indexOf('MSIE') == -1) {
$browser = 'MSIE';
} else if ($UA.indexOf('MSIE') != -1) {
$browser = 'MSIE';
} else if ($UA.indexOf('OPR/') != -1) {
$browser = 'Opera';
} else if ($UA.indexOf("Chrome") != -1) {
$browser = 'Chrome';
} else if ($UA.indexOf("Safari")!=-1) {
$browser = 'Safari';
}
if($UA.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Nokia|Mobile|Opera Mini/i)) {
$browser = 'Mobile';
}else if($UA.match(/KFAPWI/i)){
$browser = 'Kindle';
}
console.log($browser);
_
リソース:
jsfiddleの例を作成しました。実際に、すべてのオブジェクトを含むキャンバス全体を、図のように親divにドラッグできます。これを段階的に説明していきます。
まず、ドラッグライブラリjquery.dradscroll.jsをダウンロードします。ネットで見つけることができます。これは小さなjsファイルであり、少し変更するだけでタスクを完了できます。ダウンロードリンク: http://www.Java2s.com/Open-Source/Javascript_Free_Code/jQuery_Scroll/Download_jquery_dragscroll_Free_Java_Code.htm
キャンバスを保持するコンテナを作成します。
_ <div class="content">
<canvas id="c" width="600" height="700" ></canvas>
</div>
_
少しCSS
_.content{
overflow:auto;
width:400px;
height:400px;
}
_
javascript:
a。キャンバスを作成します。
b。デフォルトのカーソルを作成し、キャンバス上にあるとき、手を開きます
canvas.defaultCursor = 'url(" http://maps.gstatic.com/intl/en_us/mapfiles/openhand_8_8.cur") 15 15, crosshair';
c。 __onMouseDown関数をオーバーライドして、closedhandカーソル(末尾)に変更します。
_ fabric.Canvas.prototype.__onMouseDown = function(e){
// accept only left clicks
var isLeftClick = 'which' in e ? e.which === 1 : e.button === 1;
if (!isLeftClick && !fabric.isTouchSupported) {
return;
}
if (this.isDrawingMode) {
this._onMouseDownInDrawingMode(e);
return;
}
// ignore if some object is being transformed at this moment
if (this._currentTransform) {
return;
}
var target = this.findTarget(e),
pointer = this.getPointer(e, true);
// save pointer for check in __onMouseUp event
this._previousPointer = pointer;
var shouldRender = this._shouldRender(target, pointer),
shouldGroup = this._shouldGroup(e, target);
if (this._shouldClearSelection(e, target)) {
this._clearSelection(e, target, pointer);
}
else if (shouldGroup) {
this._handleGrouping(e, target);
target = this.getActiveGroup();
}
if (target && target.selectable && !shouldGroup) {
this._beforeTransform(e, target);
this._setupCurrentTransform(e, target);
}
// we must renderAll so that active image is placed on the top canvas
shouldRender && this.renderAll();
this.fire('mouse:down', { target: target, e: e });
target && target.fire('mousedown', { e: e });
if(!canvas.getActiveObject() || !canvas.getActiveGroup()){
flag=true;
//change cursor to closedhand.cur
canvas.defaultCursor = 'url("http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur") 15 15, crosshair';
}//end if
_
__onMouseUpイベントをオーバーライドして、カーソルをオープンハンドに戻します。
_ fabric.Canvas.prototype.__onMouseUp = function(e){
if(flag){
canvas.defaultCursor = 'url(" http://maps.gstatic.com/intl/en_us/mapfiles/openhand_8_8.cur") 15 15, crosshair';
flag=false;
}
};
_
DragScroll()を初期化して、キャンバスをホストするコンテンツを処理します。
_ $('.content').dragScroll({});
_
キャンバスをドラッグするタイミングとドラッグしないタイミングを理解するために、jquery.dragScroll.jsファイルにいくつかの小さな変更を加えました。 mousedown()イベントでは、ifステートメントを追加して、アクティブなオブジェクトまたはグループがあるかどうかを確認します。trueの場合、キャンバスのドラッグはありません。
_ $($scrollArea).mousedown(function (e) {
if (canvas.getActiveObject() || canvas.getActiveGroup()) {
console.log('no drag');return;
} else {
console.log($('body'));
if (typeof options.limitTo == "object") {
for (var i = 0; i < options.limitTo.length; i++) {
if ($(e.target).hasClass(options.limitTo[i])) {
doMousedown(e);
}
}
} else {
doMousedown(e);
}
}
});
_
mousedownイベントで、DOM要素(.content)を取得し、top&left position
_ function doMousedown(e) {
e.preventDefault();
down = true;
x = e.pageX;
y = e.pageY;
top = e.target.parentElement.parentElement.scrollTop; // .content
left = e.target.parentElement.parentElement.scrollLeft;// .content
}
_
スクロールバーを表示したくない場合:
_ .content{
overflow:hidden;
width:400px;
height:400px;
_
}
小さな問題がありますが、jsfiddleはhttpsライブラリのみを受け入れるため、 ' https://rawgit.com/kangax/fabric.js/master/dist/fabric。 js 'ですが、やはり何度かブロックされます(少なくともmy chrome and mozilla)。
jsfiddleの例: https://jsfiddle.net/tornado1979/up48rxLs/
あなたは私よりもあなたのブラウザーでより幸運を持っているかもしれませんが、それは間違いなくあなたのライブアプリで動作します。
とにかく、私は、幸運を助けることを願っています。