my eye

author Angelo Gladding

name My World

published 2025-08-03T18:21:12.840302-07:00

type entry

updated 2025-08-13T16:49:21.966057-07:00

url /map, /2025/08/04/qz

visibility public

Content

<div id=map></div>

<style>
#map { height: 60em; width: 100%; }
</style>

<link href=https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css rel=stylesheet>
<script src=https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js></script>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoicmFndC1hZyIsImEiOiJjbWR3ZjZ5cjkxMmRhMmtwbHVlcDBrN240In0.nCEdq0_XYbjl8jq6YV4p5g';
const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/satellite-streets-v12',
  center: [-118.150, 34.113], // Centered on South Pasadena (ZIP 91030)
  zoom: 13
});
map.addControl(new mapboxgl.NavigationControl());
</script>

<!--input id="addrInput" type="text" value="1856 Hanscom Dr, South Pasadena, CA" style="width:60%;padding:4px">
<button id="addrBtn">Show Parcel</button-->

<script>
(function () {
  function ringsToGeoJSON(rings){
    return { type:'Feature', geometry:{ type:'Polygon', coordinates: rings.map(function(r){ return r.map(function(c){ return [c[0], c[1]] }) }) }, properties:{} }
  }
  function fitToFeature(feature){
    var coords = feature.geometry.coordinates[0]
    var xs = coords.map(function(c){ return c[0] }), ys = coords.map(function(c){ return c[1] })
    var b = [[Math.min.apply(null,xs), Math.min.apply(null,ys)], [Math.max.apply(null,xs), Math.max.apply(null,ys)]]
    map.fitBounds(b, { padding: 60, duration: 500 })
  }
  function toEnvMeters(lat, lon, m){
    var dLat = m / 111132
    var dLon = m / (111320 * Math.cos(lat * Math.PI / 180))
    return { xmin: lon - dLon, ymin: lat - dLat, xmax: lon + dLon, ymax: lat + dLat, spatialReference: { wkid: 4326 } }
  }
  async function queryParcelByPoint(lon, lat){
    // try precise contains with a point
    var url = new URL('https://arcgis.gis.lacounty.gov/arcgis/rest/services/DRP/GISNET_Public/MapServer/333/query')
    url.searchParams.set('geometry', JSON.stringify({ x: lon, y: lat, spatialReference:{wkid:4326} }))
    url.searchParams.set('geometryType','esriGeometryPoint')
    url.searchParams.set('spatialRel','esriSpatialRelContains')
    url.searchParams.set('inSR','4326'); url.searchParams.set('outSR','4326')
    url.searchParams.set('where','1=1')
    url.searchParams.set('outFields','AIN,SitusFullAddress')
    url.searchParams.set('returnGeometry','true'); url.searchParams.set('f','json')
    var r = await fetch(url.toString())
    if (r.ok) {
      var d = await r.json()
      if (d.features && d.features.length && d.features[0].geometry && d.features[0].geometry.rings) return d.features[0]
    }
    // fallback: tiny 3 m envelope intersects (handles edge/precision)
    var tiny = toEnvMeters(lat, lon, 3)
    var u2 = new URL('https://arcgis.gis.lacounty.gov/arcgis/rest/services/DRP/GISNET_Public/MapServer/333/query')
    u2.searchParams.set('geometry', JSON.stringify(tiny))
    u2.searchParams.set('geometryType','esriGeometryEnvelope')
    u2.searchParams.set('spatialRel','esriSpatialRelIntersects')
    u2.searchParams.set('inSR','4326'); u2.searchParams.set('outSR','4326')
    u2.searchParams.set('where','1=1')
    u2.searchParams.set('outFields','AIN,SitusFullAddress')
    u2.searchParams.set('returnGeometry','true'); u2.searchParams.set('f','json')
    var r2 = await fetch(u2.toString())
    if (!r2.ok) return null
    var d2 = await r2.json()
    return (d2.features && d2.features.length) ? d2.features[0] : null
  }
  async function drawParcelAt(lon, lat){
    var feat = await queryParcelByPoint(lon, lat)
    if (!feat) return console.warn('No parcel at click')
    var parcelFeature = ringsToGeoJSON(feat.geometry.rings)
    // clear old
    if (map.getLayer('parcel-line')) map.removeLayer('parcel-line')
    if (map.getLayer('parcel-fill')) map.removeLayer('parcel-fill')
    if (map.getSource('parcel')) map.removeSource('parcel')
    // add new
    map.addSource('parcel', { type:'geojson', data: parcelFeature })
    map.addLayer({ id:'parcel-fill', type:'fill', source:'parcel', paint:{ 'fill-color':'#ffae00', 'fill-opacity':0.25 } })
    map.addLayer({ id:'parcel-line', type:'line', source:'parcel', paint:{ 'line-color':'#ff7300', 'line-width':2 } })
    fitToFeature(parcelFeature)
  }
  function ensureMapReady(fn){
    if (map && map.isStyleLoaded && map.isStyleLoaded()) fn()
    else map.once('load', fn)
  }
  ensureMapReady(function(){
    map.getCanvas().style.cursor = 'crosshair'
    map.on('click', function(e){
      drawParcelAt(e.lngLat.lng, e.lngLat.lat)
    })
  })
})()
</script>