#JP75 Sistem Hitung Cepat Pemilu Menggunakan Web Apps Script (Paket)

Sistem Hitung Cepat Pemilu Menggunakan Web Apps Script (Quick count Pemilu) 



1. Copy Spreadsheet (Klik Disini)

2. Buatlah Folder baru pada Google Drive dengan nama Berkas.



3. Kembali ke dalam Spreadsheet yang telah di copy di atas. Di dalam Spreadsheet terdapat beberapa sheet yaitu :

  • Sheet Lokasi 
Pada sheet Lokasi terdapat beberapa Kolom yang nantinya pada saat input suara jika memilih salah satu lokasi maka akan otomatis menampilkan Dropdown Multi Level yang sesuai dengan pilihan lokasi.


  • Sheet Data
Pada sheet Data ini terdapat beberapa kolom yang nantinya akan terisi otomatis dari data yang di input pada form Input Suara.


  • Sheet Proses Data
Pada sheet Proses Data ini adalah sheet gabungan antara sheet Lokasi dan sheet Data yang berfungsi untuk memproses semua data inputan dari sheet Data sesuai Lokasi yang ada.


  • Sheet Pivot Kab Jember
Pada sheet Pivot Kab Jember ini adalah berfungsi untuk memfilter kebutuhan yang akan di tampilkan pada Website (Contohnya : Data Perolehan Suara Setiap Paslon, Rincian Suara Per Kecamatan, DLL).



  • Sheet Login
Pada sheet Login ini berfungsi untuk masuk ke dalam penginputan suara setiap individu/Timses. Dalam sheet ini berisi Username, Password dan URL. Untuk kolom URL di isi dari Form Input Suara (Tutorial point nomor 13).



4. Buatlah lembar kerja Apps Script, dengan cara klik menu Ekstensi/Extensions lalu pilih Apps Script.


5. Terdapat 2 List Proyek pekerjaan yang otomatis sudah kami sediakan yaitu
  • Grafik suara
  • Input suara

6. Buka Proyek Input suara (Dengan klik kanan - open link new tab).

7. Pada lembar kerja Input suara terdapat 2 file dan 2 layanan otomatis tersedia.
  • File Code.gs
  • File Page.html
  • Layanan Drive API
  • Layanan Sheet API


8. Copy pastekan script di bawah ini ke Code.gs (Input Suara)

Masukkan Password Untuk Melihat Script (Password ada di dalam video)

// Source Code www.javabitpro.com

function doGet() {
  return HtmlService.createTemplateFromFile('Page').evaluate()
  .addMetaTag('viewport', 'width=device-width, initial-scale=1')
  .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
}

function getData(sheetName) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  var data = sheet.getDataRange().getValues();
  return JSON.stringify(data);
}

function getKabupatenOptions() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var kabupatenOptions = [];

  for (var i = 1; i < data.length; i++) {
    var kabupaten = data[i][0];
    if (!kabupatenOptions.includes(kabupaten)) {
      kabupatenOptions.push(kabupaten);
    }
  }

  return JSON.stringify(kabupatenOptions);
}

function getKecamatanOptions(kabupaten) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var kecamatanOptions = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && !kecamatanOptions.includes(data[i][1])) {
      kecamatanOptions.push(data[i][1]);
    }
  }

  return JSON.stringify(kecamatanOptions);
}


function getDesaOptions(kabupaten, kecamatan) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var desaOptions = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && data[i][1] === kecamatan) {
      desaOptions.push(data[i][2]);
    }
  }

  return JSON.stringify(desaOptions);
}

function getPaslon1Options(kabupaten, kecamatan, desa) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var paslon1Options = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && data[i][1] === kecamatan && data[i][2] === desa) {
      paslon1Options.push(data[i][3]);
    }
  }

  return JSON.stringify(paslon1Options);
}

function getPaslon2Options(kabupaten, kecamatan, desa, paslon1) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var paslon2Options = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && data[i][1] === kecamatan && data[i][2] === desa && data[i][3] === paslon1) {
      paslon2Options.push(data[i][4]);
    }
  }

  return JSON.stringify(paslon2Options);
}

function getPaslon3Options(kabupaten, kecamatan, desa, paslon1, paslon2) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var paslon3Options = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && data[i][1] === kecamatan && data[i][2] === desa && data[i][3] === paslon1 && data[i][4] === paslon2) {
      paslon3Options.push(data[i][5]);
    }
  }

  return JSON.stringify(paslon3Options);
}

function getPaslon4Options(kabupaten, kecamatan, desa, paslon1, paslon2, paslon3) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Lokasi');
  var data = sheet.getDataRange().getValues();
  var paslon4Options = [];

  for (var i = 1; i < data.length; i++) {
    if (data[i][0] === kabupaten && data[i][1] === kecamatan && data[i][2] === desa && data[i][3] === paslon1 && data[i][4] === paslon2 && data[i][5] === paslon3) {
      paslon4Options.push(data[i][6]);
    }
  }

  return JSON.stringify(paslon4Options);
}

// Tambahkan fungsi serupa untuk Paslon 5, dan seterusnya...

function submitForm(formData) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
  var folderId = 'ID_FOLDER_BERKAS'; // Ganti dengan ID folder Google Drive Anda

  var data = JSON.parse(formData);
  var fileBlob = Utilities.newBlob(Utilities.base64Decode(data.file.data), data.file.type, data.file.name);
  var folder = DriveApp.getFolderById(folderId);
  var newFile = folder.createFile(fileBlob);

  var fileUrl = newFile.getUrl();

  sheet.appendRow([data.nama, data.notps, data.kabupaten, data.kecamatan, data.desa, data.dpt, data.paslon1, data.suarapaslon1, data.paslon2, data.suarapaslon2, data.paslon3, data.suarapaslon3, data.paslon4, data.suarapaslon4, data.suaratidaksah, fileUrl]);
}

Sesuaikan ID_FOLDER_BERKAS dengan ID Folder yang telah di buat tadi.

9. Copy dan pastekan script di bawah ini ke Page.html (Input Suara).

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<!-- Source Code www.javabitpro.com -->

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
     <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

    <script>
      function updateKabupatenOptions() {
        google.script.run.withSuccessHandler(populateKabupatenOptions).getKabupatenOptions();
      }

      function populateKabupatenOptions(kabupatenOptions) {
        var kabupatenDropdown = document.getElementById('kabupaten');
        kabupatenDropdown.innerHTML = '';

        JSON.parse(kabupatenOptions).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          kabupatenDropdown.add(newOption);
        });

        // Setelah mengisi dropdown Kabupaten, panggil fungsi untuk mengisi dropdown Kecamatan
        updateKecamatanOptions();
      }

      function updateKecamatanOptions() {
        var kabupaten = document.getElementById('kabupaten').value;
        google.script.run.withSuccessHandler(populateKecamatanOptions).getKecamatanOptions(kabupaten);
      }

      function populateKecamatanOptions(kecamatanOptions) {
        var kecamatanDropdown = document.getElementById('kecamatan');
        kecamatanDropdown.innerHTML = '';

        JSON.parse(kecamatanOptions).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          kecamatanDropdown.add(newOption);
        });

        // Setelah mengisi dropdown Kecamatan, panggil fungsi untuk mengisi dropdown Desa
        updateDesaOptions();
      }

      function updateDesaOptions() {
        var kabupaten = document.getElementById('kabupaten').value;
        var kecamatan = document.getElementById('kecamatan').value;
        google.script.run.withSuccessHandler(populateDesaOptions).getDesaOptions(kabupaten, kecamatan);
      }

      function populateDesaOptions(desaOptions) {
        var desaDropdown = document.getElementById('desa');
        desaDropdown.innerHTML = '';

        JSON.parse(desaOptions).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          desaDropdown.add(newOption);
        });

        // Setelah mengisi dropdown Desa, panggil fungsi untuk mengisi dropdown Paslon1
        updatePaslon1Options();
      }

      function updatePaslon1Options() {
        var kabupaten = document.getElementById('kabupaten').value;
        var kecamatan = document.getElementById('kecamatan').value;
        var desa = document.getElementById('desa').value;
        google.script.run.withSuccessHandler(populatePaslon1Options).getPaslon1Options(kabupaten, kecamatan, desa);
      }

      function populatePaslon1Options(paslon1Options) {
        var paslon1Dropdown = document.getElementById('paslon1');
        paslon1Dropdown.innerHTML = '';

        JSON.parse(paslon1Options).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          paslon1Dropdown.add(newOption);
        });

        // Setelah mengisi dropdown Paslon1, panggil fungsi untuk mengisi dropdown Paslon2
        updatePaslon2Options();
      }

      function updatePaslon2Options() {
        var kabupaten = document.getElementById('kabupaten').value;
        var kecamatan = document.getElementById('kecamatan').value;
        var desa = document.getElementById('desa').value;
        var paslon1 = document.getElementById('paslon1').value;
        google.script.run.withSuccessHandler(populatePaslon2Options).getPaslon2Options(kabupaten, kecamatan, desa, paslon1);
      }

      function populatePaslon2Options(paslon2Options) {
        var paslon2Dropdown = document.getElementById('paslon2');
        paslon2Dropdown.innerHTML = '';

        JSON.parse(paslon2Options).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          paslon2Dropdown.add(newOption);
        });

        // Setelah mengisi dropdown Paslon2, panggil fungsi untuk mengisi dropdown Paslon3
         updatePaslon3Options();
      }

function updatePaslon3Options() {
        var kabupaten = document.getElementById('kabupaten').value;
        var kecamatan = document.getElementById('kecamatan').value;
        var desa = document.getElementById('desa').value;
        var paslon1 = document.getElementById('paslon1').value;
        var paslon2 = document.getElementById('paslon2').value;
        google.script.run.withSuccessHandler(populatePaslon3Options).getPaslon3Options(kabupaten, kecamatan, desa, paslon1, paslon2);
      }

      function populatePaslon3Options(paslon3Options) {
        var paslon3Dropdown = document.getElementById('paslon3');
        paslon3Dropdown.innerHTML = '';

        JSON.parse(paslon3Options).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          paslon3Dropdown.add(newOption);
        });

        // Setelah mengisi dropdown Paslon3, panggil fungsi untuk mengisi dropdown Paslon4
         updatePaslon4Options();
      }

function updatePaslon4Options() {
        var kabupaten = document.getElementById('kabupaten').value;
        var kecamatan = document.getElementById('kecamatan').value;
        var desa = document.getElementById('desa').value;
        var paslon1 = document.getElementById('paslon1').value;
        var paslon2 = document.getElementById('paslon2').value;
        var paslon3 = document.getElementById('paslon3').value;
        google.script.run.withSuccessHandler(populatePaslon4Options).getPaslon4Options(kabupaten, kecamatan, desa, paslon1, paslon2, paslon3);
      }

      function populatePaslon4Options(paslon4Options) {
        var paslon4Dropdown = document.getElementById('paslon4');
        paslon4Dropdown.innerHTML = '';

        JSON.parse(paslon4Options).forEach(function(option) {
          var newOption = document.createElement('option');
          newOption.value = option;
          newOption.text = option;
          paslon4Dropdown.add(newOption);
        });

        // Setelah mengisi dropdown Paslon4, panggil fungsi untuk mengisi dropdown Paslon5, Hapus tanda // di bawah ini
        // updatePaslon5Options();
      }
      // ... Fungsi-fungsi lainnya ...

      // Panggil updateKabupatenOptions saat halaman dimuat
      document.addEventListener('DOMContentLoaded', function() {
        updateKabupatenOptions();
      });

     function submitForm() {
        var nama = document.getElementById("nama").value;
        var notps = document.getElementById("notps").value;
        var kabupaten = document.getElementById("kabupaten").value;
        var kecamatan = document.getElementById("kecamatan").value;
        var desa = document.getElementById("desa").value;
        var dpt = document.getElementById("dpt").value;
        var paslon1 = document.getElementById("paslon1").value;
        var suarapaslon1 = document.getElementById("suarapaslon1").value;
        var paslon2 = document.getElementById("paslon2").value;
        var suarapaslon2 = document.getElementById("suarapaslon2").value;
        var paslon3 = document.getElementById("paslon3").value;
        var suarapaslon3 = document.getElementById("suarapaslon3").value;
        var paslon4 = document.getElementById("paslon4").value;
        var suarapaslon4 = document.getElementById("suarapaslon4").value;
        var suaratidaksah = document.getElementById("suaratidaksah").value;
       

        // Retrieve the file input element
        var fileInput = document.getElementById("fileInput");
        var file = fileInput.files[0];

        // Show loading element
        document.getElementById("loading").style.display = "block";

        // Convert the file to base64
        var reader = new FileReader();
        reader.onloadend = function() {
          var fileData = {
            name: file.name,
            type: file.type,
            data: reader.result.split(',')[1] // Extracting the base64 data
          };

          // Prepare the form data
          var formData = {
            nama: nama,
            notps: notps,
            kabupaten: kabupaten,
            kecamatan: kecamatan,
            desa: desa,
            dpt: dpt,
            paslon1: paslon1,
            suarapaslon1: suarapaslon1,
            paslon2: paslon2,
            suarapaslon2: suarapaslon2,
            paslon3: paslon3,
            suarapaslon3: suarapaslon3,
            paslon4: paslon4,
            suarapaslon4: suarapaslon4,
            suaratidaksah: suaratidaksah,
            file: fileData
          };

          // Pass the form data to the server-side script for submission
          google.script.run
            .withSuccessHandler(function() {

              // Hide loading element
              document.getElementById("loading").style.display = "none";
              // Show success popup
              document.getElementById("successPopup").style.display = "block";
              
              // Optionally, clear the file input after successful upload
              fileInput.value = "";
              
              // Clear other form fields after submission (optional)

              document.getElementById("nama").value = "";
              document.getElementById("notps").value = "";
              document.getElementById("kabupaten").value = "";
              document.getElementById("kecamatan").value = "";
              document.getElementById("desa").value = "";
              document.getElementById("dpt").value = "";
              document.getElementById("paslon1").value = "";
              document.getElementById("suarapaslon1").value = "";
              document.getElementById("paslon2").value = "";
              document.getElementById("suarapaslon2").value = "";
              document.getElementById("paslon3").value = "";
              document.getElementById("suarapaslon3").value = "";
              document.getElementById("paslon4").value = "";
              document.getElementById("suarapaslon4").value = "";
              document.getElementById("suaratidaksah").value = "";


            })
            .submitForm(JSON.stringify(formData));
        };

        reader.readAsDataURL(file);
      }

      function closeSuccessPopup() {
        document.getElementById("successPopup").style.display = "none";
      }
    </script>
        <style>
       #successPopup {
        display: none;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: #fff;
        padding: 20px;
        border: 1px solid #ccc;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      }

      #loading {
        display: none;
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: #fff;
        padding: 20px;
        border: 1px solid #ccc;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      }
          .card-img-top {
      width: 256px;
      height: 256px;
      object-fit: cover;
    }

    .center-content {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100%;
    }
    </style>
  </head>
  <body>
    <form>
      <div class="container mt-4">
  <!-- Card di bagian atas dengan formasi 2x3 -->
  <div class="row">
    <div class="col-md-12">
      <div class="card">
        <div class="card-body">
          <h5 class="card-title">MASUKKAN DATA</h5>

          <div class="row">
            <div class="col-md-4 mb-3">
              <label for="nama">Nama:</label>
              <input type="text" class="form-control" id="nama" name="nama" required>
            </div>
            <div class="col-md-4 mb-3">
              <label for="notps">No TPS:</label>
              <input type="text" class="form-control" id="notps" name="notps" required>
            </div>
            <div class="col-md-4 mb-3">
              <label for="dpt">Jumlah DPT:</label>
              <input type="text" class="form-control" id="dpt" name="dpt" required>
            </div>
          </div>

          <div class="row">
            <div class="col-md-4 mb-3">
              <label for="kabupaten">Kabupaten:</label>
              <select class="form-control" id="kabupaten" name="kabupaten" onchange="updateKecamatanOptions()"></select>
            </div>
            <div class="col-md-4 mb-3">
               <label for="kecamatan">Kecamatan:</label>
               <select class="form-control" id="kecamatan" name="kecamatan"  onchange="updateDesaOptions()"></select>
            </div>
            <div class="col-md-4 mb-3">
              <label for="desa">Desa:</label>
              <select class="form-control" id="desa" name="desa" onchange="updatePaslon1Options()"></select>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

<!-- Dua card di bawahnya -->
  <div class="row mt-4">
    <div class="col-md-6">
      <div class="card">
        <div class="center-content">
        <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZpozi0SKfcS4ltzmd0Z6rnSiBsV_ClmyAzDffhc5A_eKPtgKOh8ALQ1XHyCUXE5qeBUhehGO7DX6nP6otmXoAAFGYEYuLEEmLPOrMI3JXepLLzl3mgAs8doKc1-jf4qGHd5Cb3gnWWWYwNt0V6U5vq9hYfHiFT3cpo-TN6hBstoaWuMTOXPzf-ScuG6o/s16000/1.jpg" class="card-img-top" alt="Img 256x256">
        <div class="card-body">
          <h5 class="card-title">Paslon 1</h5>
          <label for="paslon1">Paslon 1:</label>
          <select class="form-control" id="paslon1" name="paslon1" onchange="updatePaslon2Options()"></select>
          <label for="suarapaslon1">Jumlah suara:</label>
          <input type="text" class="form-control" id="suarapaslon1" name="suarapaslon1" required>
        </div>
        </div>
      </div>
    </div>

    <div class="col-md-6">
      <div class="card">
        <div class="center-content">
        <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSiNP4AZ4iV5q4VcHxn7Y28z8njnnXuI6n4P9zaeWst-vKHDagQAuzRJuajLyaCLvESuYLk79cOFl5bmfbvSGoCfRDEiKdUosD2cuNj4rbXvZpynxpa0WCy4LalWc_bmm7t5trdutgZFDWglGswsqNgFaNGQsMU9J7SCYJ-0OT5LXuqktUed1-nmHqKw/s16000/2.jpg" class="card-img-top" alt="Img 256x256">
        <div class="card-body">
          <h5 class="card-title">Paslon 2</h5>
          <label for="paslon2">Paslon 2:</label>
          <select class="form-control" id="paslon2" name="paslon2" onchange="updatePaslon3Options()"></select>
          <label for="suarapaslon2">Jumlah suara:</label>
          <input type="text" class="form-control" id="suarapaslon2" name="suarapaslon2" required>
        </div>
        </div>
      </div>
    </div>
  </div>

  
  <div class="row mt-4">
    <div class="col-md-6">
      <div class="card">
        <div class="center-content">
        <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgauN7BfUMUfLoO7ZTkoB34kjF2N8xqRwYpNQshE0T4VWQorbudGBs5LKHds1sv5NYmhhKKPEnCMW6Qk-8BUzB12uspBa0P7V64PVgC4zHa48dgYrAOe8VTfSsCo7UAmHXZaxsUkTOjo9h1uXIHHcGybSF7qjJC9UiCZ379hjNISzNGttwptaDe38oQhGE/s16000/3.jpg" class="card-img-top" alt="Img 256x256">
        <div class="card-body">
          <h5 class="card-title">Paslon 3</h5>
          <label for="paslon3">Paslon 3:</label>
          <select class="form-control" id="paslon3" name="paslon3" onchange="updatePaslon4Options()"></select>
          <label for="suarapaslon3">Jumlah suara:</label>
          <input type="text" class="form-control" id="suarapaslon3" name="suarapaslon3" required>
        </div>
        </div>
      </div>
    </div>

    <div class="col-md-6">
      <div class="card">
        <div class="center-content">
        <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhja9YI89NgavHcTPajBX2SzRJtsB5V2VZZeD4nzCU4nOwDa6eWDIloxLHKV6Skf-iyJybufBg07EwZ4NWAuHKZmr2MFYJHrJHjDd0f45mUn9UkrFw44pD6U4fk-44jUzf7YbdRHQ79svHqB-k-KBiu4-7IqLeFpN4OXTFBHgbq_HtSISDD5qOkK56Tp0k/s16000/4.jpg" class="card-img-top" alt="Img 256x256">
        <div class="card-body">
          <h5 class="card-title">Paslon 4</h5>
          <label for="paslon4">Paslon 4:</label>
          <select class="form-control" id="paslon4" name="paslon4"></select>
          <label for="suarapaslon4">Jumlah suara:</label>
          <input type="text" class="form-control" id="suarapaslon4" name="suarapaslon4" required>
        </div>
        </div>
      </div>
    </div>
  </div>
   <!-- Tambahkan dropdown untuk Paslon3, Paslon4, dan seterusnya... -->
  <!-- Card paling bawah dengan upload foto dan tombol di tengah -->
  <div class="row mt-4">
    <div class="col-md-12">
      <div class="card">
        <div class="card-body">
          <h5 class="card-title">Upload Foto Bukti Rekap Suara</h5>


<div class="form-row">
            <div class="form-group col-md-6">
               <label for="suaratidaksah">Suara Tidak Sah:</label>
              <input type="text" class="form-control" id="suaratidaksah" name="suaratidaksah" required>
            </div>

<div class="form-group col-md-6">
              <label for="photo">Upload Foto:</label>
              <input type="file" class="form-control-file" id="fileInput" accept="image/*">
            </div>
<input type="button" value="Submit" onclick="submitForm()">
          
      </div>
    </div>
  </div>
</div>


    </form>
    <div id="loading">
      Loading...
    </div>

    <div id="successPopup">
      <p>Formulir berhasil disubmit!</p>
      <button onclick="closeSuccessPopup()">Tutup</button>
    </div>
  </body>
</html>

10. Klik ikon Save.


11. Klik tombol Terapkan/Deploy lalu pilih Deployment baru/New deployment.


12. Pastikan jenisnya adalah Aplikasi web dan hak aksesnya adalah Siapa saja/Anyone lalu klik Terapkan/Deploy.


13. Silahkan salin URL yang sudah di Deploy dan pastekan pada kolom URL yang ada di sheet Login. (Tutorial point nomor 3).



14. Kembali ke List Proyek, dan buka Proyek Grafik suara.

15. Pada lembar kerja Grafik Suara terdapat 5 File dan 2 Layanan yang tersedia otomatis yaitu :
  • File Code.gs
  • File Page.html
  • File cssjam.html
  • File jsjam.html
  • File visit.html
  • Layanan Drive API
  • Layanan Sheet API


16. Copy dan pastekan script di bawah ini Code.gs (Grafik Suara)


Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

// Source Code www.javabitpro.com

function doGet() {
  return HtmlService.createTemplateFromFile('Page').evaluate()
      .setTitle('Javabitpro')
      .addMetaTag('viewport','width=device-width , initial-scale=1')
        .setFaviconUrl('https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvHj7zvogZ96zuoYdLKx87C2iYHmwi8hEr7qC_MgAN6qgfKYk721CMQv6w317b4oWlj68S9qdOKHt6ZhG_trYr_nT5rCeTuCyr6MaZpFc7y0vmrnY9S1eKCrgDBJMMn37A30MB95-LkAxLBd61dtfQd7C_dUH-2NdPXOfdSsP4mvBlDTa1U-OaJIdi1Wk/s1600/button-logojp.png');
}

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
      .getContent();
}

// Login
function checkLogin(username, password) {
  var sheet = SpreadsheetApp.openById('ID_SPREADSHEET').getSheetByName('Login');
  var data = sheet.getDataRange().getValues();
  
  for (var i = 1; i < data.length; i++) {
    if (data[i][0] == username && data[i][1] == password) {
      return { success: true, index: i };
    }
  }
  
  return { success: false };
}

function getUrls(username) {
  var sheet = SpreadsheetApp.openById('ID_SPREADSHEET').getSheetByName('Login');
  var data = sheet.getDataRange().getValues();
  
  for (var i = 1; i < data.length; i++) {
    if (data[i][0] == username) {
      return { url1: data[i][2], url2: data[i][3] };
    }
  }
  
  return { url1: '', url2: '' };
}
function logout() {
  var output = HtmlService.createHtmlOutputFromFile('Page')
    .setTitle('Login')
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
  return output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
// End Login


// Data
// Grafik Jumlah Suara
function getData1() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var data = sheet.getRange('N1:O5').getValues();
      // Menambahkan kolom warna untuk setiap bar di data
    var colors = ['#3366cc', '#dc3912', '#ff9900', '#109618', '#990099']; // Sesuaikan dengan jumlah batang bar
    data = data.map(function(row, index) {
         return [row[0], row[1] , colors[index % colors.length], row[1]]; 
    });
    return [['Kategori', 'Nilai', { role: 'style', }, { role: 'annotation' }]].concat(data);
}

//Grafik Persentase Suara
function getData2() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var data = sheet.getRange('P1:Q5').getValues();
     // Menambahkan kolom warna untuk setiap bar di data
    var colors = ['#3366cc', '#dc3912', '#ff9900', '#109618', '#990099']; // Sesuaikan dengan jumlah batang bar
    data = data.map(function(row, index) {
         return [row[0], row[1] * 100, colors[index % colors.length],  (row[1] * 100).toFixed(2) + '%']; 
    });

    return [['Kategori', 'Nilai1', { role: 'style', }, { role: 'annotation' }]].concat(data);
}
//Data Masuk Per-Kecamatan Grafik Vertcal
function getData3() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var data = sheet.getRange('S2:T32').getValues();
      // Menambahkan kolom warna untuk setiap bar di data
    var colors = ['#3366cc']; // Sesuaikan dengan jumlah batang bar
    data = data.map(function(row, index) {
         return [row[0], row[1] , colors[index % colors.length], row[1]]; 
    });
    return [['Kategori', 'Nilai', { role: 'style', }, { role: 'annotation' }]].concat(data);
}

//Data Suara Per-Paslon Sekecamatan Grafik Vertcal
function getData4() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var data = sheet.getRange('V2:Z32').getValues();
      // Menambahkan kolom warna untuk setiap bar di data
    var colors = ['#3366cc', '#dc3912', '#ff9900', '#109618']; // Sesuaikan dengan jumlah batang bar
    data = data.map(function(row, index) {
         return [row[0], row[1] ,row[2] ,row[3] ,row[4] , colors[index % colors.length], row[5]]; 
    });
    return [['Kategori', 'Nilai1','Nilai2','Nilai3','Nilai4', { role: 'style', }, { role: 'annotation' }]].concat(data);
}

//Persentase Suara Paslon1
function getCard3Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    //var dataO = sheet.getRange('S1').getValue();
    var dataQ = sheet.getRange('Q1').getValue() * 100; // Mengambil nilai persentase dan dikalikan 100
    return [dataQ];
}

//Persentase Suara Paslon2
function getCard4Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    //var dataO = sheet.getRange('S2').getValue();
    var dataQ = sheet.getRange('Q2').getValue() * 100; // Mengambil nilai persentase dan dikalikan 100
    return [dataQ];
}

//Persentase Suara Paslon3
function getCard5Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    //var dataO = sheet.getRange('S2').getValue();
    var dataQ = sheet.getRange('Q3').getValue() * 100; // Mengambil nilai persentase dan dikalikan 100
    return [dataQ];
}

//Persentase Suara Paslon4
function getCard6Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    //var dataO = sheet.getRange('S2').getValue();
    var dataQ = sheet.getRange('Q4').getValue() * 100; // Mengambil nilai persentase dan dikalikan 100
    return [dataQ];
}

//Persentase Jumlah DPT Masuk
function getCard7Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var dataO = sheet.getRange('O6').getValue(); // Mengambil nilai persentase dan dikalikan 100
    return [dataO];
}

//Persentase Suara Tidak Sah
function getCard8Data() {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pivot Kab Jember');
    var dataO = sheet.getRange('O5').getValue(); // Mengambil nilai persentase dan dikalikan 100
    return [dataO];
}

Sesuaikan ID_SPREADSHEET pada point ke 17 dan 30 pada script.

17. Copy dan pastekan script di bawah ini ke Page.html (Grafik Suara).

Masukkan Password Untuk Melihat Script (Password sama dengan di atas)

<!-- Source Code www.javabitpro.com -->
<!DOCTYPE html>
<html lang="en">

<head>
<base target="_top">
<meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
   <!-- font-awesome@6.2.0 icon Visit -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css">
  <?!= include('visit')?>
  <?!= include('cssjam'); ?>
  <?!= include('jsjam'); ?>
<style>
 .custom-card {
      margin-left: 0; /* Set margin kiri menjadi 0 */
    }

      .card-img-top {
      width: 100px;
      height: 100px;
      object-fit: cover;
    }

    .center-content {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100%;
    }
     #dashboard {
      display: none;
    }
</style>
    <script>
        google.charts.load('current', { 'packages': ['corechart','annotationchart'] });
        google.charts.setOnLoadCallback(drawCharts);

        function drawCharts() {
            // Mengambil data dari server
            google.script.run.withSuccessHandler(drawChart1).getData1();
            google.script.run.withSuccessHandler(drawChart2).getData2();
            google.script.run.withSuccessHandler(drawChart3).getData3();
            google.script.run.withSuccessHandler(drawChart4).getData4();
        }
      // Grafik Jumlah Suara
        function drawChart1(data) {
            var chartData = google.visualization.arrayToDataTable(data);

            var options = {
                title: 'Grafik Jumlah Suara',
                chartArea: { width: '100%' },
                hAxis: { title: 'Total' },
                vAxis: { title: 'Nilai' }, 
                width: 500,
                height: 300,
                is3D:true
            };

            var chart = new google.visualization.ColumnChart(document.getElementById('chart1'));
            chart.draw(chartData, options);
        }

      // Grafik Persentase Suara
        function drawChart2(data) {
            var chartData = google.visualization.arrayToDataTable(data);

            var options = {
                title: 'Grafik Persentase Suara',
                chartArea: { width: '100%' },
                hAxis: { title: 'Persentase' },

                width: 500,
                height: 300,
                
            };

            var chart = new google.visualization.ColumnChart(document.getElementById('chart2'));
            chart.draw(chartData, options);
        }

      //Data Masuk Per-Kecamatan Grafik Vertcal
        function drawChart3(data) {
            var chartData = google.visualization.arrayToDataTable(data);

            var options = {
                title: 'Grafik Rincian DPT Masuk',
                chartArea: { width: '50%' , height: '100%'},
                hAxis: { title: 'Data Masuk' },
                vAxis: { title: 'Suara' },
                height: 800,
                
            };
              
            var chart = new google.visualization.BarChart(document.getElementById('chart3'));
            chart.draw(chartData, options);
        }

      //Data Suara Per-Paslon Sekecamatan Grafik Vertcal
        function drawChart4(data) {
            var chartData = google.visualization.arrayToDataTable(data);

            var options = {
                title: 'Grafik Rincian Suara',
                chartArea: { width: '50%' , height: '100%'},
                hAxis: { title: 'Data Masuk' },
                vAxis: { title: 'Suara' },
                height: 800,
                
            };
              
            var chart = new google.visualization.BarChart(document.getElementById('chart4'));
            chart.draw(chartData, options);
        }

//Persentase Suara Paslon1        
function drawCard3(data) {
    var formattedValueP1 = data[0].toFixed(2) + '%'; // Mengubah nilai persentase menjadi string dengan dua desimal
    document.getElementById('card3').innerText =  formattedValueP1;
}

//Persentase Suara Paslon2
function drawCard4(data) {
    var formattedValueP2 = data[0].toFixed(2) + '%'; // Mengubah nilai persentase menjadi string dengan dua desimal
    document.getElementById('card4').innerText =  formattedValueP2;
}

//Persentase Suara Paslon3
function drawCard5(data) {
    var formattedValueP3 = data[0].toFixed(2) + '%'; // Mengubah nilai persentase menjadi string dengan dua desimal
    document.getElementById('card5').innerText =  formattedValueP3;
}

//Persentase Suara Paslon4
function drawCard6(data) {
    var formattedValueP4 = data[0].toFixed(2) + '%'; // Mengubah nilai persentase menjadi string dengan dua desimal
    document.getElementById('card6').innerText =  formattedValueP4;
}

//Grafik Jumlah DPT Masuk
function drawCard7(data) {
    var card7Value = Number(data).toLocaleString('id-ID'); // Format angka sesuai lokal Indonesia
    document.getElementById('card7').innerText = 'Total : ' + card7Value;
}

//Grafik Jumlah Suara Tidak Sah
function drawCard8(data) {
    var card8Value = Number(data).toLocaleString('id-ID'); // Format angka sesuai lokal Indonesia
    document.getElementById('card8').innerText = 'Total : ' + card8Value;
}
function getDataFromServer() {
    google.script.run.withSuccessHandler(drawCard3).getCard3Data();
    google.script.run.withSuccessHandler(drawCard4).getCard4Data();
    google.script.run.withSuccessHandler(drawCard5).getCard5Data();
    google.script.run.withSuccessHandler(drawCard6).getCard6Data();
    google.script.run.withSuccessHandler(drawCard7).getCard7Data();
    google.script.run.withSuccessHandler(drawCard8).getCard8Data();
}
  window.onload = function() {
        getDataFromServer();
    };
    </script>
</head>

<body>
   <!-- Formulir Login -->
<div id="login">
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <a class="navbar-brand">Sistem Hitung Cepat (by Javabitpro)</a>
      <form class="form-inline ml-auto">
        <div class="form-group">
          <label for="username" class="text-light mr-2">Username:</label>
          <input type="text" class="form-control mr-2" id="username" name="username" placeholder="Masukkan Username">
        </div>
        <div class="form-group">
          <label for="password" class="text-light mr-2">Password:</label>
          <input type="password" class="form-control mr-2" id="password" name="password" placeholder="Masukkan Password">
        </div>
        <button type="button" class="btn btn-primary" onclick="attemptLogin()">Login</button>
      </form>
  </nav>
<br>
<div class="w3-container w3-center">
  <h2>Sistem Perhitungan Cepat Pemilu</h2>
  <p>Source Code.by Javabitpro</p>
</div>
<div class="container mt-5">
<!-- 2 kolom chart horizontal -->      
        <div class="row">
            <div class="col-md-6">
                <div class="card custom-card">
                    <div class="card-body">
                       
                        <div id="chart1"></div>
                    </div>
                </div>
            </div>
            <div class="col-md-6">
                <div class="card custom-card">
                    <div class="card-body" >
                        
                        <div id="chart2" ></div>
                    </div>
                </div>
            </div>
        </div>
<br>
<!-- end 2 kolom chart horizontal -->  

<!-- 4 kolom -->
  <div class="row">
	<div class="col-sm-3">
		<div class="card border-primary mb-3" style="max-width: 18rem;">
		  <div class="card-header text-center">Paslon Nomor 1</div>
		  <div class="card-body text-primary text-center">
		    <h5 class="card-title">Persentase Suara</h5>
		    	<h1 id="card3"></h1>
		  </div>
		</div>
	</div>
	<div class="col-sm-3">
		<div class="card border-secondary mb-3" style="max-width: 18rem;">
		  <div class="card-header text-center">Paslon Nomor 2</div>
		  <div class="card-body text-secondary text-center">
		    <h5 class="card-title">Persentase Suara</h5>
		    	<h1 id="card4"></h1>
		  </div>
		</div>
	</div>
	<div class="col-sm-3">
		<div class="card border-success mb-3" style="max-width: 18rem;">
		  <div class="card-header text-center">Paslon Nomor 3</div>
		  <div class="card-body text-success text-center">
		    <h5 class="card-title">Persentase Suara</h5>
		    	<h1 id="card5"></h1>
		  </div>
		</div>
	</div>
	<div class="col-sm-3">
		<div class="card border-danger mb-3" style="max-width: 18rem;">
		  <div class="card-header text-center">Paslon Nomor 4</div>
		  <div class="card-body text-danger text-center">
		   <h5 class="card-title">Persentase Suara</h5>
		    	<h1 id="card6"></h1>
		  </div>
		</div>
	</div>
    </div>
<!-- end 4 kolom -->

<!-- 2 kolom -->
<div class="row">
	<div class="col-sm-6">
		<div class="card text-center">
		  <div class="card-header">
		    Jumlah DPT Masuk
		  </div>
		  <div class="card-body">
		    <h1 id="card7"></h1>
		  </div>
		</div>
	</div> 
	<div class="col-sm-6">
		<div class="card text-center">
		  <div class="card-header">
		    Jumlah Suara Tidak Sah
		  </div>
		  <div class="card-body">
		    <h1 id="card8"></h1>
		  </div>
		</div>
	</div>
</div>
<br>
<!-- end 2 kolom -->

<!-- 2 kolom vertical -->
<div class="row">
	<div class="col-sm-6">
		<h4 class="bg-danger text-white" align="center">Data Masuk Per-Kecamatan</h4>
		<div class="card text-center">
		  <div class="card-header">
		    Rincian
		  </div>
		  <div class="card-body">
		    <div id="chart3" ></div>
		  </div>
		</div>
	</div>
 
	<div class="col-sm-6">
		<h4 class="bg-danger text-white" align="center">Data Suara Per-Paslon Sekecamatan</h4>
		<div class="card text-center">
		  <div class="card-header">
		    Rincian
		  </div>
		  <div class="card-body">
		    <div id="chart4" ></div>
		  </div>
		</div>
	</div>
</div>

<!-- end 2 kolom vertical -->


  <div class="row mt-4">
    <div class="col-md-12">
      <div class="card">

 <div class="jam-digital">
   <div id="jam"></div>
   <div id="unit">
     <span>Jam</span>
     <span>Menit</span>
     <span>Detik</span>
   </div>
</div>
</div>
  </div>
</div>
</div>
</div>
   <!-- end Formulir Login -->

<div id="dashboard" style="background-color: #f0f0f0; background-image: url('https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlhuokn2FsWEv0stmc-y98DYtX5YxQrOFFo8SuOQhVAgMqHW8JTGT25DwBzIgVmrlHsuWpDkNvlFRX_N1cSqf7MN7EioFS0MQ9XksWhAfSXp8cbb91nr8WFC5iQCk4zS20by0dPftGeJAlTjI9Gb3Gg8KJygs2iJ9qxjAlhxjKYimvVppgEb8DBs8c5EQ/s16000/Abstract_White_Background_HD_motion_graphics_background_loop_White_video_Royalty_Free_Footages.gif'); background-size: cover;">
    <div id="header" style="display: flex; justify-content: space-between; align-items: center; padding: 10px; background-color: #343a40; color: #fff; box-shadow:  0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);">
      <div style="display: flex; align-items: center;">
        <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZ8B_nPqW3IXcEHCrI7xrh-sqJTMHP8IUzgXSIZhH6-y04PdmOsunTJUWXZGsiHVUDt1fBvhMdDltzihl6hq0rZT8SO1EgCu7LgzQXfxlP_7tbeuekfm0gZqvA8MLV0QpyFEc2e1VsIRt7SDhZaDFFTwYX_vdSWEjS15Z_kyKeC-mKyuWxfkQEPOP0UD8/s320/Untitled%20design.gif" alt="Logo" style="height: 50px; width: auto;">
        <h3 id="dashboardHeader" style="margin-left: 10px;"></h3>
      </div>
      <div>
        <button class="btn btn-success" onclick="showIframe(1)">Input Suara</button>
        <button class="btn btn-danger" onclick="showLogoutModal()">Logout</button>
      </div>
    </div>
  <br>
  <iframe id="iframeContainer" width="100%" height="900" frameborder="0" style="border:0;"></iframe>
</div>

  <!-- Loading Modal -->
  <div class="modal" tabindex="-1" role="dialog" id="loadingModal" data-backdrop="static" data-keyboard="false">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-body text-center">
          <div class="spinner-border" role="status">
            <span class="sr-only">Loading...</span>
          </div>
          <p class="mt-2">Logging in...</p>
        </div>
      </div>
    </div>
  </div>

  <!-- Logout Modal -->
  <div class="modal" tabindex="-1" role="dialog" id="logoutModal">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Logout Confirmation</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
          <p>Apakah yakin anda akan keluar?</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
          <button type="button" class="btn btn-danger" onclick="logout()">Logout</button>
        </div>
      </div>
    </div>
  </div>

  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
  <script>
    function attemptLogin() {
      var username = document.getElementById("username").value;
      var password = document.getElementById("password").value;

      $('#loadingModal').modal('show');

      google.script.run
        .withSuccessHandler(function (result) {
          if (result.success) {
            showDashboard(result.index,username);
          } else {
            alert("Login Ditolak. Silahkan Cek Username dan Password.");
            $('#loadingModal').modal('hide');
          }
        })
        .checkLogin(username, password);
    }

 function showDashboard(index, username) {
      document.getElementById("dashboardHeader").innerText = 'Dashboard Timses - ' + username;
      document.getElementById("login").style.display = "none";
      document.getElementById("dashboard").style.display = "block";

      google.script.run
        .withSuccessHandler(function (urls) {
          document.getElementById("iframeContainer").src = urls.url1;
          $('#loadingModal').modal('hide');
        })
        .getUrls(index);
    }

     function showIframe(buttonNumber) {
    var username = document.getElementById("username").value;

    google.script.run
      .withSuccessHandler(function (urls) {
        var iframeSrc = buttonNumber === 1 ? urls.url1 : urls.url2;
        document.getElementById("iframeContainer").src = iframeSrc;
      })
      .getUrls(username);
  }

    function showLogoutModal() {
      $('#logoutModal').modal('show');
    }

    function logout() {
      $('#logoutModal').modal('hide');

      $('#loadingModal').modal('show');

      google.script.run
        .withSuccessHandler(function () {
          document.getElementById("login").style.display = "block";
          document.getElementById("dashboard").style.display = "none";
          $('#loadingModal').modal('hide');
        })
        .logout();
         
    }
  </script>
</body>
<!-- Source Code www.javabitpro.com -->
</html>


18. Untuk script pada cssjam.html, jsjam.html dan visit.html sudah kami sediakan di dalam file.

19. Klik ikon Save.

20. Klik tombol Terapkan/Deploy lalu pilih Deployment baru/New deployment.


21. Pastikan jenisnya adalah Aplikasi web dan hak aksesnya adalah Siapa saja/Anyone lalu klik Terapkan/Deploy.


22. Salin atau klik URL yang sudah di Deploy.


SELESAI !!!






Previous Post Next Post

Promo