jvascript プログラミングです


Img 要素が複数あり
画像の切替を行います

X1 X2 X3

切替は Xにローディング用画像(以下IMG_L)をセットし
画面に表示されていないYに新画像(以下IMG_Nx)をセットし
YのonLoadイベントで XにIMG_Nxをセットしています
YはXと同じ数だけ用意してあります

以上を前提条件として
次のように切替処理を行います

X1 開始
X1 終了前に
X2 開始

X1 終了
X2 終了前に
X3 開始

現状だと次の順番で表示されます
 X1 IMG_L
 X1 IMG_N1
 X2 IMG_L
 X2 IMG_N2
 X3 IMG_L
 X3 IMG_N3

これを
 X1 IMG_L
 X2 IMG_L
 X1 IMG_N1
 X3 IMG_L
 X2 IMG_N2
 X3 IMG_N3
というシーケンスに表示されるよう組みなおすことは
可能でしょうか?

IMG_Lは キャッシュしてあるので
読み込み速度は一瞬です
対して IMG_Nxは 大きな画像サイズで
読み込みに時間がかかります

ブラウザは IEをつかっています

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2007/12/25 17:07:14
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答2件)

id:t_shiono No.1

回答回数256ベストアンサー獲得回数22

ポイント35pt

ご期待の動作がよく分からないので、確認させてください。

imgタグがX1として表現しているのですよね?

それで各タグごとに、まずローディング中画像を表示して、高精度の画像をロード後置き換えるということでよいのですよね?

そこで、ローディング画像の表示順を指定する必要はあるのでしょうか?

閲覧直後 :X1(L)、X2(L)、X3(L)

N1ロード時:X1(N1)、X2(L)、X3(L)

N2ロード時:X1(N1)、X2(N2)、X3(L)

N3ロード時:X1(N1)、X2(N2)、X3(N3)

ではだめなのでしょうか?

何か理由がありだめだということだと思うのですが、

X1、X2、X3はページロード直後から表示されているはずなので、すべてを含んだ時系列は次のような感じでよいでしょうか?

閲覧直後  :X1(L)、X2(*)、X3(*)

タイミング1:X1(L)、X2(L)、X3(*)

N1ロード時 :X1(N1)、X2(L)、X3(*)

タイミング2:X1(N1)、X2(L)、X3(L)

N2ロード時 :X1(N1)、X2(N2)、X3(L)

N3ロード時:X1(N1)、X2(N2)、X3(N3)

※ *は何も表示しない状態など

この場合、タイミング1とタイミング2をどのように作成するかが問題となります。

この方法の1つはタイマーの利用だと思います。

X1のLのロード完了時にタイマーを起動させて、タイマーの時間経過後にX2にLを表示させるとよいです。

タイミング2も同様にN1のロードが完了し、X1に設定した時点でタイマーを設定して、一定時間後にLをX3に設定すればよいです。

それで、ここで問題となるのは、N1のロードとX1で設定したタイマーのトリガーとどちらが先に来るかは分からないという点です。絶対にこの時系列を守る必要があるのであれば、これは結構面倒です。

つまり、N1のロードが先に終わってから、タイマーが発生することとなった場合、N1のロードのハンドラでは、設定できません。なぜなら、X2にLをまだ設定していないからです。

と、このようなことをきちんと検討する必要が出てきます。


そこで、一番分かりやすいのは、画像の設定をすべてタイマー駆動にしてしまうのが、よいのではないかと思います。ここまでやると、何でも設定できるのではないかと思います。

概観ですが、

var state = 0;
var isLoadN1, isLoadN2, ...;

function onTimer() {
  if (state == 0) {
    X1にLを設定
     state = 1;
  } else if (state == 1) {
    X2にLを設定
     state = 2;
  } else if (state == 2) {
    if (isLoadN1) {
      X1にN1を設定
       state = 3;
    }
  } else if (state == 3) {
    X3にLを設定
     state = 4;
  } else if (state == 4) {
    if (isLoadN2) {
      X2にN2を設定
       state = 5;
    }
  } else if (state == 5) {
    if (isLoadN3) {
      X3にN3を設定
       タイマーの停止
    }
  }
}

<body onLoad="onTimerを繰り返し呼び出すタイマーを起動">

<img id="Y1" onLoad="isLoadN1を真に"/>
<img id="Y1" onLoad="isLoadN1を真に"/>
<img id="Y1" onLoad="isLoadN1を真に"/>

いかがでしょうか?

id:you_got

ご回答ありがとうございます。

接続できなかったため、返事が遅くなってしまいました。すみません。

>mgタグがX1として表現しているのですよね?

そうです。

>そこで、ローディング画像の表示順を指定する必要はあるのでしょうか?

あります。

X1・X2・X3 はあらかじめ 画像が表示されています。

切り替えが生じるたびに、切り替えが生じた要素のみ ローディング画像を表示したいのです。

タイマーを使うのも 今回の目的ではそぐいません。

切り替え要求が発生したらすぐに、ローディング画像を表示したいためです。


質問の仕方が悪かったようです。

X1読み込み中に X2の切り替えが発生したとき

X1が読み込み終わる前に 

X2の画像を ローディング中画像に切り替えることは可能でしょうか?

2007/12/24 14:32:01
id:t_shiono No.2

回答回数256ベストアンサー獲得回数22

ポイント35pt

ご希望の動作の件、了解しました。

全然、検討違いでしたね。すいません。

一応、確認ですが、

1.X1、X2、X3になんらかの画像が表示されている

2.X1の画像を差し替えるイベントが発生

3.X1のsrcにローディング画像を設定

4.Y1にX1の差し替え画像を設定

5.Y1のonLoadでX1のsrcを差し替え

というのが基本動作で、今回差し替え画像が大きくロードに時間がかかるため、

4と5の間にX2の画像を差し替えるイベントが発生する可能性がある。

現状では、X2の差し替えイベントが発生した時点で、X2のsrcをローディング画像に書き換えても表示は変わらなく、X1の差し替えが終了してからでないと、X2のローディング画像が表示されない

ということでよろしいですよね?


差し替えのイベントがどんなものか分からないですが、そのイベント内でXnのsrcをローディング画像の変えてあげれば、動作するような気がするんですが、駄目なんですよね?

function loadImg(n) {
  x = document.getElementById('X' + n);
  x.src = ローディング画像
  y = document.getElementById('Y' + n);
  y.src = 読み込む画像
}
function changeImg(n) {
  x = document.getElementById('X' + n);
  y = document.getElementById('Y' + n);
  x.src = y.src;
}

<img id="X1" src="..."/>
<img id="Y1" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(1);">change1</a>

<img id="X2" src="..."/>
<img id="Y2" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(3);">change2</a>

<img id="X3" src="..."/>
<img id="Y3" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(3);">change3</a>


あとは、ローディング用のスレッドのようなものを作成してあげるとかで対処できるかと思います。

タイマーは却下とのことですが、

var imgStates = Array(0, 0, 0);

function loadImg(n) {
  imgStates[n - 1] = 1;
}

function onTime() {
  for (var i = 1; i <= 3; ++i) {
    if (imgStates[i - 1] > 0) {
      img = document.getElementById('X' + i);
      if (img.src != ローディング画像) {
        img.src = ローディング画像
      }
    }
  }
}

<img id="X1" src="..."/>
<img id="Y1" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(1);">change1</a>

<img id="X2" src="..."/>
<img id="Y2" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(3);">change2</a>

<img id="X3" src="..."/>
<img id="Y3" src="..." style="display: none" onLoad="changeImg(1)"/>
<a href="#" onClick="loadImg(3);">change3</a>

と思ったのですが、あまり変わらないですね。

一応書いてみたので、載せておきますが、後者で動くなら前者で動くきがします。



ひょっとするとブラウザ依存してしまうかもしれませんね。

画像の読み込みをマルチスレッドで走らせられるかというあたりです。

JavaScriptでsrcを書き換えた際に、ブラウザが画像を並列して読みにいくかどうか。

仮に既にロードされていたとしても、一瞬でロードが完了するとしても、画像の読み込みは順次処理しかしてくれないとすると、一筋縄じゃいかないかもですね。

もし、このような症状であれば、ちょっとトリッキーですが、ローディング画像用のimgタグを常に用意しておいて、X1のsrcの書き換えの変わりに、このimgタグをX1と完全に重なる位置に表示させるということで、同様のことができるかもしれません。


どれもテストしたわけではないのですが、参考になれば。

id:you_got

はい そのとおりです

最初の質問の仕方が 不適切でもうしわけありません

>画像の読み込みをマルチスレッドで走らせられるかというあたりです。

そうなんです。

そこが問題でして ふつうにsrcを指定すると 順次で読み込んでしまいます。

>X1と完全に重なる位置に表示させるということで、同様のことができるかもしれません。

やっぱりそれが 最適解かもしれませんね。

ありがとうございます。

2007/12/24 17:32:04
  • id:t_shiono
    またまた、未確認で恐縮ですが、

    期待は薄いですが、画像のロードの仕方を変更するのはどうですか?
    JavaScript中で次のような感じで行う方法です。

    // 読み込み用Imageオブジェクトの配列
    var img = Array(null, null, null);

    // 読み込み中かどうかのフラグの配列
    var states = Array(0, 0, 0);

    function loadImg(n) {
    img[n - 1] = new Image();
    img[n - 1].src = 大きな画像;
    states[n - 1] = 1;
    x = document.getElementById('X' + n);
    x.src = ローディング画像
    }

    // タイマーで読み込み中状態かつ、読み込み完了のものをチェック
    function onTimer() {
    for (var i = 0; i < 3; ++i) {
    if (states[i] > 0 && img[i].complete) {
    states[i] = 0;
    x = document.getElementById('X' + i);
    x.src = img[i].src;
    }
    }
    }

    以下省略・・・・
  • id:you_got
    うーん
    だめでした

    いろいろと考えていただいてありがとうございます。
    違うアプローチを検討してみます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません