顯示具有 javascript 標籤的文章。 顯示所有文章
顯示具有 javascript 標籤的文章。 顯示所有文章

2025-06-08

【jQuery】jQuery + CSS 多個 checkbox 勾選

 
<html>
<head>
<title>checkbox lab</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script>
// chkAll 點擊事件
function checkAll() {
    var isChecked = $('#chkAll').prop('checked');
    // 更新所有 nameCheckbox 的狀態
    $('.nameCheckbox').prop('checked', isChecked).trigger('change');
}


// 更新 chkAll 狀態
function updateChkAll() {
    var totalCheckboxes = $('.nameCheckbox').length;
    var checkedCheckboxes = $('.nameCheckbox:checked').length;
    var $chkAll = $('#chkAll');
               
    if (checkedCheckboxes === 0) {
        // 全部未選中
        $chkAll.prop('checked', false);
        $chkAll.removeClass('partial');
    } else if (checkedCheckboxes === totalCheckboxes) {
        // 全部選中
        $chkAll.prop('checked', true);
        $chkAll.removeClass('partial');
    } else {
        // 部分選中
        $chkAll.prop('checked', false);
        // 關鍵修改:部分選中時保持 checked 但變灰色
        $chkAll.prop('checked', true).addClass('partial');
    }
}
</script>
<style type="text/css">
#chkAll {
    margin-bottom: 10px;
    font-size: 10px;
}
/* 部分選中時的灰色打勾 */
#chkAll.partial {
    accent-color: gray;  /* 現代瀏覽器 */
    filter: grayscale(50%) opacity(80%);  /* 舊瀏覽器備用 */
}
</style>
</head>
<body>
<center>
<form name="frmInput" id="frmInput" method="post" action="func.php">
<input type="hidden" name="act" value="input" />
<table border="1">
	<tr>
		<th nowrap="nowrap"><input type="checkbox" id="chkAll" onchange="checkAll()" />全選</th>
		<th nowrap="nowrap">姓名</th>
	</tr>
	<tr>
		<td><input type="checkbox" class="nameCheckbox" id="chk1" onchange="updateChkAll()" /></td>
		<td>張三</td>
	</tr>
	<tr>
		<td><input type="checkbox" class="nameCheckbox" id="chk2" onchange="updateChkAll()" /></td>
		<td>李四</td>
	</tr>
	<tr>
		<td><input type="checkbox" class="nameCheckbox" id="chk3" onchange="updateChkAll()" /></td>
		<td>王五</td>
	</tr>
</table>
</form>
</center>
</body>
</html>
 

2024-07-13

【網頁程式】土砲打造 -- 依數個地點距離由近至遠規劃行程導航

參考資料 ----


當我們要前往數個地點,想依距離由近至遠排序,規劃開車行程,可以請 Google Cloud 服務,不過這是要收費的。

行程含目的地的停靠點在 10 個點以下,是一種費率,11(含)個點以上則會收較高的費用。

本筆記是自行計算及排序停靠點(注意,還是要收費的)。


您可以服務全開,不過我只使用其中 2 項 -- 取得地理位置(經緯度)導航







建立 GMap 類別
 
<?php 
date_default_timezone_set('Asia/Taipei');
  
// 用來查詢地址的經、緯度
class GMap {
    function getPageData($url) { 
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);  
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect: '));
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_NOBODY, false);
        curl_setopt($ch, CURLOPT_FILETIME, true);
        curl_setopt($ch, CURLOPT_REFERER, $url); 
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 4);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
        $result['data'] = curl_exec($ch);
        curl_close($ch);
          
        return $result;
    }
    
    // 初始化 apikey 金鑰 
    function __construct() {
        $this->apikey = '向 Google map 申請 apikey';
    } 


    // 從 google map 取得地址經緯度
    public function getLngLat($addr='',$sDebug='') {
        $apikey = $this->apikey;
        $url = "https://maps.googleapis.com/maps/api/geocode/json?address=$addr&key=$apikey";
        $geocode = $this->getPageData($url);
        if($sDebug=='debug')
            var_dump($geocode);

        if(isset($geocode['data'])) {
            if(!$geocode["data"])
                // 當 Google map 解析不了時,回應 經/緯度值都是 -1 的虛擬經緯度
                $geocode = '{"results":[{"geometry":{"location":{"lat":-1,"lng":-1}}}]}';
            else
                $geocode = $geocode['data'];
        } else
            // 當 Google map 解析不了時,回應 經/緯度值都是 -1 的虛擬經緯度
            $geocode = '{"results":[{"geometry":{"location":{"lat":-1,"lng":-1}}}]}';

        $output = json_decode($geocode); 
        $latitude = $output->results[0]->geometry->location->lat;
        $longitude = $output->results[0]->geometry->location->lng; 
     
        return array('lat'=>$latitude,'lng'=>$longitude);
    }
}
?>
 


getroute.php,用來依次計算起點至每個目的地的距離,取最近的地址做為下個停靠點,並再以這地址做為下次計算的起點
 
<?php
// 切換至 https
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === "off") 
{
    $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $location);
    exit;
}

include('gmap.php');

class MyDest {
    public $addr;
    public $len = 0;
    public $lng = -1;
    public $lat = -1;
  
    function __construct($aa) {
        $this->addr = $aa;
    }
}


if(isset($_GET['lat'])) {
    // 接收到起點 經/緯 度
    // $sLat = 22.612058525444247;    // 測試用
    // $sLng = 120.3142669919977;   // 測試用
    $sLat = $_GET['lat'];
    $sLng = $_GET['lng'];
    

    $aDest = array();    // 存放上傳的目的地
    $aSort = array();    // 排序後的目的地

    $gmap = new GMap();
    
    if(isset($_GET['dest1'])) {
        $obj = new MyDest($_GET['dest1']);
        $fLngLat = $gmap->getLngLat($obj->addr);    // 上車地點經緯度
        $obj->lat = $fLngLat["lat"];    // 緯度
        $obj->lng = $fLngLat["lng"];    // 經度
        array_push($aDest, $obj);
    }
    if(isset($_GET['dest2'])) {
        $obj = new MyDest($_GET['dest2']);
        $fLngLat = $gmap->getLngLat($obj->addr);    // 上車地點經緯度
        $obj->lat = $fLngLat["lat"];    // 緯度
        $obj->lng = $fLngLat["lng"];    // 經度
        array_push($aDest, $obj);
    }
    if(isset($_GET['dest3'])) {
        $obj = new MyDest($_GET['dest3']);
        $fLngLat = $gmap->getLngLat($obj->addr);    // 上車地點經緯度
        $obj->lat = $fLngLat["lat"];    // 緯度
        $obj->lng = $fLngLat["lng"];    // 經度
        array_push($aDest, $obj);
    }
    if(isset($_GET['dest4'])) {
        $obj = new MyDest($_GET['dest4']);
        $fLngLat = $gmap->getLngLat($obj->addr);    // 上車地點經緯度
        $obj->lat = $fLngLat["lat"];    // 緯度
        $obj->lng = $fLngLat["lng"];    // 經度
        array_push($aDest, $obj);
    }
    if(isset($_GET['dest5'])) {
        $obj = new MyDest($_GET['dest5']);
        $fLngLat = $gmap->getLngLat($obj->addr);    // 上車地點經緯度
        $obj->lat = $fLngLat["lat"];    // 緯度
        $obj->lng = $fLngLat["lng"];    // 經度
        array_push($aDest, $obj);
    }

    while(count($aDest)>0) {
        foreach($aDest as &$val) {    // 注意:$val 前面有 &
            // 計算【各目的地】距離【起點】的長度
            $url = "https://maps.googleapis.com/maps/api/directions/json?origin=$sLat,$sLng&destination=".urlencode($val->addr)."&key=$apiKey";
            
            // 目的地 destination 參數也可以是經緯度
            $url = "https://maps.googleapis.com/maps/api/directions/json?origin=$sLat,$sLng&destination=".urlencode($val->lat).",".urlencode($val->lng)."&key=$apiKey";
            
            // 若希望路線避開上高速公路, 則可加 avoid=highways 參數
            $url = "https://maps.googleapis.com/maps/api/directions/json?origin=$sLat,$sLng&destination=".urlencode($val->addr)."&avoid=highways&key=$apiKey";
            // 此外, 還可避開 ----
            // tolls:避開收費路段
            // highways:避開高速公路
            // ferries:避開渡輪
            // indoor:避開室內路線(主要用於步行路線)
            
            // 初始化 cURL
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $response = curl_exec($ch);
            curl_close($ch);
    
            // 解析 json 響應
            $data = json_decode($response, true);
            if ($data['status']=='OK') {
                $val->len = $data['routes'][0]['legs'][0]['distance']['value'];
            } else {
                $val->len = -1;
            }
            unset($val);
        }

        // 使用 usort 函數排序陣列,根據 $a 屬性值從小到大排序
        usort($aDest, function($a, $b) {
            return $a->len <=> $b->len;
        });
        // 排序後的第一個物件就是 距離最短的地址
        $minObj = $aDest[0];
        // print_r($aDest);
        array_push($aSort, ['addr' => ($minObj->addr)]);
        
        // 這個地址做為起點
        $sLat = $minObj->lat;
        $sLng = $minObj->lng;
        array_splice($aDest, 0, 1);
    }
    echo json_encode($aSort);   // 回傳依距離排序後的停靠點及目的地
}

?>
 


navi.php,將排好的順序丟給 GoogleMap 導航。
 
<?php
// 切換至 https
if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === "off") 
{
    $location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $location);
    exit;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html style="height:100%;">
<head>
    <meta charset="utf-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<br />
<button onclick="startNavigation()" style="font-size:40pt;">巡航</button><br />
<span  style="font-size:40pt;">提醒:在 Android Chrome 開啟本網頁</span><br />
<br />
<br />
<script>
function startNavigation() {
    var aRoute = [
        "高雄市苓雅區四維三路2號",
        "高雄市前鎮區中華五路789號",
        "高雄市鼓山區濱海二路1號",
        "高雄市左營區博愛二路777號",
        "高雄市左營區高鐵路107號"
    ];

    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
            var latitude = position.coords.latitude;    // 緯度
            var longitude = position.coords.longitude;  // 經度
            var str = "https://您自己的網址/getroute.php?lat="+latitude+"&lng="+longitude+"&dest1="+aRoute[0]+"&dest2="+aRoute[1]+"&dest3="+aRoute[2]+"&dest4="+aRoute[3]+"&dest5="+aRoute[4];
            // alert('str = '+str);
            // return;

            var destinations = new Array();
            $.getJSON(str, function(res) {
                // alert("res = "+res);
                // 這段是從 client 端向 server 請求查詢
                // server 回傳 json 型態的陣列
                // 陣列內的元素是 addr
                res.forEach(function(element) {
                    destinations.push(element.addr);
                });
                var waypoints = destinations.map(function(destination) {
                    // Google map 規定停靠點以【|】字元分隔
                    // 將 5 個地點以【|】字元分隔
                    return encodeURIComponent(destination);
                }).join("|");
                destination = waypoints.split('|').pop();   // 取得最後【|】右邊的字串做為目的地
                waypoints = waypoints.slice(0, waypoints.lastIndexOf('|')); // 取得最後【|】的左邊字串做為停靠點

                // 構建導航 URL
                var mapsURL = "https://www.google.com/maps/dir/?api=1&origin=" + latitude + "," + longitude + "&destination=" + destination + "&waypoints=" + waypoints + "&travelmode=driving";
                // alert(mapsURL);
                // return;

                // 跳轉到 Google Maps
                window.location.href = mapsURL;
            });
            // return;
            

            
        }, function(error) {
                alert("無法取得地理位置: " + error.message);
            }
        );
    } else {
        alert("瀏覽器不支援地理定位功能。");
    }
}
</script>
<br />
<br />
</body>
</html>

 


排序後,程式呼叫 Android 手機上的 Google Map app 進行導航。

第一次執行這個網頁程式時,會詢問是否同意瀏覽器存取你的地理位置,選擇同意且記住您的選擇,之後執行就不會再跳出詢問視窗了。

測試 Google Chrome、Firefox、Microsoft Edge 這幾個主流瀏覽器
Chrome 效果最佳,直接啟動 Google Map,畢竟都是自家的產品;
Edge 雖可呼叫 Google Map,但詢問視窗一直開著,不會自動關閉
Firefox 最差,啟動了 Google Map,但要導航的地址全不見了!!



另一個有趣的發現:
如果只單純導航前往一個地點,Google Map 並不管目的地是否與您的行車方向順向,只要抵達目的地附近,Google Map 就認為任務完成了。ex:出發點是高雄市中山大學,目的地是高雄女中(雄女),雄女的對面是國軍英雄館,Google 導航只要帶您到國軍英雄館,導航就結束了。
但當設了多個停靠點時,Google Map 就會使命必達,規劃的路線即使繞一圈也會帶您順向抵達雄女。

然後...老人家又好奇了...這個網頁程式在 iPhone 上打開會是什麼結果?
答案是:在 Safari 直接 Deny!! 不給開

2025


相關筆記 ----






2022-12-17

【WEB程式】Apache ECharts -- 圓餅圖(Pie Chart)

參考資料 ----

Apache ECharts 教程


再來試試 圓餅圖

 
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Pie Chart</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/dist/echarts.min.js"></script>
    <!-- 引入 vitage 樣式 js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/theme/vintage.js"></script>
</head>
<body>
    <!-- 為 ECharts 準備一個具備大小(寬高)的 DOM -->
    <div id="main" style="width:600px; height:400px;"></div>
    
    <script type="text/javascript">
        <?php
            $aExam = [  ['name' => '初等考試', 'value' => 7],
                        ['name' => '大學指考', 'value' => 15],
                        ['name' => '高考護理師', 'value' => 26],
                        ['name' => '國中會考', 'value' => 1],
                        ['name' => '機車駕照', 'value' => 17],
                        ['name' => '汽車駕照', 'value' => 32]
                    ];

            // 如果是從資料庫撈出來的, 做法如下:
            // $aExam = array();
            // ...
            // ...
            // foreach($rs => $row)
            //    array_push($aExam, ['name' => $row['考試科目'], 'value' => $row['下載次數']]);


            echo 'var aExam = '.json_encode($aExam,JSON_NUMERIC_CHECK).";\n";    // 將 PHP 陣列轉出成 javascript 陣列
                                                                                   // 要注意 json_encode() 的第 2 個參數
                                                                                   // 若沒有第 2 個參數, json_encode 預設會轉出成 字串 陣列, 每個數字會以雙引號包住
                                                                                   // 這樣會造成圖表的顯示出現無法預期的結果,ex: 線亂畫、座標點錯誤...
        ?>
        // 基於準備好的 DOM,初始化 echarts 實體
        var myChart = echarts.init(document.getElementById('main'), 'vintage');    // 第 2 個參數 是 樣式 選項: 預設, light(內建), dark(內建), vintage, macarons, infographic, shine, roma
                                                                                   // 如果沒有 "樣式" 參數,就是預設樣式
                                                                                   // light樣式 與 預設樣式 的差異在 light 的顏色比預設更淡
                                                                                   // 若要採用不同樣式, 除了內建的 light/dark,其他樣式則上面也要引入相應的 js
 
        // 指定圖表的配置項和數據
        var option = {
                        title: {
                                text: '考試下載比例',
                                left: 'center'
                            },
                        tooltip: {
                                    trigger: 'item'
                                },
                        legend: {
                                    orient: 'vertical',
                                    left: 'left'
                                },
                        series: [{
                                    name: '考試科目',
                                    type: 'pie',
                                    data: aExam,
                                },
                                ],
                    };
 
        // 使用剛才指定的配置項和數據顯示圖表。
        myChart.setOption(option);
    </script>
</body>
</html>

 



滑鼠移至某個考試科目時,就會顯示該科考試的下載數,這是參數 tooltip 的效果。
點擊左上角(legend 區域) 的考試科目,該科考試的色塊就會隱藏,再點擊一次會再出現。


相關筆記 ----


2022-11-20

【jQuery】簡單好用的表格元件 EasyUI datagrid

參考資料 ----


===== 2026.03.28 =====
這幾天不知道什麼原因,無法連線官網,導致 datagrid 無法顯示,在緊急尋找應變方法時發現大陸有個 "鏡像站"(只是不確定是不是官方授權),趕緊下載元件以防日後官網真的掛了時,還能把元件改放在自己的網站裡;另外,在元件的 demo 頁,官網怪怪的,大陸的鏡像站反而是正常的。


EsayUI datagrid 元件可以造出功能強大又好看的表格,只要添加自己撰寫對應的程式碼,甚至可以做到直接在表格內 新增/修改/刪除 的功能;非商業用途的可用免費版。

因為我的資料來源為網站上的資料庫,所以需要 server 端的程式以回應 client 端傳來的請求,又因為只做瀏覽用,如果看倌有要在表格內直接 新增/修改/刪除 數據的需要,請自行另外研究囉~。

先到 EasyUI 下載壓縮包,解壓後,找到名為 locale 的目錄,裡面有個 easyui-lang-zh_TW.js ,這是正體中文語言檔,將它上傳至您網站指定目錄,在本例為 /js/


前端的程式 client.php
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="keywords" content="" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>datagrid demo</title>
<meta name="description" content="datagrid demo" />
<link rel="shortcut icon" href="/image/icon.png" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/icon.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/themes/color.css">
<link rel="stylesheet" type="text/css" href="https://www.jeasyui.com/easyui/demo/demo.css">
<script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="/js/easyui-lang-zh_TW.js"></script><!-- 正體中文語言包-->
</head>
<body>
    <!-- <table id="table1" class="easyui-datagrid" style="width:1000px;height:auto"   auto 表示 表格的高度自動調整 -->
    <!-- 若屬性中設了 fixColumns="true" 欄寬就被固定住了, 並且表格底部不會顯示橫向捲軸 -->
    <table id="table1" class="easyui-datagrid" style="width:100%;height:400px"<!-- 可以用 px 設定表格 寬/高, 也可以用 % 螢幕比例 -->
        url="uber_rec.php"  <!-- 指定 server 端程式 -->
        pagination="true"   <!-- 要有頁數導覽元件 -->
        rownumbers="true"   <!-- 最左邊顯示列號 -->
        noWrap="true"       <!-- 欄位內的文字不折行 -->
        striped="true"      <!-- 單偶列不同背景色 -->
        singleSelect="true" <!-- 滑鼠點擊的列會高亮度顯示 -->
        pageList=[30,60,90] <!-- 每頁顯示的列數選項 -->
        pageSize=30 >       <!-- 預設每頁顯示 30 筆記錄 -->
        <thead>
            <tr>
                <th field="欄位1" width="180">欄位1 在 datagrid 的顯示名稱</th>
                <th field="欄位2" width="200">欄位2 在 datagrid 的顯示名稱</th>
                ...
                ...
            </tr>
        </thead>
    </table>
</div>
</body>
</html>

 


server 端的程式 get_rec.php
 
<?php
// 建立 PDO
$dsn = 'mysql:dbname=資料庫名;host=localhost;charset=utf8;';
$user = 'MySQL帳戶名';
$password = '密碼';
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'); 
try
    {   // 建立資料連線
        $pdo = new PDO($dsn, $user, $password, $options);
    }
catch (PDOException $e)
    {
        echo 'connection failed';
        exit;
    }

$result = array();

// 撈記錄總筆數
$sql = "SELECT COUNT(*) cnt FROM 資料表A";
$pdoStat = $pdo->prepare($sql);
$pdoStat->execute();
$rs = $pdoStat->fetch();
$result["total"] = $rs['cnt'];   // EasyUI 規定的 jason 元素名


$iRows = isset($_POST['rows']) ? intval($_POST['rows']) : 30;   // client 端傳來的一頁要顯示的記錄筆數, 預設 30
$iOffset = isset($_POST['page']) ? (intval($_POST['page'])-1)*$iRows : 0;   // client 端傳來的一頁要顯示第幾頁, 預設 0
$sql = "SELECT * FROM 資料表A ORDER BY 排序欄位 LIMIT $iRows OFFSET $iOffset";
$pdoStat = $pdo->prepare($sql);
$pdoStat->execute();
$rs = $pdoStat->fetchAll();

$recs = array();

if(count($rs)>0)
{
    foreach($rs as $row)
    {
        array_push($recs, ['欄位1'=>$row['欄位1'], '欄位2'=>$row['欄位2'], ...]);
    }
    $result["rows"] = $recs;  // EasyUI 規定的 jason 元素名
}
echo json_encode($result);
?>
 


2022-04-04

【Javascript】在字串前(後) 補相同 字元/字串 padStart() 和 padEnd()

 
// 2017 年, Javascript 已內建此功能
// 用法:
// 變數.padStart(字串長度,重複的字元或字串);
// 變數.padEnd(字串長度,重複的字元或字串);

var str  = '123';

str2 = str.padStart(10,'0');    // 最終字串長度為 10 字, 若原字串不足 10 字, 則在原字串前補 0 → 0000000123

str3 = str.padEnd(10,'x');    // 123xxxxxxx

str4 = str.padStart(10,'ab');    // abababa123
 

2022-04-02

【Javascript】以 3rd party 函式庫 Decimal() 進行 浮點數、整數 的混合運算

參考資料 ----

JavaScript 之浮點四捨五入花式地雷

decimal.js


當 整數遇上浮點數時,其運算結果往往是預期之外,目前可借助 第三方函式庫(或該說是 類別庫?) Decimal() 來維持 浮點數 與 整數的 混合運算 的精度。

簡單來說就是將每個數都轉換為  Decimal 類別,再進行運算。

這個函式庫採 MIT 授權,並開放原始碼,放在 GitHub,去官網下載後,上傳到您網站的指定目錄,例如:/js/
 
<script src='/js/decimal.js'></script>

...
...

<script>
ii = 9999
fPlate1 = Decimal(parseInt(ii)/80);    // 124.9875
fPlate2 = Decimal(Math.floor(parseInt(sPlate)/80));    // 9999 ÷ 80 的整數 = 124
fPlate3 = fPlate1.minus(fPlate2);    // 124.9875 - 124 = 0.9875
iPlate4 = fPlate3.times(80);    // 0.9875 × 80 = 79


// 注意:上述的數字都是 Decimal 類別
// 必須轉換為 int 才能進行 switch()
switch(parseInt(iPlate4))
{
    case 1: ...
        break;
    case 2: ...
        break;
    ...
}

...
...

</script>
 



【Javascript】以遞迴方式為字串補重複字元

2017Javascript 已內建有相同功能了。
請參考 在字串前(後) 補相同 字元/字串 padStart() 和 padEnd()
 
<script>
// 建立一個遞迴函式
function pad(str,max) 
{   // 當字串 str 長度小於 max 時,就在字串左方補 0 後回傳
    str = str.toString();
    return str.length<max ? pad("0" + str, max) : str;
}

...
...

myStr = "1";
myStr = pad(myStr,4);    // 指定 myStr 補 0 後的字串長度為 4 字元
</script>
 


2022-01-30

【jQuery】Timer 的使用

 
setInterval(要做的事, 時間間隔);


setInterval(function() 
        {
            if ($(".mover").length)
            {    // 若網頁內有 mover 類別的元素, 則將這些類別隱藏
                $(".mover").hide();
                
                // 停止 Timer
                clearInterval(interval);
            }					
        }, 1000);
 


【jQuery】內嵌網頁

參考資料 ----


 
<div id="lnkOne">要內嵌另一個網頁的地方</div>


<script type="text/javascript">
    $("#lnkOne").load("b.html");
</script>

// load() 內, 也可以是 一段文字 或 物件
 


【jQuery】顯示/隱藏 網頁元素

 
// 顯示
$(".mover").show();

// 隱藏
$(".mover").hide();

// 雙引號內可以是 類別 / id / html元素
 


【jQuery】尋找網頁中的元素(element)

 
假設網頁中有個元素
<a id="lnkOne" href="somewebpage.html" class="index-tab mover" rel="index">某連結</a>
 


 
if ($(".mover").length)
{
    // 若網頁中有要尋找的元素, 則做以下的事
    ...
    ...
}

// 在本例中 .mover 是類別(class)
// 有些網頁因 CSS 的緣故, class 的雙引號內有很多個
// 而本例就有 2 個: index-tab 和 mover, 只要找其中的一個即可
// 當然, 網頁可能會有多個 mover
// 我就是要對所有的 mover 類別 做我指定的變化

// 要以 id 找, 則是 $("#lnkOne")

// 也可以找 html 的元素, ex: <a>, <p>, <h1>, ...
// $("a")
 


2021-04-10

【WEB程式】以 Apache ECharts 繪製圖表 -- 折線圖(Line Chart)

參考資料 ----

Apache ECharts 教程

 

 

Apache Echarts 原本由百度開發並開放源碼,之後百度貢獻給 Apache,成為 Apache 的專案項目之一,所以有詳盡豐富的中文參考文檔(雖然是簡體中文)。

這個真的要狂推!不僅免費,功能強大,又容易上手,而且有中文文檔。

 

要使用 ECharts 有多種方法,老人家選擇 "通过 jsDelivr 等 CDN 引入 的方式",除了 jsDelivr 外,還有 Staticfile;直接由 CDN 引入好像成了目前的趨勢,ZingChart 現在也採用這種方式。


最簡單的範例

 
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/dist/echarts.min.js"></script>
    <!-- 引入 vitage 樣式 js -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/theme/vintage.js"></script>
</head>
<body>
    <!-- 為 ECharts 準備一個具備大小(寬高)的 DOM -->
    <div id="main" style="width:600px; height:400px;"></div>
    
    <script type="text/javascript">
        <?php
            $aDlday = [5, 20, 36, 10, 10, 20];
            $aExam = ["1"=>7, "2"=>15, "3"=>26, "4"=>1, "5"=>17, "6"=>32];
            echo 'var aDlday = '.json_encode($aDlday,JSON_NUMERIC_CHECK).";\n";    // 將 PHP 陣列轉出成 javascript 陣列
                                                                                   // 要注意 json_encode() 的第 2 個參數
                                                                                   // 若沒有第 2 個參數, json_encode 預設會轉出成 字串 陣列, 每個數字會以雙引號包住
                                                                                   // 這樣會造成圖表的顯示出現無法預期的結果,ex: 線亂畫、座標點錯誤...
            // 當陣列有索引時,要先轉成無索引陣列
            $arr = array_values($aExam);
            echo 'var aExam = '.json_encode($arr,JSON_NUMERIC_CHECK).";\n";
        ?>
        // 基於準備好的 DOM,初始化 echarts 實體
        var myChart = echarts.init(document.getElementById('main'), 'vintage');    // 第 2 個參數 是 樣式 選項: 預設, light(內建), dark(內建), vintage, macarons, infographic, shine, roma
                                                                                   // 如果沒有 "樣式" 參數,就是預設樣式
                                                                                   // light樣式 與 預設樣式 的差異在 light 的顏色比預設更淡
                                                                                   // 若要採用不同樣式, 除了內建的 light/dark,其他樣式則上面也要引入相應的 js

        // 指定圖表的配置項和數據
        var option = {
            title: {
                text: 'ECharts 入門範例'    // 圖表標題
            },
            tooltip: {},
            legend: {   // 圖例(即折線, 直條, ...)說明
                        // 預設位置在圖表上方, 可在上 top, 左 left, 右 right
                        // 例如 left:30
                        // type: 'scroll',    // 當要畫的圖例很多項時, 可以捲動方式顯示
                        data:['下載數','練習數']    // 注意這裡的陣列元素就是下方 series 的 name 屬性
            },
            xAxis: {
                boundaryGap:false,    // 預設值 true,名稱會顯示在 x 軸兩個座標點中間
                                      // 值為 false 時,則名稱顯示在 x 軸座標點
                data: ["初等考試","大學指考","高考護理師","國中會考","機車駕照","汽車駕照"]
            },
            yAxis: {},    // y 軸座標, 預設是數值, 會自動隨 series 的數值改變
                          // 例如:本例 series 最大值 36, 則 y 軸座標點自動顯示為 10, 20, 30, 40
            series: [{
                        name: '下載數',
                        type: 'line',    // 圖表種類為 長條圖
                                        // 另有 line(折線圖), radar(雷達圖), pie(圓餅圖), tree(樹狀圖), gauge(儀表板),
                                        // k(K線圖), scatter(散點圖), ...
                                        // 可參考示例 https://echarts.apache.org/examples/zh/index.html#chart-type-scatter
                        data: aDlday,    // 這是由 PHP 轉出的陣列
                        symbol: 'emptyCircle', // 折點的樣式, 預設為 'emptyCircle', 其他值有 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
                    },
                    {
                        name: '練習數',
                        type: 'line',
                        data: aExam
                    }],
            tooltip: { // 是否顯示折點的數值, 預設為 none
                       // item: 滑鼠移至該折點時, 只顯示該折點的值
                       // axis: 會顯示一條通過滑鼠的垂直(虛)線, 及在垂直線上所有折點的值
                        trigger: 'axis'   // item, axis, none
                    },
        };

        // 使用剛才指定的配置項和數據顯示圖表。
        myChart.setOption(option);
    </script>
</body>
</html>

 






Echarts 會自動幫您為每條線配色,您也可以自己指定顏色。

點擊 legend 的某一項目,代表該項目的線就會隱藏,再點一次,就又出現,這在很多線條時很好用,可以將部份線隱藏,觀察您關心的某幾條線。


試著將陣列 aExam 的值放大 100 倍,這時 aDlday 的折線會因為數值太低而趜近水平線。




我們可以顯示雙 Y 軸,左邊的 Y 軸顯示下載數,右邊的 Y 軸顯示練習數。

 
            ...
            ...
            
            $aDlday = [5, 20, 36, 10, 10, 20];
            $aExam = ["1"=>700, "2"=>1500, "3"=>2600, "4"=>100, "5"=>1700, "6"=>3200];
            
            ...
            ...
            
            yAxis: [
                {   // 左右兩邊都有座標軸
                    name: '下載數',
                    type: 'value'
                },
                {
                    name: '練習數',
                    type: 'value',
                    // inverse: true    // 數字小的在上
                }
            ], 
            series: [{
                        name: '下載數',
                        type: 'line',
                        data: aDlday,
                        yAxisIndex:0,    // 加入這列參數
                        symbol: 'emptyCircle'
                    },
                    {
                        name: '練習數',
                        type: 'line',
                        yAxisIndex:1,    // 加入這列參數
                        data: aExam
                    }],
            
 



 


 

 相關筆記 ----

【WEB程式】以 Chartjs 繪製圖表 



2021-03-25

【Javascipt】偵測使用者上網瀏覽的裝置

老人家想做個網站,只供 手機/平板 瀏覽,所以要判斷辨認使用者的裝置

 

 
<body>
<script language="javascript">
if( /Android|webOS|iPhone|iPad|Mac|Macintosh|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) 
    {
        alert('mobile');
    }
else
    {
        alert("PC");
    }
</script>

...
...

</body>