<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Black-Oystercatcher on Wildlife.blog</title><link>https://wildlife.blog/tags/black-oystercatcher/</link><description>Recent content in Black-Oystercatcher on Wildlife.blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 24 Aug 2026 01:43:10 +0000</lastBuildDate><atom:link href="https://wildlife.blog/tags/black-oystercatcher/index.xml" rel="self" type="application/rss+xml"/><item><title>Black Oystercatcher at China Beach, San Francisco</title><link>https://wildlife.blog/posts/black-oystercatcher-at-china-beach-san-francisco/</link><pubDate>Mon, 24 Aug 2026 01:43:10 +0000</pubDate><guid>https://wildlife.blog/posts/black-oystercatcher-at-china-beach-san-francisco/</guid><description>&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Black Oystercatcher&lt;/strong&gt; &lt;em&gt;(Haematopus bachmani)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A big, all-black shorebird of rocky Pacific coastlines, with a blazing red-orange bill it uses to pry mussels and limpets off the rocks.&lt;/p&gt;
&lt;p&gt;Year-round along the SF coast — look for them on rocky points and breakwaters rather than sandy beaches.&lt;/p&gt;
&lt;figure class="range-map-figure"&gt;
&lt;div class="range-map"
data-geojson="/posts/black-oystercatcher-at-china-beach-san-francisco/range.geojson"
data-taxon="4838"
aria-label="Map of the modeled range of this species"&gt;&lt;/div&gt;
&lt;figcaption&gt;Modeled range · &lt;a href="https://www.inaturalist.org/taxa/4838" target="_blank" rel="noopener"&gt;iNaturalist&lt;/a&gt; · CC BY 4.0&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;script src="https://wildlife.blog/js/leaflet.db49d009c841f5ca34a888c96511ae936fd9f5533e90d8b2c4d57596f4e5641a.js"&gt;&lt;/script&gt;
&lt;script&gt;
(function () {
var CORE_PCT = 0.05;
var GAP_MIN = 20;
var KEEP_FRAC = 0.75;
function quantile(sortedAsc, q) {
if (!sortedAsc.length) return undefined;
var pos = (sortedAsc.length - 1) * q;
var lo = Math.floor(pos), hi = Math.ceil(pos);
if (lo === hi) return sortedAsc[lo];
return sortedAsc[lo] + (sortedAsc[hi] - sortedAsc[lo]) * (pos - lo);
}
function rangeBounds(geo, layer) {
var pts = [];
(function walk(c) {
if (!c) return;
if (typeof c[0] === 'number' &amp;&amp; typeof c[1] === 'number') {
pts.push([c[0], c[1]]); return;
}
for (var i = 0; i &lt; c.length; i++) walk(c[i]);
})((function collect(g) {
if (g.type === 'FeatureCollection') return g.features.map(function (f) { return f.geometry &amp;&amp; f.geometry.coordinates; });
if (g.type === 'Feature') return g.geometry &amp;&amp; g.geometry.coordinates;
return g.coordinates;
})(geo));
if (!pts.length) return layer.getBounds();
pts.sort(function (a, b) { return a[0] - b[0]; });
var n = pts.length;
var wrapGap = (pts[0][0] + 360) - pts[n - 1][0];
var maxGap = wrapGap, splitIdx = 0;
for (var i = 1; i &lt; n; i++) {
var g = pts[i][0] - pts[i - 1][0];
if (g &gt; maxGap) { maxGap = g; splitIdx = i; }
}
if (maxGap &lt; GAP_MIN) return layer.getBounds();
var ordered = [];
for (var k = 0; k &lt; n; k++) {
var p = pts[(splitIdx + k) % n];
var lon = p[0];
if (k &gt; 0 &amp;&amp; lon &lt; ordered[k - 1][0]) lon += 360;
ordered.push([lon, p[1]]);
}
var clusters = [], cur = [ordered[0]];
for (var j = 1; j &lt; ordered.length; j++) {
if (ordered[j][0] - ordered[j - 1][0] &gt;= GAP_MIN) {
clusters.push(cur); cur = [];
}
cur.push(ordered[j]);
}
clusters.push(cur);
clusters.sort(function (a, b) { return b.length - a.length; });
var kept = [], have = 0, need = Math.ceil(n * KEEP_FRAC);
for (var c = 0; c &lt; clusters.length; c++) {
kept = kept.concat(clusters[c]); have += clusters[c].length;
if (have &gt;= need) break;
}
var lonSorted = kept.map(function (p) { return p[0]; }).sort(function (a, b) { return a - b; });
var latSorted = kept.map(function (p) { return p[1]; }).sort(function (a, b) { return a - b; });
var w = quantile(lonSorted, CORE_PCT);
var e = quantile(lonSorted, 1 - CORE_PCT);
var s = quantile(latSorted, CORE_PCT);
var nn = quantile(latSorted, 1 - CORE_PCT);
if (!(e &gt; w)) { w = lonSorted[0]; e = lonSorted[lonSorted.length - 1]; }
if (!(nn &gt; s)) { s = latSorted[0]; nn = latSorted[latSorted.length - 1]; }
return L.latLngBounds([[s, w], [nn, e]]);
}
function shiftGeo(geo, dLon) {
function shiftCoords(c) {
if (typeof c[0] === 'number' &amp;&amp; typeof c[1] === 'number') {
return [c[0] + dLon, c[1]];
}
return c.map(shiftCoords);
}
function shiftGeom(g) {
if (!g) return g;
return { type: g.type, coordinates: shiftCoords(g.coordinates) };
}
if (geo.type === 'FeatureCollection') {
return { type: 'FeatureCollection', features: geo.features.map(function (f) {
return { type: 'Feature', properties: f.properties, geometry: shiftGeom(f.geometry) };
}) };
}
if (geo.type === 'Feature') {
return { type: 'Feature', properties: geo.properties, geometry: shiftGeom(geo.geometry) };
}
return shiftGeom(geo);
}
function initRangeMaps() {
if (typeof L === 'undefined') return;
document.querySelectorAll('.range-map').forEach(function (el) {
if (el._rangeMap) return;
var map = L.map(el, { scrollWheelZoom: false, worldCopyJump: true });
el._rangeMap = map;
var taxon = el.getAttribute('data-taxon');
var credit = taxon
? '&lt;a href="https://www.inaturalist.org/taxa/' + taxon + '"&gt;iNaturalist&lt;/a&gt;'
: 'iNaturalist';
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 12,
attribution: '&amp;copy; &lt;a href="https://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt; · Range: ' + credit + ' (CC BY 4.0)'
}).addTo(map);
map.setView([0, 0], 1);
fetch(el.getAttribute('data-geojson'))
.then(function (r) { return r.json(); })
.then(function (geo) {
var style = { color: '#2e7d32', weight: 1, fillColor: '#2e7d32', fillOpacity: 0.35 };
var layer = L.geoJSON(geo, { style: style }).addTo(map);
[-360, 360].forEach(function (dLon) {
L.geoJSON(shiftGeo(geo, dLon), { style: style, interactive: false }).addTo(map);
});
try { map.fitBounds(rangeBounds(geo, layer), { padding: [12, 12], maxZoom: 8 }); } catch (e) {}
})
.catch(function () { });
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initRangeMaps);
} else {
initRangeMaps();
}
})();
&lt;/script&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Black_oystercatcher"&gt;Wikipedia&lt;/a&gt; | &lt;a href="https://www.inaturalist.org/taxa/4838"&gt;iNaturalist&lt;/a&gt; | &lt;a href="https://www.inaturalist.org/taxa/4838/map"&gt;Range map&lt;/a&gt; | &lt;a href="https://ebird.org/species/bloys2"&gt;eBird&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>