Javascript: строим диаграмму Вороного
Диаграмма Вороного - это вот такая симпатичная штука, каждая область которой образована множеством точек, более близких к "своей" точке, показанной чёрным цветом, чем к любой другой точке множества, подробнее есть в Вики.
диаграмма Вороного, пример
Ну а ниже показан небольшой онлайн-сервис, который умеет эти диаграммы строить. Точка добавляется кликом мыши, цвета областей случайны с избеганием слишком тёмных оттенков. Также избегается добавление точки, "слишком близкой" к одной из существующих. Для начала работы кликните в любом месте канвы... хотя бы 2-3 раза в разных местах :)
Конечно, в сети есть решения куда круче, но они и куда длиннее плюс лишены возможности самому расставить точки.
В исходнике можно попытаться поменять переменную metrics
и посмотреть, как будут выглядеть области при использовании вместо
обычной евклидовой метрики (значение metrics
равно 1, по умолчанию)
манхэттенского расстояния (при значении metrics
, равном 2)
или нормы Минковского (для metrics
, равного 3) .
Открыть приложение "Диаграмма Вороного" в текущем окне (вкладке)
VoronoiDiagram.html, файл приложения (3 Кб)
Полный исходник, предполагается кодировка Юникод (UTF-8) для файла .html
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Voronoi</title> </head> <body> <canvas id="diagramCanvas" width="600" height="600" style="background-color: #999999;"> Извините, канва недоступна в вашем бруазере </canvas> <script type="text/javascript"> var metrics = 1; //1-Евклидова, 2-Манхэттенская, 3-Минковского var numPoints = 0; var X=new Array(), Y=new Array(), C=new Array(); var canvas=document.getElementById("diagramCanvas"); var context=canvas.getContext("2d"); function randomNumber (max) { //Случайное число [0;max-1] return Math.floor(Math.random()*max) } function randomColor() { //Случайный цвет с интенсивностью компонент не ниже 33hex return "#"+ ("00"+(51+randomNumber(205)).toString(16)).slice(-2)+ ("00"+(51+randomNumber(205)).toString(16)).slice(-2)+ ("00"+(51+randomNumber(205)).toString(16)).slice(-2) } function Metric (x, y) { //Выбор метрики if (metrics==1) { return Math.sqrt(x*x + y*y); } if (metrics==2) { return Math.abs(x) + Math.abs(y); } if (metrics==3) { return(Math.pow(Math.pow(Math.abs(x),3) + Math.pow(Math.abs(y),3),0.33333)); } } function Diagram() { //Диаграмма var width=canvas.width, height=canvas.height; var dist1=dist0=j=0, width1=width-2, height1=height-2; context.fillStyle="white"; context.fillRect(0,0,width,height); for (var y=0; y<height1; y++) { for (var x=0; x<width1; x++) { dist0=Metric (height1,1); j = -1; for (var i=0; i<numPoints; i++) { dist1 = Metric (X[i]-x, Y[i]-y); if (dist1 < dist0) { dist0=dist1; j=i; } } context.fillStyle=C[j]; context.fillRect(x,y,1,1); } } context.fillStyle="black"; for (var i=0; i<numPoints; i++) { context.fillRect (X[i], Y[i], 3, 3); } } canvas.onclick = function (event) { //Обработчик кликов var x = event.clientX - canvas.offsetLeft, y = event.clientY - canvas.offsetTop; for (var i=0; i<X.length; i++) { if (Math.sqrt(Math.pow(X[i]-x,2)+Math.pow(Y[i]-y,2))<5) { context.fillStyle="red"; context.fillRect (X[i]-2, Y[i]-2, 7, 7); context.fillStyle="black"; context.fillRect (X[i], Y[i], 3, 3); return; //Подчеркнём, что "слишком близко" и не добавляем } } X[numPoints] = x; Y[numPoints] = y; C[numPoints] = randomColor(); numPoints++; Diagram(); } </script> <noscript>Извините, требуется включённый Javascript для работы приложения!</noscript> </body></html>
13.10.2017, 16:54 [5770 просмотров]