Визуализация карт на устройствах с выбранным темным режимом

Я визуализирую фрагменты карты OSM на веб-странице с помощью HTML-холста drawImage. Однако там, где конечный пользователь выбрал темный режим, я хотел бы уменьшить яркость этих отображаемых карт, но все же позволить им иметь смысл для пользователя.

Пока у меня был умеренный успех, а именно:

  1. Сначала построение тайла карты с помощью drawImage
  2. установка globalCompositeOperation на "разницу"
  3. нанесение на тайл карты белого прямоугольника того же размера
  4. установка globalCompositeOperation обратно в "исходный код"

Но эта простая инверсия цвета, пожалуй, не лучшее решение. У кого-нибудь есть другие предложения.

3 ответа

Вы можете переключиться на другой тайловый сервер с другим стилем карты. Посмотрите, например, "CartoDB.DarkMatter" из демонстрации Leaflet Provider или MapBox Light & Dark.

Я нашел довольно хорошее решение этой проблемы:

  1. Сначала установите контекстный фильтр холста на "поворот оттенка (180 градусов)"
  2. Затем нанесите фрагмент карты на холст с помощью drawImage.
  3. Затем установите для контекстного фильтра холста значение "нет".
  4. Установите контекст холста globalCompositeOperation на "разницу"
  5. Затем нанесите на тайл карты белый прямоугольник того же размера.
  6. Наконец, установите контекст холста globalCompositeOperation обратно в "исходный код"

Возможно, кому-то это все еще пригодится, это какой-то код, который я использую для этой цели в моем проекте tar1090. Отрицательный и положительный контраст, вероятно, четкие, а тусклый - это просто изменение яркости с перевернутым знаком.

функция переключения:

      function setDim(layer, state) {
    if (state) {
        layer.dimKey = layer.on('postrender', dim);
    } else {
        ol.Observable.unByKey(layer.dimKey);
    }
    OLMap.render();
}

пострендерная функция:

      function dim(evt) {
    const dim = mapDimPercentage * (1 + 0.25 * toggles['darkerColors'].state);
    const contrast = mapContrastPercentage * (1 + 0.1 * toggles['darkerColors'].state);
    if (dim > 0.0001) {
        evt.context.globalCompositeOperation = 'multiply';
        evt.context.fillStyle = 'rgba(0,0,0,'+dim+')';
        evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    } else if (dim < -0.0001) {
        evt.context.globalCompositeOperation = 'screen';
        console.log(evt.context.globalCompositeOperation);
        evt.context.fillStyle = 'rgba(255, 255, 255,'+(-dim)+')';
        evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    }
    if (contrast > 0.0001) {
        evt.context.globalCompositeOperation = 'overlay';
        evt.context.fillStyle = 'rgba(0,0,0,'+contrast+')';
        evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    } else if (contrast < -0.0001) {
        evt.context.globalCompositeOperation = 'overlay';
        evt.context.fillStyle = 'rgba(255, 255, 255,'+ (-contrast)+')';
        evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    }
    evt.context.globalCompositeOperation = 'source-over';
}

функция переключения при использовании LayerSwitcher:

      function setDimLayerSwitcher(state) {
    if (!state) {
        ol.control.LayerSwitcher.forEachRecursive(layers_group, function(lyr) {
                if (lyr.get('type') != 'base')
                return;
                ol.Observable.unByKey(lyr.dimKey);
                });
    } else {
        ol.control.LayerSwitcher.forEachRecursive(layers_group, function(lyr) {
                if (lyr.get('type') != 'base')
                return;
                lyr.dimKey = lyr.on('postrender', dim);
                });
    }
    OLMap.render();
}

Другие вопросы по тегам