Автор статьи: Ли Фэнлу, инженер по визуализации TalkingData.
Монтажер: Аресн
inMap — это библиотека визуализации больших данных на основе холста, ориентированная на визуализацию точек, линий и плоскостей в направлении больших данных. В настоящее время поддерживает методы рассеяния, забора, тепловые, сетки, агрегации и другие методы, предназначенные для упрощения визуализации больших данных.
Адрес гитхаба:GitHub.com/говорящие данные…
Адрес документа:inmap.talkingdata.com/
При визуализации географической информации мы часто сталкиваемся с необходимостью пометить текст на карте.Ниже показан эффект популярной рамки диаграммы:
Когда отображаемого текстового пространства недостаточно, это приведет к тому, что текст будет перекрываться и отображаться в замешательстве, а взаимодействие с пользователем будет очень недружественным.
Как решить эту проблему? Мы используем алгоритм избегания текста, чтобы решить эту сложную проблему.
Ниже показан эффект избегания текста inMap:
Алгоритм разметки текста — одна из самых сложных задач в ГИС (относится к проблеме сложности NP, поэтому найти оптимальное решение, как правило, невозможно, можно найти только лучшее решение).
Алгоритм уклонения inMap использует алгоритм квартильной модели.Далее я научу вас писать алгоритм уклонения, а старый водитель заставит вас делать вид, что заставляет вас летать.
Подготовить данные
inMap получает данные широты и долготы, которые необходимо сопоставить с пиксельными координатами холста.При этом используется преобразование Меркатора.Алгоритм Меркатора очень сложен.В будущем у нас будет отдельная статья,чтобы рассказать о его принципе. После преобразования данные, которые вы получите, должны выглядеть так:
[
{
"name": "海门",//要显示的文字
"lng": 121.15,
"lat": 31.89,
"count": 7,
"pixel": { //像素坐标
"x": 968,
"y": 736
}
},
{
"name": "鄂尔多斯",
"lng": 109.781327,
"lat": 39.608266,
"count": 5,
"pixel": {
"x": 659,
"y": 478
}
},
...
]
Что ж, мы получаем преобразованные данные координат пикселей (x, y) и можем сделать следующее.
Найдите фактический размер каждого текстового прямоугольника
measureText()
это встроенный метод canvas, который возвращает ширину шрифта в пикселях:
let ctx = this.container.getContext('2d'); // canvas 上下文
let width= ctx.measureText(name).width;
Мы получаем ширину каждого текста через MeasureText, у холста нет метода прямого получения текста, как получить высоту текста?
В результате повторных тестов мы обнаружили, что когда шрифт canvas равен шрифту «13px Arial» (другие шрифты не гарантируются), высота текста примерно в 1,1 раза превышает размер шрифта.
Итак, код выглядит следующим образом:
let fontSize = parseInt(ctx.font);
let height = fontSize * 1.1;
После получения ширины и высоты текста мы можем создать систему координат текстового прямоугольника.
Создайте квартильную модель
Так называемая квартильная модель, каждая отмеченная точка имеет четыре места для текста, если левая часть не помещается, то пробуем поставить ее справа, если все равно не получается, ставим внизу, и так на, принцип настолько прост, как это, ха-ха.
Создайте правильное описание координат виртуального прямоугольника:
Описание координат виртуального прямоугольника справа также включает точки для предотвращения наложения текста и точек.
Есть некоторые ямки при расчете высоты виртуального прямоугольника.Размер точки не фиксирован, он динамически настраивается под пользователя.Диаметр точки может быть больше высоты текста.Задаем высоту виртуального прямоугольника, чтобы он всегда был самым большим. Выполните специальную обработку.
код показывает, как показано ниже:
_getLeftAnchor() {
let x = this.center.x - this.radius - this.textReact.width,
y = this.center.y - this.textReact.height / 2,
diam = this.radius * 2,
maxH = diam > this.textReact.height ? diam : this.textReact.height; //矩形的高度
return {
x,
y,
minX: x,
maxX: this.center.x + this.radius,
minY: this.center.y - maxH / 2,
maxY: this.center.y + maxH / 2
};
}
И так далее, опишите координаты виртуального прямоугольника внизу, слева и вверху.
Судебное столкновение
Чтобы судить о том, перекрываются ли два прямоугольника и пересекаются ли они, оцените пересечение в соответствии с minX, maxX, minY, maxY прямоугольника.Принцип относительно прост.Код выглядит следующим образом:
/**
* 判断分位是否相交
* @param {*} target
*/
isAnchorMeet(target) {
let react = this.getCurrentRect(),
targetReact = target.getCurrentRect();
if ((react.minX < targetReact.maxX) && (targetReact.minX < react.maxX) &&
(react.minY < targetReact.maxY) && (targetReact.minY < react.maxY)) {
return true;
}
return false;
}
Создайте объект сбора виртуального текста
let labels = pixels.map((val) => {
let radius = val.pixel.radius + this.style.normal.borderWidth; //圆点半径
return new Label(val.pixel.x, val.pixel.y, radius, fontSize, byteWidth, val.name);
});
Рекурсивный обход фиктивных текстовых коллекций, чтобы определить, будет ли другое пересечение, если вы переместите текущее место пересечения текста до тех пор, пока оно не будет пересекаться. Если нет подходящего места, выберите, чтобы скрыть текущий текст.
код показывает, как показано ниже:
do {
var meet = false; //本轮是否有相交
for (let i = 0; i < labels.length; i++) {
let temp = labels[i];
for (let j = 0; j < labels.length; j++) {
if (i != j && temp.show && temp.isAnchorMeet(labels[j])) {
temp.next();
meet = true;
break;
}
}
}
} while (meet);
Пиктограмма
labels.forEach(function (item) {
if (item.show) { //是否显示
let pixel = item.getCurrentRect();
ctx.beginPath();
ctx.fillText(item.text, pixel.x, pixel.y);
ctx.fill();
}
});
Алгоритм избегания текста был введен до сих пор, и соответствующий адрес файла inMapGitHub.com/говорящие данные…, и я продолжу делиться с вами галантерейными товарами в будущем.
Благосостояние
Поделитесь начальными курсами двух громких имен в отрасли:
-
Аресн, великий бог, открыл исходный код превосходной библиотеки компонентов пользовательского интерфейса iView и опубликовал книгу «Vue.js в действии». Всем рекомендую его курс.Серия практических руководств по Vue.js, скидка 20% по этой ссылке, в порядке живой очереди.
-
Эксперт Chaos WebGL, хорошо разбирается в веб-3D-разработке. главным образомКурсы серии "Плохая земля", очень подходит для начинающих.