2015-12-17 12 views
5

Grałem z elementem canvas i odkryłem, że gdy próbuję narysować jednolite jednolite komórki NxN obok siebie, w niektórych konfiguracjach szerokości/wysokości, występują rozmyte białe linie między im.Dziwne HTML Antialiasing na płótnie

Na przykład to płótno ma wyglądać na czarny, ale zawiera pewnego rodzaju siatkę , co przypuszczam, że jest wynikiem wadliwego wygładzania krawędzi w przeglądarce.

The canvas demonstrating the issue.

Wystarczy powiedzieć, że ten błąd pojawia się tylko w niektórychkonfiguracje, ale chciałbym, aby pozbyć się go na dobre. Czy istnieje sposób na obejście tego? Czy kiedykolwiek miałeś problemy z wygładzaniem krawędzi w płótnie?

Zrobiłem this fiddle, który demonstruje problem i pozwala grać z wymiarami płótna i liczbą komórek. Zawiera również kod, którego używam do rysowania komórek, abyś mógł go sprawdzić i powiedzieć, czy robię coś złego.

var ctx = canvas.getContext('2d'); 
ctx.clearRect(0, 0, canvasWidth, canvasHeight); 
for (var i = 0; i < numberOfCells; ++i) { 
    for (var j = 0; j < numberOfCells; ++j) { 
    ctx.fillStyle = '#000'; 
    ctx.fillRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight); 
    } 
} 

Dzięki z góry,

Petr.

+0

Witam Petr, wydaje się, że zapomniałeś o podanie linku skrzypce, mógłbyś aktualizować – Canvas

+0

Wystarczy zauważył. Przepraszam, proszę bardzo! :) –

+0

Najpopularniejszą sztuczką jest przekształcenie całego płótna o jeden piksel na początku, aby uniknąć tego, jak sądzę. –

Odpowiedz

1

Po przeczytaniu i wypróbowaniu kilku podejść, postanowiłem wymyślić własne. Stworzyłem kolejne (wirtualne) płótno o wymiarach całkowitych odpowiadających liczbie komórek w siatce.

Po narysowaniu wszystkich komórek, wywołuję context.drawImage() na płótnie głównym i przekazuję wirtualne płótno jako argument wraz z parametrami przesunięcia i skali, aby pasował do reszty rysunku. Zakładając, że przeglądarka skaluje obraz wirtualnej kanwy jako całość (a nie jako pojedyncze komórki), miałem nadzieję pozbyć się niechcianych linii separujących.

Pomimo moich wysiłków, linie nadal istnieją. Jakieś sugestie?

Oto skrzypce demonstrując moją technikę: https://jsfiddle.net/ngxjnywz/5/

+0

Odkryłem winnego. Okazuje się, że to podejście działa tak długo, jak długo nie przesuję płótna pomocniczego o 0,5 piksela (jak sugeruje inna odpowiedź). Po usunięciu 'context.translate (0.5, 0.5)', wszystko inne wpadło na swoje miejsce. –

4

jsFiddle: https://jsfiddle.net/ngxjnywz/2/

urywek javascript

var cellWidth = Math.ceil(canvasWidth/numberOfCells); 
var cellHeight = Math.ceil(canvasHeight/numberOfCells); 

zależności od szerokości, wysokości i twoi numberOfCells jesteś czasami dostaję ... powiedzmy 4.2, który jest 4, więc to będzie wyświetlany źle i pozwoli na pojawienie się pustej linii o wartości 1 piksela. Więc wszystko co musisz zrobić, to skorzystać z funkcji Math.ceil a to spowoduje, że cellWidth i cellHeight być zawsze wyższa liczba, a nie dostaniesz puste wiersze już

+0

Niestety zaokrąglanie działa tylko wtedy, gdy linie są równoległe do osi X lub Y, ani nie bierze pod uwagę żadnej transformacji, która może być stosowane. – Blindman67

+0

To jest naprawdę ładne i łatwe rozwiązanie. Może się to nieco komplikować, ponieważ komórki zaczną się nakładać, co może spowodować, że kolejność rysowania stanie się nagle istotna, ale ponieważ ta sama funkcja "cellWidth" zostanie użyta do zrekompensowania procedury rysowania, zostanie to uniemożliwione. –

+0

Właśnie próbowałem "ctx.fillRect (j * cellWidth + 151, i * cellHeight + 77, cellWidth, cellHeight);" i działa bez problemu, ale mogę potwierdzić, że jakakolwiek "transformacja" na siatce będzie odtwarzać linie, jednak jeśli coś przekształcisz po siatce, to dobrze, spójrz na mój link https://jsfiddle.net/ngxjnywz/ 4/ – Canvas

2

Najlepszym rozwiązaniem jest dodanie 0,5 piksela szeroki wokół obrysu wszystkie wypełnienia, używając tego samego stylu co wypełnienie i przesuwając wszystkie rysunki, aby renderować w środku pikseli zamiast w lewym górnym rogu.

Jeśli dodasz skalowanie lub tłumaczenie, będziesz musiał dostosować współrzędne, aby nadal udostępniać centra dla współrzędnych rysunku.

Na koniec można zmniejszyć liczbę artefaktów, ale w wielu sytuacjach nie można ich całkowicie usunąć.

Ta odpowiedź pokazuje, jak usunąć artefakty z nietransformowanego płótna. How to fill the gaps

+0

To wygląda na skomplikowaną procedurę. W mojej konkretnej konfiguracji musiałbym całkowicie przemyśleć matematykę mojego rysunku siatki. –

+0

@ PetrMánek To prawda, ale w innych sytuacjach jest to najprostsze rozwiązanie - po prostu dodaj .5 do wszystkich współrzędnych. –

+0

@ PetrMánek. Półpikselowy trik działa dobrze kosztem przeprojektowania. Innym obejściem jest stworzenie "klocków" na drugim płótnie i [złożenie projektu z tych klocków] (http://stackoverflow.com/questions/29355920/canvas-polygons-not-touching-properly). – markE