3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Google Apps Script 公式チュートリアルのプチ改造 (Quickstart: Menus and Custom Functions)

Posted at

はじめに

Google Apps Scriptの公式サイトのチュートリアル「Quickstart: Menus and Custom Functions」を多くの人が写経していると思います。本記事では、チュートリアルの内容の理解を深めるために、自分なりに「プチ改造」した内容を記載します。

プチ改造内容

オリジナルのソースコードに、以下2点の改造を加えます。

  1. 日本語化する
  2. ルート検索のモードを変更する

ゴール

以下のように、オリジナルでは英語で表示されていたものを日本語にします。
image.png

また、ルート検索の結果も、日本語で表示されるようにします。さらに、オリジナルでは、ルート検索でのモードが「車による運転」ですが、これも「公共交通機関」に変更します。
image.png

手順

オリジナルのチュートリアル実施

まずは、オリジナルのチュートリアルを以下のサイトに従って行います。

Quickstart: Menus and Custom Functions

日本語化する

公式チュートリアルは、当然のことながら英語の表示となります。ルート検索の結果も以下のように英語で表示されます。
image.png

これを日本語にするには、「DirectionFinder」オブジェクトに以下のように言語設定をします。

コード.gs
var directionFinder = Maps.newDirectionFinder();
中略
directionFinder.setLanguage('ja'); // 言語設定を追加する

また、シート上に表示される文言も適宜、日本語に変更します。

ルート検索のモードを変更する

オリジナルでは、ルート検索でのモードが「車による運転(DRIVING)」ですが、これも「公共交通機関(TRANSIT)」に変更します。

また、モードが「公共交通機関(TRANSIT)」の場合は、出発時刻または到着時刻を指定する必要があります。こちらの例では、出発時刻として現在時刻を設定しています。

コード.gs
var directionFinder = Maps.newDirectionFinder();
中略
directionFinder.setMode(Maps.DirectionFinder.Mode.TRANSIT); // 「公共交通機関(TRANSIT)に変更」
directionFinder.setDepart(new Date()); // 出発時刻に現在時刻を設定

なお、モードに指定できるのは、以下の値となります。

  • DRIVING
  • WALKING
  • BICYCLING
  • TRANSIT

詳細は、公式リファレンスを参照してください。
Google Apps Script - REFERENCE - Maps - Enum Mode

ソースコード

以下にすべてのソースコードを記載します。

コード.gs
function onOpen() {
  var spreadsheet = SpreadsheetApp.getActive();
  var menuItems = [
    {name: 'シートを準備...', functionName: 'prepareSheet_'},
    {name: 'ルート生成...', functionName: 'generateStepByStep_'},
  ];
  spreadsheet.addMenu('ルート検索', menuItems);
}
    
function metersToMiles(meters) {
  if (typeof meters != 'number') {
    return null;
  }
  return meters / 1000 * 0.6212371;
}
function drivingDistance(origin, destination) {
  var directions = getDirections_(origin, destination);
  return directions.routes[0].legs[0].distance.value;
}
function prepareSheet_() {
  var sheet = SpreadsheetApp.getActiveSheet().setName('設定');
  var headers = [
    '始点',
    '終点',
    '距離 (メートル)',
    '距離 (マイル)'
  ];
  var initialDate = [
    '350 5th Ave, New York, NY 10118',
    '405 Lexington Ave, New York, NY 10174'
  ];
  sheet.getRange('A1:D1').setValues([headers]).setFontWeight('bold');
  sheet.getRange('A2:B2').setValues([initialDate]);
  sheet.setFrozenRows(1);
  sheet.autoResizeColumns(1, 4);
}

function generateStepByStep_() {
  var spreadsheet = SpreadsheetApp.getActive();
  var settingsSheet = spreadsheet.getSheetByName('設定');
  settingsSheet.activate();

  var selectedRow = Browser.inputBox('ルート生成',
                                 'ルート生成する対象の行番号を指定してください' + 
                                     ' (例: "2"):',
                                 Browser.Buttons.OK_CANCEL);
  if (selectedRow == 'cancel') {
    return;
  }

  var rowNumber = Number(selectedRow);
  if (isNaN(rowNumber) || rowNumber < 2 ||
      rowNumber > settingsSheet.getLastRow() ) {
    Browser.msgBox('Error',
                  Utilities.formatString('Row "%s" is not valid.', selectedRow),
                   Browser.Buttons.OK);
    return;
  }
  var row = settingsSheet.getRange(rowNumber, 1, 1, 2);
  var rowValues = row.getValues();
  var origin = rowValues[0][0];
  var destination = rowValues[0][1];
  if (!origin || !destination) {
    Browser.msgBox('Error', 'Row does not contain two addresses.',
                   Browser.Buttons.OK);
    return;
  }
  var directions = getDirections_(origin, destination);
  
  var sheetName = 'ルート 行: ' + rowNumber;
  var directionsSheet = spreadsheet.getSheetByName(sheetName);
  if (directionsSheet) {
    directionsSheet.clear();
    directionsSheet.activate();
  } else {
    directionsSheet = 
      spreadsheet.insertSheet(sheetName, spreadsheet.getNumSheets());
  }
  var sheetTitle = Utilities.formatString('ルート[始点(%s) ~ 終点(%s)])',
                                          origin, destination);
  var headers  = [
    [sheetTitle, '', ''],
    ['ステップ', '距離 (メートル)', '距離 (マイル)']
  ];
  var newRows = [];
  for (var i = 0; i < directions.routes[0].legs[0].steps.length; i++) {
    var step = directions.routes[0].legs[0].steps[i];
    
    var instructions = step.html_instructions.replace(/<br|<div.*?>/g, '\n')
    .replace(/<.*?>/g, '');
    newRows.push([
      instructions,
      step.distance.value
    ]);
  }
  directionsSheet.getRange(1, 1, headers.length, 3).setValues(headers);
  directionsSheet.getRange(headers.length + 1, 1, newRows.length, 2)
    .setValues(newRows);
  directionsSheet.getRange(headers.length + 1, 3, newRows.length, 1)
    .setFormulaR1C1('=METERSTOMILES(R[0]C[-1])');
  
  directionsSheet.getRange('A1:C1').merge().setBackground('#ddddee');
  directionsSheet.getRange('A1:2').setFontWeight('bold');
  directionsSheet.setColumnWidth(1, 500);
  directionsSheet.getRange('B2:C').setVerticalAlignment('top');
  directionsSheet.getRange('C2:C').setNumberFormat('0.00');
  var stepsRange = directionsSheet.getDataRange()
    .offset(2, 0, directionsSheet.getLastRow() -2);
  setAlternatingRowBackgroundColors_(stepsRange, '#ffffff', '#eeeeee');
  directionsSheet.setFrozenRows(2);
  SpreadsheetApp.flush();
}

function setAlternatingRowBackgroundColors_(range, oddColor, evenColor) {
  var backgrounds = [];
  for (var row = 1; row <= range.getNumRows(); row++) {
    var rowBackgrounds = [];
    for (var column = 1; column <= range.getNumColumns(); column++) {
      if (row % 2 == 0) {
        rowBackgrounds.push(evenColor);
      } else {
        rowBackgrounds.push(oddColor);
      }
    }
    backgrounds.push(rowBackgrounds);
  }
  range.setBackgrounds(backgrounds);
}

function getDirections_(origin, destination) {
  var directionFinder = Maps.newDirectionFinder();
  directionFinder.setOrigin(origin);
  directionFinder.setDestination(destination);
  directionFinder.setMode(Maps.DirectionFinder.Mode.TRANSIT);
  directionFinder.setDepart(new Date());
  directionFinder.setLanguage('ja');

  var directions = directionFinder.getDirections();
  if (directions.status !== 'OK') {
    throw directions.error_message;
  }
  return directions;
}

最後に

プログラムを学ぶうえで「写経」はとても重要です。しかし、ソースコードをより深く理解するためには、「写経」した内容にオリジナルの改造を加えることがとても有効です。
今回もたいした改造はしていないですが、単に「写経」するよりは、確実に自分の身になっていると実感します。
みなさんもぜひ、プチ改造しましょう!

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?