import { isNonEmptyArr } from "@web3r/flowerkit/arr"; import { getMergedObj } from "@web3r/flowerkit/obj"; import { getId } from "@web3r/flowerkit/str"; import { clusterDefaults, pointDefaults } from "../../config"; import type { TAPI, TCluster, TClusterDefaults, TClusterElements, TConstructorInstance, TFactoryCallback, TMapContext, TPoint, TPointDefaults, ILayoutBalloonCluster, } from "../../config/types"; import { getLayoutConstructor, getUserField, isValidLayout, } from "../index"; import { getNormalizedPoints } from "../placemark"; /** * Получает кластеры с предустановленными параметрами * @param clusters{TCluster[]} * @param clusterOptions{TClusterDefaults} * @param pointOptions{TPointDefaults} * @returns TCluster[] */ const getNormalizedClusters = (clusters: TCluster[], clusterOptions: Partial = clusterDefaults, pointOptions: Partial = pointDefaults) => { return (Array.isArray(clusters) ? clusters : []) .filter((item) => { if (!!item && !!item.id && Array.isArray(item.points)) { return true; } else { console.error(`[Map] All clusters must have "id" (string) and "points" (array) props`, item); return false; } }) .map((item) => { const defaults = { ...clusterDefaults, ...clusterOptions, }; const withDefaults = getMergedObj(defaults, item, { isMergeArrays: false, }); return { ...withDefaults, points: getNormalizedPoints(withDefaults.points, pointOptions), }; }); }; /** * Получает экземпляр вызова templateLayoutFactory для указанного типа элемента * @param ymaps * @param props * @param getCN * @param callback * @param type * @returns {object} */ const ClustererInstanceLayout = async function({ ymaps, props, getCN, callback, type, }: { ymaps: TAPI; props: TCluster; getCN: TMapContext["getCN"]; callback?: TFactoryCallback; type: TClusterElements; }): Promise> { return await getClustererLayout({ clusterer: props, instance: ymaps, getCN, type, }) .then((html) => { return getLayoutConstructor(ymaps, html, callback, null); }); }; /** * Получает разметку для Clusterer * @param getCN{Function} * @param clusterer{Object} * @param instance{Object} * @param type{String} * @returns {String} */ const getClustererLayout = async ({ getCN, instance, clusterer, type, }: { getCN: TMapContext["getCN"]; instance: TAPI; clusterer: TCluster; type: TClusterElements; }): Promise => { const userFnArg = { point: clusterer.points[0]!, clusterer, instance, getCN, }; return new Promise((resolve, reject) => { void (async () => { switch (type) { case "balloon": { const { getLayout = null, extraClasses = {} } = clusterer.render?.balloon ?? {}; if (typeof getLayout === "function") { // user layout const layout = await getUserField(getLayout, userFnArg) || ""; resolve(layout); } else { // default layout resolve(`
    {% for point in properties.points %}
  • {% endfor %}
{{ properties.activePoint.balloonHeader|raw }}
{{ properties.activePoint.balloonContent|raw }}
`); } break; } case "icon": { const { getLayout = null, extraClasses = {} } = clusterer.render?.icon ?? {}; if (typeof getLayout === "function") { // user layout const layout = await getUserField(getLayout, userFnArg) || ""; resolve(layout); } else { // default layout resolve(`
$[properties.geoObjects.length]
`); } break; } default: { throw new Error(`Unsupported type "${type}"`); } } })().catch(reject); }) .then((layout) => { return isValidLayout(layout) ? layout : Promise.reject(clusterer); }) .catch((err) => { console.error("[Maps] Something went wrong while parsing layout: ", err); return ""; }); }; /** * Получает количество активных точек в кластерах * @returns {Number} */ const getActivePointsCount: ((clusters: TCluster[]) => number) = (clusters = []): number => { return clusters .map((item) => { return item.points.filter((point) => point.state?.isActive).length; }) .reduce((prev, current) => { return prev + current; }, 0); }; /** * Получает начальное состояние кластеризации * @param clusters * @param points * @param clusterOptions * @param pointOptions * @returns {Array} */ const getInitialClusters = (clusters?: TCluster[], points?: TPoint[], clusterOptions?: Partial, pointOptions?: Partial): TCluster[] => { return (!!clusters && isNonEmptyArr(clusters)) ? getNormalizedClusters(clusters, clusterOptions, pointOptions) : getNormalizedClusters([ { id: getId(8), points: (!!points && isNonEmptyArr(points)) ? points : [], }, ], clusterOptions, pointOptions); }; export { ClustererInstanceLayout, getActivePointsCount, getClustererLayout, getInitialClusters, getNormalizedClusters, };