import { aq, op } from "@uwdata/arquero"
bucket_base = "https://d33173dkfxwa5x.cloudfront.net/www/"
FA = FileAttachment  import {aq as aq, op as op} from "@uwdata/arquero"
bucket_base = "https://d33173dkfxwa5x.cloudfront.net/www/"
FA = ƒ(name)
import { aq, op } from "@uwdata/arquero"
bucket_base = "https://d33173dkfxwa5x.cloudfront.net/www/"
FA = FileAttachment  import {aq as aq, op as op} from "@uwdata/arquero"
mutable myLocation = null
mutable geolocateStatus = "default"
getLocation = {
  yield null
  yield navigator.geolocation.getCurrentPosition(
    pos => {
      mutable myLocation = {
        lat: pos.coords.latitude,
        lon: pos.coords.longitude
      }
      mutable geolocateStatus = "granted"
    },
    e => {
      console.log("Geolocation error", e),
      mutable geolocateStatus = "error"
    },
    {
      enableHighAccuracy: false
    })
}geolocateStatus == "default" ?
  md`Allow location to see local station` :
    geolocateStatus == "error" ?
      md`Problem getting location` :
      md``Allow location to see local station
myLocation != null ?
  md`Location is lat: ${myLocation.lat}, lon: ${myLocation.lon}` :
  md`Location permission not granted`Location permission not granted
// on the home page, get station id from:
//   * _geolocator.qmd's myLocation, plus
//   * _map.qmd's statsAll
stationId = {
  
  // fallback to sydney?
  if (myLocation == null) {
    return "023000"
  }
  // otherwise, find closest station on statsAll
  const closestStation = aq.from(statsAll)
    .params({
      currentLat: myLocation.lat,
      currentLon: myLocation.lon,
    })
    .derive({
      dist: (d, $) => Math.sqrt(
        ($.currentLat - d.isit_lat) ** 2 + ($.currentLon - d.isit_lon) ** 2)
    })
    .orderby("dist")
    .slice(0, 1)
    .array("id")
  return closestStation[0]
}Is it hot in Adelaide right now?
answers = ({
  "Hell no!":   {color: "white",   fill1: "#5287d1", fill2: "#2166ac" },
  "No!":        {color: "white",   fill1: "#a2cdeb", fill2: "#67a9cf" },
  "Nope":       {color: "#333333", fill1: "#f5f8fa", fill2: "#d1e5f0" },
  "Not really": {color: "#333333", fill1: "#f7f7f7", fill2: "#ebebeb" },
  "Yup":        {color: "#333333", fill1: "#fddcca", fill2: "#f7cfb7" },
  "Yeah!":      {color: "white",   fill1: "#de7b49", fill2: "#fc946a" },
  "Hell yeah!": {color: "white",   fill1: "#d1231d", fill2: "#b2182b" }
})
html`
<div class="answer-icon-and-label">
  <span class="answer-icon" style="background-color: ${answers[statsPlace.isit_answer].fill2};">
  </span>
  <span>${statsPlace.isit_answer}</span>
</div>`datefns = import("https://cdn.skypack.dev/date-fns@3.3.1?min")
tmaxWhen = new Date(Date.parse(statsPlace.isit_maximum_dt || null))
tminWhen = new Date(Date.parse(statsPlace.isit_minimum_dt || null))
tmaxWhenFriendly = isFinite(tmaxWhen) ?
  datefns.formatRelative(tmaxWhen, new Date()) : ""
tminWhenFriendly = isFinite(tminWhen) ?
  datefns.formatRelative(tminWhen, new Date()) : ""
percentRating = statsPlace.isit_average.toFixed(1) + "%"This is the distribution of temperatures typical for this time of year, which we’ve defined as a seven day window either side of today. Just like a bell curve, the plot is higher at more common temperatures and lower at rare temperatures.
We’ve compared every day this year at Adelaide to similar times of year in the past. Red days were hot compared to records; blue days were cold.
statsAllRaw = FA(bucket_base + "stats/stats_all.json").json()
// statsAllRaw is an object with keys by station id, but we
// need an array with an id field. let's move the ids in
statsAll = {
  const statsArray = []
  Object.keys(statsAllRaw).map(k => statsArray.push({...statsAllRaw[k], id: k}))
  const tidiedStats = aq.from(statsArray)
    .derive({
      lat: d => op.parse_float(d.isit_lat),
      lon: d => op.parse_float(d.isit_lon),
      isit_average: d => op.parse_float(d.isit_average),
      // current? (that's the actual avg temp)
      isit_maximum: d => op.parse_float(d.isit_maximum),
      isit_minimum: d => op.parse_float(d.isit_minimum),
      max_when: d => op.parse_date(d.isit_maximum_dt),
      min_when: d => op.parse_date(d.isit_minimum_dt),
      slug: d =>
        op.replace(
          op.replace(
            op.replace(
              op.lower(d.isit_label),
              /\s-\s/g, "-"),
            /\s/g, "-"),
          /[()]/g, "")
    })
    // mark as stale if latest obs are > 24 hours old
    .derive({
      max_stale:
        d => ((d.max_when - op.now()) / (1000 * 60)) / (24 * 60) > 1,
      min_stale:
        d => ((d.min_when - op.now()) / (1000 * 60)) / (24 * 60) > 1
    })
    .objects()
  return(tidiedStats)
}currentStats = statsAll.filter(d => (!d.max_stale) && (!d.min_stale))
staleStats = statsAll.filter(d => d.max_stale || d.min_stale)australia = FileAttachment("/assets/australia.geojson").json()
Plot = import("https://esm.run/@observablehq/plot")
answer_domain = [
  "Hell no!",
  "No!",
  "Nope",
  "Not really",
  "Yup",
  "Yeah!",
  "Hell yeah!"]
Plot.plot({
  projection: {
    type: "equirectangular",
    rotate: [-133, 28],
    domain: d3.geoCircle().center([133, -28]).radius(18)()
  },
  marks: [
    // Plot.graticule(),
    Plot.geo(australia, {
      fill: "#00000009",
      stroke: "#dddddd"
    }),
    // replace stale locations with crosses
    Plot.dot(staleStats, {
      x: "lon",
      y: "lat",
      stroke: "lightgrey",
      r: 6,
      symbol: "times"
    }),
    Plot.dot(currentStats, {
      x: "lon",
      y: "lat",
      fill: "isit_answer",
      stroke: d =>
        d.isit_answer == "Hell no!" || d.isit_answer == "Hell yeah!" ?
        "black" :
        "#00000099",
      strokeWidth: 0.75,
      r: 6,
    }),
    Plot.tip(currentStats, tipTemplate),
    // enlarge dot you're pointing to
    Plot.dot(currentStats, Plot.pointer({
      x: "lon",
      y: "lat",
      fill: "isit_answer",
      stroke: d =>
        d.isit_answer == "Hell no!" || d.isit_answer == "Hell yeah!" ?
        "black" :
        "#00000099",
      strokeWidth: 0.75,
      r: 12,
    })),
    // enlargen clickable areas with invisible voronoi polys
    Plot.voronoi(currentStats, {
      x: "lon",
      y: "lat",
      fill: "transparent",
      stroke: "transparent",
      href: d => "/places/" + d.slug,
    }),
  ],
  color: {
    type: "ordinal",
    domain: answer_domain,
    range: ["#2166acff",
            "#67a9cfff",
            "#d1e5f0ff",
            "#f7f7f7ff",
            "#fddbc7ff",
            "#ef8a62ff",
            "#b2182bff"]
  },
  height: 600
})// breaking out the pointer layer for readability
// (and in case we decide to customise it later)
tipTemplate = Plot.pointer({
  x: "lon",
  y: "lat",
  channels: {
    place: {
      label: "",
      value: d => d.isit_label,
    },
    label: {
      label: "",
      value: d => d.isit_comment
    },
    separator: {
      label: "",
      value: d => ""
    },
    isit_maximum: {
      label: "Max:",
      value: d => d.isit_maximum + "°C"
    },
    isit_minimum: {
      label: "Min:",
      value: d => d.isit_minimum + "°C"
    }
  },
  fontSize: 20,
  fontFamily: "Roboto Condensed",
  format: {
    x: null,
    y: null
  },
  lineWidth: 20,
  lineHeight: 1.25,
  pointerSize: 0,
  fillOpacity: 0.8,
  strokeOpacity: 0
})