質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

setInterval を使って増加減少のプログラムを作りましたがどうしてもバグが起きてしまいます。。。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,138

space_sss

score 73

下記のようなプログラムを組みました。
内容関しては数字の書いてあるものをチェックしたりすると数値が増加したり
はずすと現象したりするプログラムです。
今回困っていることが
例えば10000のチェックボックスをダブルクリックなどするとバグってしまいます。
バグの内容といたしましては
数字が加算された数値になる前に他のチェックボックスにクリックすると
中途半端な数字で止まってしまい場合によっては同じ数字をいったりきたりしてしまいます。
おそらく
setInterval
が停止していないのではないのかとは思いますが色々試してみましたがどれもうまくいきませんでした。

この対処法などはありませんでしょうか?
それともそもそもの組み方を見直すべきでしょうか?
ajaxに関しては、これ以降のプログラムで使う予定なので出来ればそのままにしておきたいです。
ajaxの返り値は単純にチェックボックスやラジオボタンの数値を足した合計値が返ってくるだけのものになります。
どうか宜しくお願いいたします。

<script>
var num,id,tgt,cnt;
num=0;
cnt=300;
function loop_set(tgt){
    if(num<tgt){
        id=setInterval(function(){
            if(num<=tgt){
                $('#count').html(num);
                num+=Math.floor(tgt/cnt);
            }else{
                $('#count').html(tgt);
                num=tgt;
                clearInterval(id);
            }
        },1);
    }else{
        id=setInterval(function(){
            if(num>=tgt){
                $('#count').html(num);
                if(cnt>tgt){
                    num-=Math.floor(num/30);
                    if(num<30){
                        $('#count').html(tgt);
                        num=tgt;
                        clearInterval(id);
                    }
                }else{
                    num-=Math.floor(tgt/cnt);
                }
            }else{
                $('#count').html(tgt);
                num=tgt;
                clearInterval(id);
            }
        },1);
    }
};
function pay(){// Ajax通信
    pay_01 = $('input[name="pay_01"]:checked').val();
    var pay_02=[];
        $('[name="pay_02[]"]:checked').each(function(){
            pay_02.push($(this).val());
        });
    $.ajax({
        url : 'inc/calculation.php',
        type : 'post',
        dataType : 'json',
        data : {
            pay_01 : pay_01,
            pay_02 : pay_02
        }
    })
    //受信部分
    .done(function(response){
        tgt=response['tgt'];//送ったデータのすべてが足された数値が戻ってきます。
        loop_set(tgt);
    })
    .fail(function() {//エラーが起きた場合
        alert('通信失敗')
    })
}
</script>
<ul>
    <li><input type="radio" onClick="pay()" name="pay_01" value="10000" />10000</li>
    <li><input type="radio" onClick="pay()" name="pay_01" value="20000" />20000</li>
</ul>
<ul>
    <li><input type="checkbox" onClick="pay()" name="pay_02[]" value="500" />500</li>
    <li><input type="checkbox" onClick="pay()" name="pay_02[]" value="10000" />10000</li>
</ul>
<div id="count">
0
</div>


inc/calculation.phpの詳細は下記になります。

<?php
$tgt=0;
if(isset($_POST['pay_01'])){
    $tgt+= htmlspecialchars($_POST['pay_01']);
}
if(isset($_POST['pay_02'])){
    foreach($_POST['pay_02'] as $check) {
        $tgt+=htmlspecialchars($check);
    }
}
header('Content-type: application/json charset=utf-8');
$calculation=array('tgt' => $tgt);
echo json_encode($calculation);
?>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Kosuke_Shibuya

    2016/12/03 11:46

    inc/calculation.php の内容を追記してください。計算処理の内容や、レスポンスの形式がわからないとデバッグできないから言っているんですよ。修正するとかしないの問題じゃありません。

    キャンセル

  • space_sss

    2016/12/03 11:51

    phpに関しては今その部分を抜き出して記載するつもりでしたがお時間かかってしまい申し訳ありません。

    キャンセル

  • space_sss

    2016/12/03 11:57

    たった今記載いたしました。

    キャンセル

回答 1

checkベストアンサー

+2

else 以下には絶対に入らないから、if(num<tgt){} の処理は無駄。
描画の回数を減らす。/ 300 となると、1000分の1秒ごとに300回描画するので。
描画のインターバルを増やす。1000分の1秒だとクライアントのマシンのスペックによってもたつく。
冗長な処理を簡素化。
obClick はレガシーコードなので、削除。on('click', function(){})に置き換え。

<!DOCTYPE HTML>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #count {
                width: 200px;
                border: 1px solid #CCC;
                padding: .5em;
                text-align: right;
            }
        </style>
    </head>
    <body>
        <form action="">
            <ul>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="10000" />
                        10000
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="20000" />
                        20000
                    </label>
                </li>
            </ul>
            <ul>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="500" />
                        500
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="10000" />
                        10000
                    </label>
                </li>
            </ul>
        </form>

        <div id="count">
            0
        </div>

        <script type="text/javascript" src="//code.jquery.com/jquery-3.1.1.min.js"></script>
        <script>
            function loop_set(tgt) {

                // 初期値
                var num = 0;

                //描画回数
                var refreshCount = 23; // 素数の方が演出的にいいかも

                //描画インターバル
                var interval = 10;

                var id = setInterval(function () {

                    if (num <= tgt) {
                        num += Math.floor(tgt / refreshCount);
                    } else {
                        num = tgt;
                        clearInterval(id);
                    }
                    $('#count').text(num);

                }, interval);
            }

            function pay() {// Ajax通信
                $.ajax({
                    url: 'inc/calculation.php',
                    type: 'post',
                    dataType: 'json',
                    data: $("form").serialize()
                }).done(function (response) {
                    loop_set(response['tgt']);
                }).fail(function () {
                    alert('通信失敗');
                });
            }

            $('.item').on('click', function () {
                pay();
            });
        </script>
    </body>
</html>

htmlspecialcharsを使うのは不適切。

<?php

function calculate(array $arr)
{
    $sum = 0;
    foreach ($arr as $val) {
        if (is_array($val)) {
            $sum += calculate($val);
        } else {
            $sum += $val;
        }
    }
    return $sum;
}

header('Content-type: application/json');
$calculation = array('tgt' => calculate(filter_input_array(INPUT_POST)));
echo json_encode($calculation);

追記

減算方向の処理でも結構簡素化できました。

<!DOCTYPE HTML>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #count {
                width: 200px;
                border: 1px solid #CCC;
                padding: .5em;
                text-align: right;
            }
        </style>
    </head>
    <body>
        <form action="">
            <ul>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="10000" />
                        10000
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="20000" />
                        20000
                    </label>
                </li>
            </ul>
            <ul>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="500" />
                        500
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="10000" />
                        10000
                    </label>
                </li>
            </ul>
        </form>

        <div id="count">
            0
        </div>

        <script type="text/javascript" src="//code.jquery.com/jquery-3.1.1.min.js"></script>
        <script>

            // 初期値
            var num = 0;

            function loop_set(tgt) {

                //描画回数
                var refreshCount = 37;

                //描画インターバル
                var interval = 10;

                // 増減
                var diff = tgt - $('#count').text();

                var id = setInterval(function () {

                    if ((diff > 0 && num <= tgt) || (diff < 0 && num > tgt)) {
                        num += Math.floor(diff / refreshCount);
                    } else {
                        num = tgt;
                        clearInterval(id);
                    }
                    $('#count').text(num);

                }, interval);
            }

            function pay() {// Ajax通信
                $.ajax({
                    url: 'inc/calculation.php',
                    type: 'post',
                    dataType: 'json',
                    data: $("form").serialize()
                }).done(function (response) {
                    loop_set(response['tgt']);
                }).fail(function () {
                    alert('通信失敗');
                });
            }

            $('.item').on('click', function () {
                pay();
            });
        </script>
    </body>
</html>

追記

<!DOCTYPE HTML>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #count {
                width: 200px;
                border: 1px solid #CCC;
                padding: .5em;
                text-align: right;
            }
        </style>
    </head>
    <body>
        <form action="">
            <ul>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="10000" />
                        10000
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="radio" name="pay_01" value="20000" />
                        20000
                    </label>
                </li>
            </ul>
            <ul>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="500" />
                        500
                    </label>
                </li>
                <li>
                    <label>
                        <input class="item" type="checkbox" name="pay_02[]" value="10000" />
                        10000
                    </label>
                </li>
            </ul>
        </form>

        <div id="count" data-value="0">
            0
        </div>

        <script type="text/javascript" src="//code.jquery.com/jquery-3.1.1.min.js"></script>
        <script>
            function number_format(num) {
                return num.toLocaleString();
            }

            function loop_set(tgt) {

                //描画回数
                var refreshCount = 37;

                //描画インターバル
                var interval = 10;

                // 変更前の値
                var num = parseInt($('#count').attr('data-value')) + 0;

                // 増減
                var diff = tgt - num;

                var id = setInterval(function () {

                    if ((diff > 0 && num <= tgt) || (diff < 0 && num > tgt)) {
                        num += Math.floor(diff / refreshCount);
                    } else {
                        num = tgt;
                        clearInterval(id);
                    }
                    $('#count').text(number_format(num))
                            .attr('data-value', num);

                }, interval);
            }

            function pay() {// Ajax通信
                $.ajax({
                    url: 'inc/calculation.php',
                    type: 'post',
                    dataType: 'json',
                    data: $("form").serialize()
                }).done(function (response) {
                    loop_set(response['tgt']);
                }).fail(function () {
                    alert('通信失敗');
                });
            }

            $('.item').on('click', function () {
                pay();
            });
        </script>
    </body>
</html>

追記

<script>
            function number_format(num) {
                return num.toLocaleString();
            }

            function loop_set(tgt) {

                //描画回数
                var refreshCount = 37;

                //描画インターバル
                var interval = 10;

                // 変更前の値
                var num = parseInt($('#count').attr('data-value')) + 0;

                // 増減
                var diff = tgt - num;

                var id = setInterval(function () {

                    if ((diff > 0 && num <= tgt) || (diff < 0 && num > tgt)) {
                        num += Math.floor(diff / refreshCount);
                    } else {
                        num = tgt;
                        clearInterval(id);
                    }
                    $('#count').text(number_format(num))
                            .attr('data-value', num);

                }, interval);
            }

            function pay() {// Ajax通信
                if ($("form").serialize() === '') {
                    loop_set(0);
                    return;
                }
                $.ajax({
                    url: 'inc/calculation.php',
                    type: 'post',
                    dataType: 'json',
                    data: $("form").serialize()
                }).done(function (response) {
                    loop_set(response['tgt']);
                }).fail(function () {
                    alert('通信失敗');
                });
            }

            $('.item').on('click', function () {
                pay();
            });

        </script>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/04 01:06

    function pay(){// Ajax通信
    if($("#calculation_pay").serialize()){
    $.ajax({
    url: 'inc/calculation.php',
    type: 'post',
    dataType: 'json',
    data: $("#calculation_pay").serialize()
    }).done(function(response){
    loop_set(response['tgt']);
    }).fail(function(){
    alert('通信失敗');
    });
    }else{
    tgt=0;
    loop_set(tgt);
    }
    }
    一応無理やりですがこういったふうにpayの関数に記載しましたがこれはあまりにも雑な気がしまして…

    キャンセル

  • 2016/12/04 01:15

    追記しておきましたよ。
    if で大きく囲んでしまうと入れ子が深くなって可読性が悪くなっちゃいますね。

    キャンセル

  • 2016/12/04 05:19

    ありがとうございます!早速参考にさせていただきました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • PHPに関する質問
  • setInterval を使って増加減少のプログラムを作りましたがどうしてもバグが起きてしまいます。。。