{"id":17493,"date":"2026-09-26T22:42:54","date_gmt":"2026-09-26T13:42:54","guid":{"rendered":"https:\/\/f1-lap-time.com\/?page_id=17493"},"modified":"2026-09-27T10:12:41","modified_gmt":"2026-09-27T01:12:41","slug":"%e3%80%90%e3%82%a2%e3%82%bc%e3%83%ab%e3%83%90%e3%82%a4%e3%82%b8%e3%83%a3%e3%83%b3gp%e3%80%91%e3%83%a9%e3%83%83%e3%83%97%e3%82%bf%e3%82%a4%e3%83%a0%e3%81%a8%e3%82%ae%e3%83%a3%e3%83%83%e3%83%97","status":"publish","type":"page","link":"https:\/\/f1-lap-time.com\/?page_id=17493","title":{"rendered":"\u3010\u30a2\u30bc\u30eb\u30d0\u30a4\u30b8\u30e3\u30f3GP\u3011\u30e9\u30c3\u30d7\u30bf\u30a4\u30e0\u3068\u30ae\u30e3\u30c3\u30d7"},"content":{"rendered":"\n<!--\nWordPress\u300c\u30ab\u30b9\u30bf\u30e0HTML\u300d\u30d6\u30ed\u30c3\u30af\u306e\u65e2\u5b58\u30b3\u30fc\u30c9\u3092\u3001\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5168\u6587\u3067\u7f6e\u304d\u63db\u3048\u3066\u304f\u3060\u3055\u3044\u3002\n\u4e0b\u306e DATA_FILE \u306f\u73fe\u5728\u3068\u540c\u3058\u76f8\u5bfeURL\u3067\u3059\u3002\u5fc5\u8981\u306b\u5fdc\u3058\u3066TSV\u306e\u516c\u958bURL\u3078\u5909\u66f4\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n\u30c9\u30e9\u30a4\u30d0\u30fc\u306e\u4e26\u3073\u30fb\u540d\u524d\u30fb\u914d\u8272\u306f\u5143\u30b3\u30fc\u30c9\u3092\u7dad\u6301\u3057\u3066\u3044\u307e\u3059\u3002\n-->\n<style>\n.race-lap-widget{width:100%;max-width:1200px;background:#fff;color:#000;font-family:\"Times New Roman\",Times,serif;line-height:1.5}\n.race-lap-widget .race-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:12px 0}\n.race-lap-widget .race-drivers{display:flex;flex-wrap:wrap;gap:6px}\n.race-lap-widget button,.race-lap-widget input,.race-lap-widget select{font:inherit;box-sizing:border-box;border:1px solid #aaa;border-radius:4px;box-shadow:none;text-transform:none;letter-spacing:normal;line-height:1.4}\n.race-lap-widget button{padding:6px 10px;background:#f5f5f5;color:#000;cursor:pointer;min-height:36px}\n.race-lap-widget button:disabled{cursor:wait;opacity:.5}\n.race-lap-widget button:focus-visible,.race-lap-widget input:focus-visible,.race-lap-widget select:focus-visible{outline:3px solid #2865c7;outline-offset:2px}\n.race-lap-widget .race-driver{font-weight:bold;border:2px solid transparent;min-width:62px}\n.race-lap-widget .race-driver[aria-pressed=\"true\"]{border-color:#000}\n.race-lap-widget .race-driver .race-check{display:inline-block;width:1em}\n.race-lap-widget label{display:inline-flex;align-items:center;gap:5px;color:#000;font-weight:normal;max-width:100%}\n.race-lap-widget label>span{white-space:nowrap;flex-shrink:0}\n.race-lap-widget .race-reference-label{flex-wrap:wrap;gap:8px}\n.race-lap-widget .race-reference{width:auto;min-width:150px;flex:0 1 auto}\n.race-lap-widget .race-language{justify-content:flex-end}\n.race-lap-widget [data-lang][aria-pressed=\"true\"]{background:#222;color:#fff;border-color:#222}\n.race-lap-widget input{width:105px;padding:6px;background:#fff;color:#000}\n.race-lap-widget select{padding:6px;background:#fff;color:#000;max-width:100%}\n.race-lap-widget .race-chart{width:100%;height:520px}\n.race-lap-widget .race-gap-chart{height:650px}\n.race-lap-widget .race-note{font-size:14px;margin:8px 0;color:#444}\n.race-lap-widget .race-error{color:#a40000;min-height:1.5em;margin:4px 0}\n.race-lap-widget h2{color:#000;margin:24px 0 10px;font-family:inherit}\n@media(max-width:600px){.race-lap-widget .race-chart{height:440px}.race-lap-widget .race-gap-chart{height:510px}}\n<\/style>\n\n<div id=\"raceLapWidget\" class=\"race-lap-widget\" lang=\"ja\">\n  <div class=\"race-controls race-language\" role=\"group\" aria-label=\"Language\"><button type=\"button\" data-lang=\"ja\" aria-pressed=\"true\">\u65e5\u672c\u8a9e<\/button><button type=\"button\" data-lang=\"en\" aria-pressed=\"false\">English<\/button><\/div>\n  <p class=\"race-status\" role=\"status\">\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3093\u3067\u3044\u307e\u3059\u2026<\/p>\n  <div class=\"race-interactive\" hidden=\"\">\n    <div class=\"race-controls\"><strong>Drivers:<\/strong><button type=\"button\" data-action=\"select\">Select All<\/button><button type=\"button\" data-action=\"clear\">Clear All<\/button><\/div>\n    <div class=\"race-drivers\" data-i18n-aria=\"driversAria\" aria-label=\"\u8868\u793a\u3059\u308b\u30c9\u30e9\u30a4\u30d0\u30fc\"><\/div>\n    <p class=\"race-note\"><span data-i18n=\"driversNote\">\u30c9\u30e9\u30a4\u30d0\u30fc\u3092\u9078\u3076\u3068\u4e21\u30b0\u30e9\u30d5\u306b\u8868\u793a\u3057\u307e\u3059\u3002\u51e1\u4f8b\u306f\u9078\u629e\u3057\u305f\u9806\u306b\u4e26\u3073\u307e\u3059\u3002<\/span><\/p>\n    <form class=\"race-controls\" data-form=\"laps\" novalidate=\"\">\n      <strong><span data-i18n=\"laps\">\u8868\u793a\u5468\u56de\uff08\u4e21\u30b0\u30e9\u30d5\u5171\u901a\uff09:<\/span><\/strong>\n      <label><span data-i18n=\"start\">\u958b\u59cb<\/span><input name=\"min\" type=\"number\" min=\"1\" step=\"1\" required=\"\"><\/label>\n      <label><span data-i18n=\"end\">\u7d42\u4e86<\/span><input name=\"max\" type=\"number\" min=\"1\" step=\"1\" required=\"\"><\/label>\n      <button type=\"submit\"><span data-i18n=\"apply\">\u9069\u7528<\/span><\/button><button type=\"button\" data-action=\"reset-laps\"><span data-i18n=\"allLaps\">\u5168\u5468\u56de\u306b\u623b\u3059<\/span><\/button>\n    <\/form>\n    <p class=\"race-error\" data-error=\"laps\" role=\"alert\"><\/p>\n\n    <h2>Lap Times<\/h2>\n\n    <form class=\"race-controls\" data-form=\"time\" novalidate=\"\">\n      <label><span>Fastest<\/span><input name=\"min\" type=\"text\" placeholder=\"1:20.000\" required=\"\" aria-label=\"Fastest\"><\/label>\n      <label><span>Slowest<\/span><input name=\"max\" type=\"text\" placeholder=\"1:28.000\" required=\"\" aria-label=\"Slowest\"><\/label>\n      <button type=\"submit\"><span data-i18n=\"apply\">\u9069\u7528<\/span><\/button><button type=\"button\" data-action=\"reset-time\"><span data-i18n=\"reset\">\u521d\u671f\u7bc4\u56f2\u306b\u623b\u3059<\/span><\/button>\n    <\/form>\n    <p class=\"race-note\"><span data-i18n=\"format\">\u30bf\u30a4\u30e0\u306f\u300c1:20.000\u300d\u307e\u305f\u306f\u300c80.000\u300d\u3067\u5165\u529b\u3067\u304d\u307e\u3059\u3002\u901f\u3044\u30bf\u30a4\u30e0\u3092\u4e0a\u306b\u8868\u793a\u3057\u307e\u3059\u3002<\/span><\/p>\n    <p class=\"race-error\" data-error=\"time\" role=\"alert\"><\/p>\n\n    <div class=\"race-chart race-time-chart\" data-i18n-aria=\"timeAria\" aria-label=\"\u30e9\u30c3\u30d7\u30bf\u30a4\u30e0\u30b0\u30e9\u30d5\"><\/div>\n    <p class=\"race-note\"><span data-i18n=\"white\">\u767d\u4e38\uff1a\u524d\u306e\u30c9\u30e9\u30a4\u30d0\u30fc\u3068\u306e\u5dee\u304c2\u79d2\u4ee5\u5185\u3002<\/span><\/p>\n\n    <h2 class=\"race-gap-title\">Gap to Leader<\/h2>\n\n    <div class=\"race-controls\">\n      <label class=\"race-reference-label\">\n        <span data-i18n=\"reference\">\u6bd4\u8f03\u57fa\u6e96<\/span>\n        <select class=\"race-reference\">\n          <option value=\"leader\" data-i18n=\"leader\">Leader\uff08\u5404\u5468\u306e\u9996\u4f4d\uff09<\/option>\n        <\/select>\n      <\/label>\n    <\/div>\n\n    <form class=\"race-controls\" data-form=\"gap\" novalidate=\"\">\n      <label><span data-i18n=\"min\">\u6700\u5c0f\u5024\uff08\u79d2\uff09<\/span><input name=\"min\" type=\"number\" step=\"any\" required=\"\"><\/label>\n      <label><span data-i18n=\"max\">\u6700\u5927\u5024\uff08\u79d2\uff09<\/span><input name=\"max\" type=\"number\" step=\"any\" required=\"\"><\/label>\n      <button type=\"submit\"><span data-i18n=\"apply\">\u9069\u7528<\/span><\/button><button type=\"button\" data-action=\"reset-gap\"><span data-i18n=\"reset\">\u521d\u671f\u7bc4\u56f2\u306b\u623b\u3059<\/span><\/button>\n    <\/form>\n\n    <p class=\"race-note\"><span data-i18n=\"gapNote\">\u30d7\u30e9\u30b9\uff1d\u57fa\u6e96\u3088\u308a\u5f8c\u65b9\u3001\u30de\u30a4\u30ca\u30b9\uff1d\u524d\u65b9\u3002\u57fa\u6e96\u3092\u5207\u308a\u66ff\u3048\u308b\u3068\u7e26\u8ef8\u306f\u521d\u671f\u7bc4\u56f2\u306b\u623b\u308a\u307e\u3059\u3002<\/span><\/p>\n    <p class=\"race-error\" data-error=\"gap\" role=\"alert\"><\/p>\n\n    <div class=\"race-chart race-gap-chart\" data-i18n-aria=\"gapAria\" aria-label=\"\u30ae\u30e3\u30c3\u30d7\u30b0\u30e9\u30d5\"><\/div>\n  <\/div>\n<\/div>\n\n<script src=\"https:\/\/cdn.plot.ly\/plotly-2.26.0.min.js\"><\/script>\n\n<script>\n(() => {\n  \"use strict\";\n\n  const root = document.getElementById(\"raceLapWidget\");\n  const DATA_FILE = \"baku_2026_lap_times.tsv\";\n\n  \/\/ [\u7565\u79f0, TSV\u306e\u5217\u540d, \u8272]\n  const driverConfig = [\n    [\"NOR\",\"Lando NORRIS\",\"rgb(255,128,0)\"],\n    [\"PIA\",\"Oscar PIASTRI\",\"rgb(255,192,128)\"],\n\n    [\"RUS\",\"George RUSSELL\",\"rgb(166,166,166)\"],\n    [\"ANT\",\"Kimi ANTONELLI\",\"rgb(0,176,80)\"],\n\n    [\"VER\",\"Max VERSTAPPEN\",\"rgb(0,32,96)\"],\n    [\"HAD\",\"Isack HADJAR\",\"rgb(102,255,0)\"],\n\n    [\"LEC\",\"Charles LECLERC\",\"rgb(255,0,0)\"],\n    [\"HAM\",\"Lewis HAMILTON\",\"rgb(255,192,192)\"],\n\n    [\"ALB\",\"Alexander ALBON\",\"rgb(192,176,224)\"],\n    [\"SAI\",\"Carlos SAINZ\",\"rgb(0,112,192)\"],\n\n    [\"LAW\",\"Liam LAWSON\",\"rgb(180,198,231)\"],\n    [\"LIN\",\"Arvid LINDBLAD\",\"rgb(112,48,160)\"],\n\n    [\"ALO\",\"Fernando ALONSO\",\"rgb(0,176,240)\"],\n    [\"STR\",\"Lance STROLL\",\"rgb(0,112,112)\"],\n\n    [\"OCO\",\"Esteban OCON\",\"rgb(0,0,0)\"],\n    [\"BEA\",\"Oliver BEARMAN\",\"rgb(128,128,128)\"],\n\n    [\"HUL\",\"Nico HULKENBERG\",\"rgb(255,193,37)\"],\n    [\"BOR\",\"Gabriel BORTOLETO\",\"rgb(192,0,0)\"],\n\n    [\"GAS\",\"Pierre GASLY\",\"rgb(0,128,255)\"],\n    [\"COL\",\"Franco COLAPINTO\",\"rgb(255,0,255)\"],\n\n    [\"PER\",\"Sergio PEREZ\",\"rgb(255,140,0)\"],\n    [\"BOT\",\"Valtteri BOTTAS\",\"rgb(0,150,136)\"]\n  ];\n\n  const WHITE_TEXT = new Set([\n    \"VER\",\"LIN\",\"STR\",\"OCO\",\"BEA\",\"SAI\",\"GAS\",\"BOR\",\"BOT\"\n  ]);\n\n  const $ = selector => root.querySelector(selector);\n  const form = name => $(`[data-form=\"${name}\"]`);\n  const field = (name, key) => form(name).elements.namedItem(key);\n\n  const error = (name, key = \"\", params = {}) => {\n    errors[name] = {key, params};\n    $(`[data-error=\"${name}\"]`).textContent = key ? t(key, params) : \"\";\n  };\n\n  const timeChart = $(\".race-time-chart\");\n  const gapChart = $(\".race-gap-chart\");\n  const status = $(\".race-status\");\n\n  const messages = {\n    ja: {\n      driversNote: \"\u30c9\u30e9\u30a4\u30d0\u30fc\u3092\u9078\u3076\u3068\u4e21\u30b0\u30e9\u30d5\u306b\u8868\u793a\u3057\u307e\u3059\u3002\u51e1\u4f8b\u306f\u9078\u629e\u3057\u305f\u9806\u306b\u4e26\u3073\u307e\u3059\u3002\",\n      laps: \"\u8868\u793a\u5468\u56de\uff08\u4e21\u30b0\u30e9\u30d5\u5171\u901a\uff09:\",\n      start: \"\u958b\u59cb\",\n      end: \"\u7d42\u4e86\",\n      apply: \"\u9069\u7528\",\n      allLaps: \"\u5168\u5468\u56de\u306b\u623b\u3059\",\n      reset: \"\u521d\u671f\u7bc4\u56f2\u306b\u623b\u3059\",\n      format: \"\u30bf\u30a4\u30e0\u306f\u300c1:20.000\u300d\u307e\u305f\u306f\u300c80.000\u300d\u3067\u5165\u529b\u3067\u304d\u307e\u3059\u3002\u901f\u3044\u30bf\u30a4\u30e0\u3092\u4e0a\u306b\u8868\u793a\u3057\u307e\u3059\u3002\",\n      white: \"\u767d\u4e38\uff1a\u524d\u306e\u30c9\u30e9\u30a4\u30d0\u30fc\u3068\u306e\u5dee\u304c2\u79d2\u4ee5\u5185\u3002\",\n      reference: \"\u6bd4\u8f03\u57fa\u6e96\",\n      leader: \"Leader\uff08\u5404\u5468\u306e\u9996\u4f4d\uff09\",\n      min: \"\u6700\u5c0f\u5024\uff08\u79d2\uff09\",\n      max: \"\u6700\u5927\u5024\uff08\u79d2\uff09\",\n      gapNote: \"\u30d7\u30e9\u30b9\uff1d\u57fa\u6e96\u3088\u308a\u5f8c\u65b9\u3001\u30de\u30a4\u30ca\u30b9\uff1d\u524d\u65b9\u3002\u57fa\u6e96\u3092\u5207\u308a\u66ff\u3048\u308b\u3068\u7e26\u8ef8\u306f\u521d\u671f\u7bc4\u56f2\u306b\u623b\u308a\u307e\u3059\u3002\",\n      loading: \"\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3093\u3067\u3044\u307e\u3059\u2026\",\n      loadError: \"\u30b0\u30e9\u30d5\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30da\u30fc\u30b8\u3092\u518d\u8aad\u307f\u8fbc\u307f\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      updateError: \"\u30b0\u30e9\u30d5\u3092\u66f4\u65b0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30da\u30fc\u30b8\u3092\u518d\u8aad\u307f\u8fbc\u307f\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      invalid: \"\u6709\u52b9\u306a\u6700\u5c0f\u5024\u30fb\u6700\u5927\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      invalidTime: \"Fastest\u30fbSlowest\u306b\u6709\u52b9\u306a\u30bf\u30a4\u30e0\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      lapError: \"\u958b\u59cb\u30fb\u7d42\u4e86\u306f{min}\u301c{max}\u306e\u6574\u6570\u3067\u3001\u958b\u59cb\u2266\u7d42\u4e86\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      timeError: \"Slowest\u306fFastest\u3088\u308a0.001\u79d2\u4ee5\u4e0a\u5927\u304d\u304f\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      gapError: \"\u6700\u5927\u5024\u306f\u6700\u5c0f\u5024\u3088\u308a\u5927\u304d\u304f\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n      driversAria: \"\u8868\u793a\u3059\u308b\u30c9\u30e9\u30a4\u30d0\u30fc\",\n      timeAria: \"\u30e9\u30c3\u30d7\u30bf\u30a4\u30e0\u30b0\u30e9\u30d5\",\n      gapAria: \"\u30ae\u30e3\u30c3\u30d7\u30b0\u30e9\u30d5\"\n    },\n\n    en: {\n      driversNote: \"Select drivers to show them on both charts. The legend follows your selection order.\",\n      laps: \"Lap range (both charts):\",\n      start: \"From\",\n      end: \"To\",\n      apply: \"Apply\",\n      allLaps: \"All Laps\",\n      reset: \"Reset Range\",\n      format: \"Enter a time as 1:20.000 or 80.000 seconds. Faster times appear higher.\",\n      white: \"White circle: within 2 seconds of the driver ahead.\",\n      reference: \"Reference\",\n      leader: \"Leader (each lap)\",\n      min: \"Minimum (s)\",\n      max: \"Maximum (s)\",\n      gapNote: \"Positive = behind the reference driver; negative = ahead. Changing the reference resets the vertical range.\",\n      loading: \"Loading data\u2026\",\n      loadError: \"Unable to load the charts. Please reload the page.\",\n      updateError: \"Unable to update the charts. Please reload the page.\",\n      invalid: \"Enter valid minimum and maximum values.\",\n      invalidTime: \"Enter valid times for Fastest and Slowest.\",\n      lapError: \"Enter whole laps from {min} to {max}, with From no greater than To.\",\n      timeError: \"Slowest must be at least 0.001 seconds greater than Fastest.\",\n      gapError: \"Maximum must be greater than Minimum.\",\n      driversAria: \"Drivers to display\",\n      timeAria: \"Lap time chart\",\n      gapAria: \"Gap chart\"\n    }\n  };\n\n  let language = \"ja\";\n\n  const t = (key, params = {}) => {\n    let text = messages[language][key] || key;\n\n    Object.entries(params).forEach(([name,value]) => {\n      text = text.replace(\"{\" + name + \"}\", String(value));\n    });\n\n    return text;\n  };\n\n  let statusKey = \"loading\";\n  const errors = {};\n\n  function setLanguage(next) {\n    language = next === \"en\" ? \"en\" : \"ja\";\n\n    root.setAttribute(\"lang\", language);\n\n    root.querySelectorAll(\"[data-i18n]\").forEach(el => {\n      el.textContent = t(el.getAttribute(\"data-i18n\"));\n    });\n\n    root.querySelectorAll(\"[data-i18n-aria]\").forEach(el => {\n      el.setAttribute(\n        \"aria-label\",\n        t(el.getAttribute(\"data-i18n-aria\"))\n      );\n    });\n\n    root.querySelectorAll(\"[data-lang]\").forEach(el => {\n      el.setAttribute(\n        \"aria-pressed\",\n        String(el.getAttribute(\"data-lang\") === language)\n      );\n    });\n\n    status.textContent = t(statusKey);\n\n    Object.entries(errors).forEach(([name,entry]) => {\n      $(`[data-error=\"${name}\"]`).textContent =\n        entry.key ? t(entry.key,entry.params) : \"\";\n    });\n  }\n\n  root.querySelectorAll(\"[data-lang]\").forEach(el => {\n    el.onclick = () => setLanguage(el.getAttribute(\"data-lang\"));\n  });\n\n  setLanguage(\"ja\");\n\n  const parseTime = value => {\n    const s = String(value ?? \"\").trim();\n\n    if (\/^\\d+(?:\\.\\d+)?$\/.test(s)) {\n      const n = Number(s);\n      return Number.isFinite(n) ? n : null;\n    }\n\n    const match = \/^(\\d+):(\\d{1,2}(?:\\.\\d+)?)$\/.exec(s);\n\n    if (!match || Number(match[2]) >= 60) {\n      return null;\n    }\n\n    const n = Number(match[1]) * 60 + Number(match[2]);\n\n    return Number.isFinite(n) ? n : null;\n  };\n\n  const formatTime = seconds => {\n    const ms = Math.round(seconds * 1000);\n\n    return (\n      Math.floor(ms \/ 60000) +\n      \":\" +\n      (Math.floor(ms \/ 1000) % 60).toString().padStart(2,\"0\") +\n      \".\" +\n      (ms % 1000).toString().padStart(3,\"0\")\n    );\n  };\n\n  function timeAxis(min, max) {\n    const target = (max - min) \/ 8;\n    const power = 10 ** Math.floor(Math.log10(target));\n    const step = [1,2,5,10]\n      .map(n => n * power)\n      .find(n => n >= target);\n\n    const ticks = [];\n    const start = Math.ceil(min \/ step) * step;\n\n    for (let i = 0; i < 20; i++) {\n      const v = Number((start + i * step).toPrecision(12));\n\n      if (v > max + step * 1e-8) {\n        break;\n      }\n\n      ticks.push(v);\n    }\n\n    return {\n      \"yaxis.range\": [max,min],\n      \"yaxis.autorange\": false,\n      \"yaxis.tickmode\": \"array\",\n      \"yaxis.tickvals\": ticks,\n      \"yaxis.ticktext\": ticks.map(formatTime)\n    };\n  }\n\n  async function init() {\n    if (!root) {\n      throw new Error(\"\u30b0\u30e9\u30d5\u306e\u8868\u793a\u9818\u57df\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\");\n    }\n\n    if (!window.Plotly) {\n      throw new Error(\n        \"Plotly\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\u3002WordPress\u304cscript\u30bf\u30b0\u3092\u524a\u9664\u3057\u3066\u3044\u306a\u3044\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002\"\n      );\n    }\n\n    const Plotly = window.Plotly;\n\n    const tsv = await fetch(DATA_FILE).then(response => {\n      if (!response.ok) {\n        throw new Error(\n          `TSV\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\uff08HTTP ${response.status}\uff09\u3002DATA_FILE\u306eURL\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002`\n        );\n      }\n\n      return response.text();\n    });\n\n    const lines = tsv\n      .replace(\/^\\uFEFF\/, \"\")\n      .split(\/\\r?\\n\/)\n      .filter(line => line.trim() !== \"\");\n\n    if (lines.length < 2) {\n      throw new Error(\"TSV\u306b\u30e9\u30c3\u30d7\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u305b\u3093\u3002\");\n    }\n\n    const headers = lines[0]\n      .split(\"\\t\")\n      .map(s => s.trim());\n\n    const columns = driverConfig.map(([,full]) =>\n      headers.indexOf(full)\n    );\n\n    if (columns.every(index => index < 0)) {\n      throw new Error(\n        \"TSV\u306e\u30c9\u30e9\u30a4\u30d0\u30fc\u5217\u540d\u304c\u8a2d\u5b9a\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093\u3002\"\n      );\n    }\n\n    const rows = lines\n      .slice(1)\n      .map(line => line.split(\"\\t\"));\n\n    const laps = rows.map(row => Number(row[0]));\n\n    if (\n      laps.some(\n        (lap,i) =>\n          !Number.isInteger(lap) ||\n          lap < 1 ||\n          (i > 0 ? lap <= laps[i-1] : false)\n      )\n    ) {\n      throw new Error(\n        \"TSV\u306e\u5468\u56de\u756a\u53f7\u306f\u3001\u91cd\u8907\u306e\u306a\u3044\u6607\u9806\u306e\u6b63\u306e\u6574\u6570\u306b\u3057\u3066\u304f\u3060\u3055\u3044\u3002\"\n      );\n    }\n\n    const times = columns.map(column =>\n      rows.map(row => {\n        const raw =\n          column < 0\n            ? \"\"\n            : (row[column] ?? \"\").trim();\n\n        const value = parseTime(raw);\n\n        return value === null\n          ? null\n          : (value > 0 ? value : null);\n      })\n    );\n\n    let fastest = Infinity;\n\n    times.forEach(values => {\n      values.forEach(v => {\n        if (v !== null) {\n          fastest = Math.min(fastest,v);\n        }\n      });\n    });\n\n    if (!Number.isFinite(fastest)) {\n      throw new Error(\"\u6709\u52b9\u306a\u30e9\u30c3\u30d7\u30bf\u30a4\u30e0\u304c\u3042\u308a\u307e\u305b\u3093\u3002\");\n    }\n\n    const cum = times.map(values => {\n      let total = 0;\n      let known = true;\n\n      return values.map((value,i) => {\n        if (\n          value === null ||\n          laps[i] !== (i === 0 ? 1 : laps[i-1] + 1)\n        ) {\n          known = false;\n        }\n\n        if (!known) {\n          return null;\n        }\n\n        total += value;\n\n        return total;\n      });\n    });\n\n    const within = driverConfig.map(() =>\n      laps.map(() => false)\n    );\n\n    const leaderTimes = laps.map((_,i) => {\n      const running = driverConfig\n        .map((_,d) => d)\n        .filter(d => cum[d][i] !== null)\n        .sort((a,b) => cum[a][i] - cum[b][i]);\n\n      for (let j = 1; j < running.length; j++) {\n        if (\n          cum[running[j]][i] -\n          cum[running[j-1]][i] <= 2\n        ) {\n          within[running[j]][i] = true;\n        }\n      }\n\n      return running.length\n        ? cum[running[0]][i]\n        : null;\n    });\n\n    let reference = \"leader\";\n\n    const gapValues = () => {\n      const base =\n        reference === \"leader\"\n          ? leaderTimes\n          : cum[Number(reference)];\n\n      return cum.map(values =>\n        values.map((v,i) =>\n          v === null || base[i] === null\n            ? null\n            : v - base[i]\n        )\n      );\n    };\n\n    const gapDefault = () =>\n      reference === \"leader\"\n        ? [0,250]\n        : [-250,250];\n\n    const gapLabel = () =>\n      reference === \"leader\"\n        ? \"Leader\"\n        : driverConfig[Number(reference)][0];\n\n    const gapHover = () =>\n      `%{fullData.name}<br>` +\n      `Lap %{x}<br>` +\n      `Gap to ${gapLabel()}: %{y:+.3f} s` +\n      `<extra><\/extra>`;\n\n    const initialTime = [\n      Math.floor(fastest),\n      Math.floor(fastest) + 8\n    ];\n\n    const wholeLaps = [\n      laps[0],\n      laps[laps.length - 1]\n    ];\n\n    const xRange = (min,max) =>\n      min === max\n        ? [min - .5,max + .5]\n        : [min,max];\n\n    const lapTraces = [];\n    const gaps = gapValues();\n    const gapTraces = [];\n\n    driverConfig.forEach(([d,,color],idx) => {\n      lapTraces.push({\n        name: d,\n        x: laps,\n        y: times[idx],\n        customdata: times[idx].map(t =>\n          t === null ? \"\" : formatTime(t)\n        ),\n        mode: \"lines\",\n        connectgaps: false,\n        line: {\n          color,\n          width: 2\n        },\n        visible: false,\n        showlegend: false,\n        hovertemplate:\n          \"%{fullData.name}<br>\" +\n          \"Lap %{x}<br>\" +\n          \"Time: %{customdata}\" +\n          \"<extra><\/extra>\"\n      });\n\n      lapTraces.push({\n        name: d,\n        x: laps,\n        y: times[idx],\n        mode: \"markers\",\n        marker: {\n          size: 6,\n          color: within[idx].map(f =>\n            f ? \"#fff\" : color\n          ),\n          symbol: \"circle\",\n          line: {\n            color,\n            width: 2\n          }\n        },\n        hoverinfo: \"skip\",\n        visible: false,\n        showlegend: false\n      });\n\n      gapTraces.push({\n        name: d,\n        x: laps,\n        y: gaps[idx],\n        mode: \"lines\",\n        connectgaps: false,\n        line: {\n          color,\n          width: 2\n        },\n        visible: false,\n        showlegend: false,\n        hovertemplate: gapHover()\n      });\n    });\n\n    const font = {\n      family: \"Times New Roman, Times, serif\"\n    };\n\n    const layout = title => ({\n      font,\n      legend: {\n        itemclick: false,\n        itemdoubleclick: false,\n        orientation: \"h\",\n        y: -.2,\n        x: 0\n      },\n      xaxis: {\n        title: {\n          text: \"Lap\"\n        },\n        range: xRange(...wholeLaps),\n        autorange: false,\n        tickformat: \"d\"\n      },\n      yaxis: {\n        title: {\n          text: title\n        },\n        autorange: false,\n        automargin: true\n      },\n      margin: {\n        t: 25,\n        r: 15,\n        b: 85,\n        l: 75\n      },\n      hovermode: \"closest\",\n      paper_bgcolor: \"#fff\",\n      plot_bgcolor: \"#fff\"\n    });\n\n    const lapLayout = layout(\"Time (m:s)\");\n    const axis = timeAxis(...initialTime);\n\n    Object.entries(axis).forEach(([key,value]) => {\n      lapLayout.yaxis[key.slice(6)] = value;\n    });\n\n    const gapLayout = layout(\"Gap (s)\");\n    gapLayout.yaxis.range = gapDefault();\n\n    $(\".race-interactive\").hidden = false;\n\n    root\n      .querySelectorAll(\"button,input,select\")\n      .forEach(el => {\n        el.disabled = true;\n      });\n\n    const config = {\n      responsive: true,\n      displaylogo: false,\n      scrollZoom: false,\n      doubleClick: false\n    };\n\n    await Promise.all([\n      Plotly.newPlot(\n        timeChart,\n        lapTraces,\n        lapLayout,\n        config\n      ),\n      Plotly.newPlot(\n        gapChart,\n        gapTraces,\n        gapLayout,\n        config\n      )\n    ]);\n\n    let busy = false;\n\n    async function run(action) {\n      if (busy) {\n        return;\n      }\n\n      busy = true;\n\n      root\n        .querySelectorAll(\"button,input,select\")\n        .forEach(el => {\n          el.disabled = true;\n        });\n\n      try {\n        await action();\n      }\n      catch (e) {\n        console.error(e);\n\n        status.hidden = false;\n        statusKey = \"updateError\";\n        status.textContent = t(statusKey);\n      }\n      finally {\n        busy = false;\n\n        root\n          .querySelectorAll(\"button,input,select\")\n          .forEach(el => {\n            el.disabled = false;\n          });\n      }\n    }\n\n    let legendCounter = 0;\n\n    const ranks = driverConfig.map(() => 0);\n    const selected = driverConfig.map(() => false);\n\n    const buttons = driverConfig.map(\n      ([d,,color],idx) => {\n        const button =\n          document.createElement(\"button\");\n\n        button.type = \"button\";\n        button.className = \"race-driver\";\n        button.style.backgroundColor = color;\n        button.style.color =\n          WHITE_TEXT.has(d)\n            ? \"#fff\"\n            : \"#000\";\n\n        button.setAttribute(\n          \"aria-pressed\",\n          \"false\"\n        );\n\n        button.setAttribute(\n          \"aria-label\",\n          d\n        );\n\n        const check =\n          document.createElement(\"span\");\n\n        check.className = \"race-check\";\n        check.setAttribute(\n          \"aria-hidden\",\n          \"true\"\n        );\n\n        button.append(\n          check,\n          document.createTextNode(d)\n        );\n\n        button.onclick = () =>\n          run(async () => {\n            selected[idx] = !selected[idx];\n\n            if (selected[idx]) {\n              ranks[idx] = ++legendCounter;\n            }\n\n            await applySelection();\n          });\n\n        $(\".race-drivers\")\n          .appendChild(button);\n\n        const option =\n          document.createElement(\"option\");\n\n        option.value = String(idx);\n        option.textContent = d;\n\n        $(\".race-reference\")\n          .appendChild(option);\n\n        return button;\n      }\n    );\n\n    function applySelection() {\n      buttons.forEach((button,i) => {\n        button.setAttribute(\n          \"aria-pressed\",\n          String(selected[i])\n        );\n\n        button.firstChild.textContent =\n          selected[i] ? \"\u2713\" : \"\";\n      });\n\n      return Promise.all([\n        Plotly.restyle(\n          timeChart,\n          {\n            visible: selected.flatMap(v => [v,v]),\n            showlegend: selected.flatMap(v => [v,false]),\n            legendrank: ranks.flatMap(v => [v,v])\n          }\n        ),\n\n        Plotly.restyle(\n          gapChart,\n          {\n            visible: selected,\n            showlegend: selected,\n            legendrank: ranks\n          }\n        )\n      ]);\n    }\n\n    $('[data-action=\"select\"]').onclick =\n      () =>\n        run(async () => {\n          legendCounter =\n            driverConfig.length;\n\n          selected.fill(true);\n\n          ranks.forEach((_,i) => {\n            ranks[i] = i + 1;\n          });\n\n          await applySelection();\n        });\n\n    $('[data-action=\"clear\"]').onclick =\n      () =>\n        run(async () => {\n          legendCounter = 0;\n          selected.fill(false);\n          ranks.fill(0);\n\n          await applySelection();\n        });\n\n    function setFields(\n      name,\n      range,\n      format = String\n    ) {\n      field(name,\"min\").value =\n        format(range[0]);\n\n      field(name,\"max\").value =\n        format(range[1]);\n    }\n\n    setFields(\n      \"laps\",\n      wholeLaps\n    );\n\n    setFields(\n      \"time\",\n      initialTime,\n      formatTime\n    );\n\n    setFields(\n      \"gap\",\n      gapDefault()\n    );\n\n    async function applyLaps(min,max) {\n      await Promise.all(\n        [timeChart,gapChart].map(chart =>\n          Plotly.relayout(\n            chart,\n            {\n              \"xaxis.range\": xRange(min,max),\n              \"xaxis.autorange\": false\n            }\n          )\n        )\n      );\n\n      setFields(\n        \"laps\",\n        [min,max]\n      );\n\n      error(\"laps\");\n    }\n\n    async function applyTime(min,max) {\n      await Plotly.relayout(\n        timeChart,\n        timeAxis(min,max)\n      );\n\n      setFields(\n        \"time\",\n        [min,max],\n        formatTime\n      );\n\n      error(\"time\");\n    }\n\n    async function applyGap(min,max) {\n      await Plotly.relayout(\n        gapChart,\n        {\n          \"yaxis.range\": [min,max],\n          \"yaxis.autorange\": false\n        }\n      );\n\n      setFields(\n        \"gap\",\n        [min,max]\n      );\n\n      error(\"gap\");\n    }\n\n    [\"laps\",\"time\",\"gap\"].forEach(name => {\n      form(name).onsubmit = event => {\n        event.preventDefault();\n\n        const rawMin =\n          field(name,\"min\")\n            .value\n            .trim();\n\n        const rawMax =\n          field(name,\"max\")\n            .value\n            .trim();\n\n        const min =\n          name === \"time\"\n            ? parseTime(rawMin)\n            : Number(rawMin);\n\n        const max =\n          name === \"time\"\n            ? parseTime(rawMax)\n            : Number(rawMax);\n\n        if (\n          !rawMin ||\n          !rawMax ||\n          !Number.isFinite(min) ||\n          !Number.isFinite(max)\n        ) {\n          error(\n            name,\n            name === \"time\"\n              ? \"invalidTime\"\n              : \"invalid\"\n          );\n\n          return;\n        }\n\n        if (name === \"laps\") {\n          if (\n            !Number.isInteger(min) ||\n            !Number.isInteger(max) ||\n            min > max ||\n            min < wholeLaps[0] ||\n            max > wholeLaps[1]\n          ) {\n            error(\n              name,\n              \"lapError\",\n              {\n                min: wholeLaps[0],\n                max: wholeLaps[1]\n              }\n            );\n\n            return;\n          }\n\n          run(() =>\n            applyLaps(min,max)\n          );\n        }\n        else {\n          if (\n            min >= max ||\n            (\n              name === \"time\"\n                ? max - min < .001\n                : false\n            )\n          ) {\n            error(\n              name,\n              name === \"time\"\n                ? \"timeError\"\n                : \"gapError\"\n            );\n\n            return;\n          }\n\n          run(() =>\n            name === \"time\"\n              ? applyTime(min,max)\n              : applyGap(min,max)\n          );\n        }\n      };\n    });\n\n    $('[data-action=\"reset-laps\"]').onclick =\n      () =>\n        run(() =>\n          applyLaps(...wholeLaps)\n        );\n\n    $('[data-action=\"reset-time\"]').onclick =\n      () =>\n        run(() =>\n          applyTime(...initialTime)\n        );\n\n    $('[data-action=\"reset-gap\"]').onclick =\n      () =>\n        run(() =>\n          applyGap(...gapDefault())\n        );\n\n    $(\".race-reference\").onchange =\n      () =>\n        run(async () => {\n          reference =\n            $(\".race-reference\").value;\n\n          await Plotly.update(\n            gapChart,\n            {\n              y: gapValues(),\n              hovertemplate: gapHover()\n            },\n            {\n              \"yaxis.range\": gapDefault(),\n              \"yaxis.autorange\": false\n            }\n          );\n\n          $(\".race-gap-title\").textContent =\n            \"Gap to \" + gapLabel();\n\n          setFields(\n            \"gap\",\n            gapDefault()\n          );\n\n          error(\"gap\");\n        });\n\n    root\n      .querySelectorAll(\"button,input,select\")\n      .forEach(el => {\n        el.disabled = false;\n      });\n\n    status.hidden = true;\n  }\n\n  init().catch(e => {\n    console.error(e);\n\n    $(\".race-interactive\").hidden = true;\n\n    status.hidden = false;\n    statusKey = \"loadError\";\n    status.textContent = t(statusKey);\n\n    root\n      .querySelectorAll(\"[data-lang]\")\n      .forEach(el => {\n        el.disabled = false;\n      });\n  });\n})();\n<\/script>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>\u65e5\u672c\u8a9eEnglish \u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3093\u3067\u3044\u307e\u3059\u2026 Drivers:Select AllClear All \u30c9\u30e9\u30a4\u30d0\u30fc\u3092\u9078\u3076\u3068\u4e21\u30b0\u30e9\u30d5\u306b\u8868\u793a\u3057\u307e\u3059\u3002\u51e1\u4f8b\u306f\u9078\u629e\u3057\u305f\u9806\u306b\u4e26\u3073\u307e\u3059\u3002 \u8868\u793a\u5468\u56de\uff08\u4e21\u30b0\u30e9\u30d5\u5171\u901a\uff09: \u958b\u59cb \u7d42\u4e86 \u9069\u7528 [&hellip;]<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":17495,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-17493","page","type-page","status-publish","has-post-thumbnail","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/pages\/17493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=17493"}],"version-history":[{"count":2,"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/pages\/17493\/revisions"}],"predecessor-version":[{"id":17507,"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/pages\/17493\/revisions\/17507"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=\/wp\/v2\/media\/17495"}],"wp:attachment":[{"href":"https:\/\/f1-lap-time.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=17493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}