UNPKG

@publidata/utils-colors

Version:
155 lines (132 loc) 5.12 kB
import { getCssVariableValue, isCssVariable } from "./helpers"; /** * * @param {array} markers - List of map markers (eg : [{color: "--var(verre)", id: 1234, title etc...}]) * @returns {object} - clusterProperties - MapLibre object to pass in mapSource */ export const generateClusterProperties = markers => { const clusterProperties = {}; const usedColors = new Set(); const normalizedColor = color => isCssVariable(color) ? getCssVariableValue(color) : color; const conditionsProperties = {}; const createCondition = color => { conditionsProperties[color] = [ "any", ["in", color, ["get", "multiflowColors"]], [ "all", ["==", ["get", "color"], color], ["==", ["get", "multiflowData"], null] ] ]; }; markers.forEach(marker => { // Normalise la couleur principale du marker const color = normalizedColor(marker.color); const { multiflowColors } = marker; if (Array.isArray(multiflowColors)) { multiflowColors.forEach(multiflowColor => { const normalizedMultiflowColor = normalizedColor(multiflowColor); if (!usedColors.has(normalizedMultiflowColor)) { createCondition(normalizedMultiflowColor); usedColors.add(normalizedMultiflowColor); } }); } if (!usedColors.has(color)) { createCondition(color); usedColors.add(color); } }); Object.entries(conditionsProperties).forEach(([color, condition]) => { clusterProperties[color] = ["+", ["case", condition, 1, 0]]; }); return clusterProperties; }; export const getClusterRadius = count => [ [1000, 50], [100, 32], [10, 24], [0, 18] ].find(([threshold]) => count >= threshold)[1]; export const getClusterFontSize = count => [ [1000, 20], [100, 18], [10, 16], [0, 14] ].find(([threshold]) => count >= threshold)[1]; /** * @description - Generates a pie chart segment path using SVG path syntax. * @param {number} start - Start angle in radians * @param {number} end - End angle in radians * @param {number} outerRadius - Outer radius of the pie chart * @param {number} innerRadius - Inner radius of the pie chart * @param {string} color - Color of the segment in pie chart * @returns {string} - A path html string representing the pie chart segment */ export const getBorderTrunk = (start, end, outerRadius, innerRadius, color) => { const angleToCoord = (angle, radius) => ({ x: radius * Math.cos(2 * Math.PI * (angle - 0.25)), y: radius * Math.sin(2 * Math.PI * (angle - 0.25)) }); const adjustedEnd = end === 1 ? end - 0.00001 : end; const largeArcFlag = adjustedEnd - start > 0.5 ? 1 : 0; const startOuter = angleToCoord(start, outerRadius); const endOuter = angleToCoord(adjustedEnd, outerRadius); const startInner = angleToCoord(start, innerRadius); const endInner = angleToCoord(adjustedEnd, innerRadius); return ` <path d=" M ${outerRadius + startInner.x} ${outerRadius + startInner.y} L ${outerRadius + startOuter.x} ${outerRadius + startOuter.y} A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${ outerRadius + endOuter.x } ${outerRadius + endOuter.y} L ${outerRadius + endInner.x} ${outerRadius + endInner.y} A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${ outerRadius + startInner.x } ${outerRadius + startInner.y} Z " fill="${color}" /> `.trim(); }; export const generatePieChartIcons = properties => { // Retrieve colors from properties and calculate counts const { point_count: pointCount } = properties; const colors = Object.keys(properties).filter(key => key.startsWith("#")); const counts = colors.map(color => properties[color]); const totalCount = counts.reduce((sum, count) => sum + count, 0); // Define outer and inner radius based on total count const outerRadius = getClusterRadius(pointCount || totalCount); const innerRadius = Math.round(outerRadius * 0.65); // Define color and font size const fontSize = getClusterFontSize(pointCount || totalCount); const width = outerRadius * 2; // Generate arcs for the pie chart const arcs = colors.map((color, index) => { const start = counts.slice(0, index).reduce((sum, count) => sum + count, 0) / totalCount; const end = counts.slice(0, index + 1).reduce((sum, count) => sum + count, 0) / totalCount; return getBorderTrunk(start, end, outerRadius, innerRadius, color); }); // Generate SVG HTML let html = ` <div> <svg width="${width}" height="${width}" viewBox="0 0 ${width} ${width}" text-anchor="middle" style="font: ${fontSize}px Lato, sans-serif; font-weight:600; display: block">`; html += arcs.join(""); html += `<circle cx="${outerRadius}" cy="${outerRadius}" r="${innerRadius}" fill="white" /> <text dominant-baseline="central" transform="translate(${outerRadius}, ${outerRadius})"> ${String(properties.point_count)} </text> </svg> </div>`; const element = document.createElement("div"); element.innerHTML = html.trim(); return element.firstChild; };