// class HexgridHeatmap { // constructor(map, options = {}) { // this.map = map; // this.options = { // id: 'hexgrid-heatmap', // radius: 1000, // meters // colorRange: [ // [0, '#f7fbff'], // [0.2, '#6baed6'], // [0.4, '#4292c6'], // [0.6, '#2171b5'], // [0.8, '#084594'], // [1, '#08306b'] // ], // opacity: 0.7, // ...options // }; // // this.hexLayerId = `${this.options.id}-hex`; // this.hexLayerId = `${this.options.id}`; // this.hexData = null; // if (this.map.loaded()) { // this._initialize(); // } else { // this.map.on('load', () => this._initialize()); // } // } // async _initialize() { // await this._createHexgrid(); // this._addSourcesAndLayers(); // this._setupEventListeners(); // } // async _createHexgrid() { // if (!this.options.data) return; // // 1. Get bounding box of point data // const bbox = turf.bbox(this.options.data); // // 2. Create hexgrid covering the bounding box // const cellSide = this.options.radius; // const hexgrid = turf.hexGrid(bbox, cellSide, { units: 'meters' }); // // 3. Count points in each hexagon // this.hexData = this._countPointsInHexagons(this.options.data, hexgrid); // } // _countPointsInHexagons(points, hexgrid) { // // Collect counts for each hexagon // const counts = {}; // points.features.forEach(point => { // hexgrid.features.forEach((hex, i) => { // if (turf.booleanPointInPolygon(point, hex)) { // counts[i] = (counts[i] || 0) + 1; // } // }); // }); // // Add counts to hexgrid properties // hexgrid.features.forEach((hex, i) => { // hex.properties = { // ...hex.properties, // count: counts[i] || 0 // }; // }); // // Normalize values (0-1) for coloring // const maxCount = Math.max(...Object.values(counts), 1); // hexgrid.features.forEach(hex => { // hex.properties.normalizedValue = hex.properties.count / maxCount; // }); // return hexgrid; // } // _addSourcesAndLayers() { // // Add hexgrid source // this.map.addSource(this.hexLayerId, { // type: 'geojson', // data: this.hexData // }); // // Add hexagon layer // this.map.addLayer({ // id: this.hexLayerId, // type: 'fill', // source: this.hexLayerId, // paint: { // 'fill-color': // 'red', // // [ // // 'interpolate', // // ['linear'], // // ['get', 'normalizedValue'], // // ...this.options.colorRange.flat() // // ], // 'fill-opacity': this.options.opacity, // 'fill-outline-color': '#fff' // } // }); // } // _setupEventListeners() { // this.map.on('click', this.hexLayerId, (e) => { // const features = this.map.queryRenderedFeatures(e.point, { // layers: [this.hexLayerId] // }); // if (features.length > 0) { // this._showPopup(features[0], e.lngLat); // } // }); // this.map.on('mousemove', this.hexLayerId, (e) => { // this.map.getCanvas().style.cursor = 'pointer'; // }); // this.map.on('mouseleave', this.hexLayerId, () => { // this.map.getCanvas().style.cursor = ''; // }); // } // _showPopup(feature, lngLat) { // console.log('Hexagon clicked:', feature); // new mapboxgl.Popup() // .setLngLat(lngLat) // .setHTML(` // Hexagon Data //
Points: ${feature.properties.count}
//
Value: ${feature.properties.normalizedValue.toFixed(2)}
// `) // .addTo(this.map); // } // // Public API // updateData(newData) { // this.options.data = newData; // return this._createHexgrid().then(() => { // this.map.getSource(this.hexLayerId).setData(this.hexData); // }); // } // remove() { // if (this.map.getLayer(this.hexLayerId)) { // this.map.removeLayer(this.hexLayerId); // } // if (this.map.getSource(this.hexLayerId)) { // this.map.removeSource(this.hexLayerId); // } // } // }