PageSourceSearch

https://draw.city/assets/services/map_tile_feature_adapter-0a920384.js

js draw.city collected 2026-09-28 10:23:09 UTC 4,549 bytes, 120 lines download raw bytes

1import {
2  calculateIndicatorValue,
3  extractVariables,
4  getAggregationNorm,
5  parseIndicator
6} from "services/indicator_helpers"
7import { classifyValue } from "services/bin_classifier"
8
9function sourceNumber(value) {
10  if (value === null || value === undefined || value === "") return null
11  const number = Number(value)
12  return Number.isFinite(number) && number >= 0 ? number : null
13}
14
15function rounded(value) {
16  return Number.isFinite(value) ? Math.round(value * 1_000_000) / 1_000_000 : null
17}
18
19function propertyKey(variable) {
20  const clean = variable.replace(/^\(|\)$/g, '')
21  if (clean === "POPULATION") return "P20"
22  if (["LAND_AREA", "ALAND20_SQMI", "ALAND20_ACRES"].includes(clean)) return "ALAND20"
23  return clean
24}
25
26export function mapTileIndicatorMeta(mapConfig, renderMeta) {
27  const parsed = parseIndicator(mapConfig?.category_indicator, mapConfig?.scope || {})
28  return {
29    global_breaks: renderMeta?.global_breaks || { category: [], partition: [] },
30    p99_height: renderMeta?.p99_height || 1,
31    value_normalize_var: parsed?.normalize || null
32  }
33}
34
35// Builds the common in-memory state for maps whose values come from MVT
36// properties. Standard maps and embedded map layers must use the same saved
37// breaks, feature adapter, and legend inputs.
38export function createMapTileViewState(mapConfig, renderMeta, cache = {}) {
39  const indicatorMeta = mapTileIndicatorMeta(mapConfig, renderMeta)
40  return {
41    geoidToFeature: cache,
42    tilePropertyAdapter: createMapTileFeatureAdapter(mapConfig, renderMeta, cache),
43    precomputed: { views: { indicator: indicatorMeta } },
44    globalBreaks: indicatorMeta.global_breaks,
45    precomputedP99Height: indicatorMeta.p99_height,
46    categoryBreaks: indicatorMeta.global_breaks.category || [],
47    partitionBreaks: [],
48    categoryLegendInfo: (mapConfig?.categories || []).map(() => ({ min: null, max: null })),
49    partitionLegendInfo: []
50  }
51}
52
53// Adapts Census properties embedded in an MVT feature to the standard map
54// feature shape. The adapter uses the saved tract scale for every geography.
55export function createMapTileFeatureAdapter(mapConfig, renderMeta, cache = {}) {
56  const config = mapConfig || {}
57  const parsed = parseIndicator(config.category_indicator, config.scope || {})
58  const variables = new Set()
59  extractVariables(parsed, variables)
60  const breaks = renderMeta?.global_breaks?.category || []
61
62  return rawProperties => {
63    const geoid = rawProperties?.GEOID
64    if (!geoid) return null
65    if (cache[geoid]) return cache[geoid]
66
67    const properties = {
68      ...rawProperties,
69      GEOID: String(geoid),
70      P20: sourceNumber(rawProperties.P20),
71      ALAND20: sourceNumber(rawProperties.ALAND20)
72    }
73    for (const variable of variables) {
74      const key = propertyKey(variable)
75      if (!Object.prototype.hasOwnProperty.call(properties, key)) continue
76      const numeric = Number(properties[key])
77      if (Number.isFinite(numeric) && numeric < 0) properties[key] = null
78    }
79    const feature = { properties }
80    let value = calculateIndicatorValue(feature, variables, parsed)
81    if (!Number.isFinite(value)) value = null
82    if (config.category_filter_negative && value < 0) return null
83    if (config.category_filter_zero && value === 0) value = null
84    if (config.category_absolute_value && value !== null) value = Math.abs(value)
85
86    let numerator = null
87    let denominator = null
88    if (parsed?.normalize) {
89      const withoutNorm = { ...parsed, normalize: null, rateDivisor: null }
90      numerator = calculateIndicatorValue(feature, variables, withoutNorm)
91      if (!Number.isFinite(numerator)) numerator = null
92      if (config.category_filter_negative && numerator < 0) numerator = null
93      if (config.category_filter_zero && numerator === 0) numerator = null
94      if (config.category_absolute_value && numerator !== null) numerator = Math.abs(numerator)
95      denominator = getAggregationNorm(feature, parsed.normalize)
96    }
97
98    value = rounded(value)
99    numerator = rounded(numerator)
100    denominator = rounded(denominator)
101    const categoryIndex = classifyValue(value, breaks)
102    const adapted = {
103      ...properties,
104      views: {
105        indicator: {
106          value,
107          value_numerator: numerator,
108          value_denominator: denominator,
109          height_value: value,
110          hasUnavailableData: value === null,
111          category_index: categoryIndex,
112          partition_index: 0,
113          color_index: categoryIndex
114        }
115      }
116    }
117    cache[geoid] = adapted
118    return adapted
119  }
120}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.