別のキャンバスの上にキャンバスを追加しようとしています-最初のキャンバスが作成されるまで、この関数を開始まで待機させるにはどうすればよいですか?
function PaintObject(brush) {
this.started = false;
// get handle of the main canvas, as a DOM object, not as a jQuery Object. Context is unfortunately not yet
// available in jquery canvas wrapper object.
var mainCanvas = $("#" + brush).get(0);
// Check if everything is ok
if (!mainCanvas) {alert("canvas undefined, does not seem to be supported by your browser");}
if (!mainCanvas.getContext) {alert('Error: canvas.getContext() undefined !');}
// Get the context for drawing in the canvas
var mainContext = mainCanvas.getContext('2d');
if (!mainContext) {alert("could not get the context for the main canvas");}
this.getMainCanvas = function () {
return mainCanvas;
}
this.getMainContext = function () {
return mainContext;
}
// Prepare a second canvas on top of the previous one, kind of second "layer" that we will use
// in order to draw elastic objects like a line, a rectangle or an ellipse we adjust using the mouse
// and that follows mouse movements
var frontCanvas = document.createElement('canvas');
frontCanvas.id = 'canvasFront';
// Add the temporary canvas as a second child of the mainCanvas parent.
mainCanvas.parentNode.appendChild(frontCanvas);
if (!frontCanvas) {
alert("frontCanvas null");
}
if (!frontCanvas.getContext) {
alert('Error: no frontCanvas.getContext!');
}
var frontContext = frontCanvas.getContext('2d');
if (!frontContext) {
alert("no TempContext null");
}
this.getFrontCanvas = function () {
return frontCanvas;
}
this.getFrontContext = function () {
return frontContext;
}
キャンバスを作成するコードにアクセスできる場合は、キャンバスが作成された直後に関数を呼び出してください。
そのコードにアクセスできない場合(たとえば、Googleマップなどのサードパーティのコードの場合)、間隔内での存在をテストすることができます。
var checkExist = setInterval(function() {
if ($('#the-canvas').length) {
console.log("Exists!");
clearInterval(checkExist);
}
}, 100); // check every 100ms
しかし、注意してください-サードパーティのコードには、ロードの完了時にコードをアクティブにするオプションがあります(コールバックまたはイベントトリガーによって)。それはあなたの関数を置くことができる場所かもしれません。間隔ソリューションは実際には悪いソリューションであり、他に何も機能しない場合にのみ使用する必要があります。
サポートする必要のあるブラウザに応じて、 MutationObserver のオプションがあります。
これに沿った何かがトリックを行うはずです:
// callback executed when canvas was found
function handleCanvas(canvas) { ... }
// set up the mutation observer
var observer = new MutationObserver(function (mutations, me) {
// `mutations` is an array of mutations that occurred
// `me` is the MutationObserver instance
var canvas = document.getElementById('my-canvas');
if (canvas) {
handleCanvas(canvas);
me.disconnect(); // stop observing
return;
}
});
// start observing
observer.observe(document, {
childList: true,
subtree: true
});
N.B.私はこのコードを自分でテストしていませんが、それは一般的な考え方です。
これを簡単に拡張して、変更されたDOMの一部のみを検索できます。そのためには、mutations
引数を使用します。これは MutationRecord
オブジェクトの配列です。
これは最新のブラウザでのみ機能しますが、then
を使用する方が簡単だと思うので、最初にテストしてください:
コード
function rafAsync() {
return new Promise(resolve => {
requestAnimationFrame(resolve); //faster than set time out
});
}
function checkElement(selector) {
if (document.querySelector(selector) === null) {
return rafAsync().then(() => checkElement(selector));
} else {
return Promise.resolve(true);
}
}
またはジェネレーター関数を使用
async function checkElement(selector) {
const querySelector = document.querySelector(selector);
while (querySelector === null) {
await rafAsync()
}
return querySelector;
}
使用法
checkElement('body') //use whichever selector you want
.then((element) => {
console.info(element);
//Do whatever you want now the element is there
});
要素を待つためのより現代的なアプローチ:
while(!document.querySelector(".my-selector")) {
await new Promise(r => setTimeout(r, 500));
}
// now the element is loaded
このコードは async function でラップする必要があることに注意してください。
requestAnimationFrame
よりもsetTimeout
でリレーする方が適切です。これはes6モジュールでのPromises
を使用した私のソリューションです。
es6、モジュールおよび約束:
// onElementReady.js
const onElementReady = $element => (
new Promise((resolve) => {
const waitForElement = () => {
if ($element) {
resolve($element);
} else {
window.requestAnimationFrame(waitForElement);
}
};
waitForElement();
})
);
export default onElementReady;
// in your app
import onElementReady from './onElementReady';
const $someElement = document.querySelector('.some-className');
onElementReady($someElement)
.then(() => {
// your element is ready
}
plain js and promises
:
var onElementReady = function($element) {
return new Promise((resolve) => {
var waitForElement = function() {
if ($element) {
resolve($element);
} else {
window.requestAnimationFrame(waitForElement);
}
};
waitForElement();
})
};
var $someElement = document.querySelector('.some-className');
onElementReady($someElement)
.then(() => {
// your element is ready
});
DOMで既にレンダリングされるまでタイムアウトを設定することで、DOMが既に存在するかどうかを確認できます。
var panelMainWrapper = document.getElementById('panelMainWrapper');
setTimeout(function waitPanelMainWrapper() {
if (document.body.contains(panelMainWrapper)) {
$("#panelMainWrapper").html(data).fadeIn("fast");
} else {
setTimeout(waitPanelMainWrapper, 10);
}
}, 10);
Jamie Hutberの答えを少し改善したものです
const checkElement = async selector => {
while ( document.querySelector(selector) === null) {
await new Promise( resolve => requestAnimationFrame(resolve) )
}
return document.querySelector(selector); };
非常に簡単です-キャンバスを作成するまでこの関数を呼び出さないでください(つまり、click
ハンドラー内で呼び出します)。