Визуализация карт на устройствах с выбранным темным режимом
Я визуализирую фрагменты карты OSM на веб-странице с помощью HTML-холста drawImage. Однако там, где конечный пользователь выбрал темный режим, я хотел бы уменьшить яркость этих отображаемых карт, но все же позволить им иметь смысл для пользователя.
Пока у меня был умеренный успех, а именно:
- Сначала построение тайла карты с помощью drawImage
- установка globalCompositeOperation на "разницу"
- нанесение на тайл карты белого прямоугольника того же размера
- установка globalCompositeOperation обратно в "исходный код"
Но эта простая инверсия цвета, пожалуй, не лучшее решение. У кого-нибудь есть другие предложения.
3 ответа
Вы можете переключиться на другой тайловый сервер с другим стилем карты. Посмотрите, например, "CartoDB.DarkMatter" из демонстрации Leaflet Provider или MapBox Light & Dark.
Я нашел довольно хорошее решение этой проблемы:
- Сначала установите контекстный фильтр холста на "поворот оттенка (180 градусов)"
- Затем нанесите фрагмент карты на холст с помощью drawImage.
- Затем установите для контекстного фильтра холста значение "нет".
- Установите контекст холста globalCompositeOperation на "разницу"
- Затем нанесите на тайл карты белый прямоугольник того же размера.
- Наконец, установите контекст холста 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();
}