დასაწყისისთვის, უაღრესად მნიშვნელოვანი იყო პირველი აპრილის პროექტის მოთხოვნების დადგენა, რადგან ის უნდა გაშვებულიყო „გადატვირთვის“ გარეშე, რათა Reddit-ის ყველა მომხმარებელს დაუყოვნებლივ შეეძლო მასზე წვდომა. თავიდანვე იდეალურად რომ არ ემუშავა, ძნელად ბევრი ადამიანის ყურადღებას მიიპყრობდა.
"დაფა" უნდა იყოს 1000x1000 ფილების ზომის, რომ ძალიან დიდი გამოიყურებოდეს.
ყველა კლიენტი უნდა იყოს სინქრონიზებული და აჩვენოს დაფის იგივე მდგომარეობა. ყოველივე ამის შემდეგ, თუ სხვადასხვა მომხმარებლებს აქვთ სხვადასხვა ვერსიები, მათ გაუჭირდებათ ურთიერთობა.
თქვენ უნდა მხარი დაუჭიროთ მინიმუმ 100000 ერთდროულ მომხმარებელს.
მომხმარებლებს შეუძლიათ ყოველ ხუთ წუთში ერთი კრამიტის განთავსება. აქედან გამომდინარე, აუცილებელია შენარჩუნდეს განახლების საშუალო სიჩქარე 100,000 ფილა ხუთ წუთში (333 განახლება წამში).
პროექტი უარყოფითად არ უნდა იმოქმედოს საიტის სხვა ნაწილებისა და ფუნქციების მუშაობაზე (თუნდაც r/Place-ზე მაღალი ტრეფიკია).
- მოქნილი კონფიგურაცია უნდა იყოს უზრუნველყოფილი მოულოდნელი შეფერხებების ან წარუმატებლობის შემთხვევაში. ანუ, თქვენ უნდა შეგეძლოთ დაფის ზომის და დაშვებული ნახაზის სიხშირის რეგულირება, თუ მონაცემთა რაოდენობა ძალიან დიდია ან განახლების სიხშირე ძალიან მაღალია.
Backend
განხორციელების გადაწყვეტილებები
ბექენდის შექმნის მთავარი სირთულე იყო დაფის სტატუსის ჩვენების სინქრონიზაცია ყველა კლიენტისთვის. გადაწყდა, რომ კლიენტებმა მოესმინათ კრამიტის განთავსების მოვლენები რეალურ დროში და დაუყოვნებლივ მოეკითხათ მთელი დაფის მდგომარეობა. ოდნავ მოძველებული სრული მდგომარეობის არსებობა მისაღებია, თუ თქვენ გამოიწერეთ განახლებები სრული მდგომარეობის გენერირებამდე. როდესაც კლიენტი იღებს სრულ მდგომარეობას, ის აჩვენებს ყველა ფილას, რომელიც მიიღო ლოდინის დროს; ყველა შემდგომი ფილა უნდა გამოჩნდეს დაფაზე მიღებისთანავე.
იმისათვის, რომ ამ სქემმა იმუშაოს, მოთხოვნა დაფის სრული მდგომარეობის შესახებ უნდა დასრულდეს რაც შეიძლება სწრაფად. თავიდან გვინდოდა მთელი დაფა ერთ რიგში შეგვენახა კასანდრაში და ყოველი მოთხოვნა უბრალოდ წაეკითხა ეს მწკრივი. ამ სტრიქონში თითოეული სვეტის ფორმატი იყო:
(x, y): („დროის შტამპი“: ეპოქები, „ავტორი“: მომხმარებლის_სახელი, „ფერი“: ფერი)
მაგრამ რადგან დაფა შეიცავს მილიონ ფილას, დაგვჭირდა მილიონი სვეტის წაკითხვა. ჩვენს წარმოების კლასტერზე ამას 30 წამამდე დასჭირდა, რაც მიუღებელი იყო და შეიძლება გამოიწვიოს კასანდრაზე გადაჭარბებული დატვირთვა.
შემდეგ გადავწყვიტეთ მთელი დაფა შეგვენახა რედისში. ჩვენ ავიღეთ მილიონი ოთხბიტიანი რიცხვის ბიტის ველი, რომელთაგან თითოეულს შეეძლო ოთხბიტიანი ფერის დაშიფვრა, ხოლო x და y კოორდინატები განისაზღვრა ოფსეტით (ოფსეტი = x + 1000y) ბიტის ველში. დაფის სრული მდგომარეობის მისაღებად, მთელი ბიტის ველი უნდა წაიკითხოთ.
შესაძლებელი იყო ფილების განახლება მნიშვნელობების განახლებით კონკრეტული ოფსეტებით (არ არის საჭირო მთელი წაკითხვის/განახლების/ჩაწერის პროცედურის დაბლოკვა ან განხორციელება). მაგრამ ყველა დეტალი მაინც უნდა იყოს შენახული კასანდრაში, რათა მომხმარებლებმა გაარკვიონ, ვინ და როდის მოათავსა თითოეული ფილა. ჩვენ ასევე ვგეგმავდით კასანდრას გამოყენებას დაფის აღსადგენად, როდესაც რედისი ჩამოვარდა. მისგან მთელი დაფის წაკითხვას 100 ms-ზე ნაკლები დასჭირდა, რაც საკმაოდ სწრაფი იყო.
აი, როგორ ვინახავდით ფერებს Redis-ში 2x2 დაფის მაგალითის გამოყენებით:
ჩვენ ვნერვიულობდით, რომ შეიძლება შეგვექმნა წაკითხვის გამტარუნარიანობა Redis-ში. თუ ბევრი კლიენტი დაუკავშირდება ან განახლდება ერთდროულად, ისინი ყველა ერთდროულად აგზავნიან მოთხოვნებს დაფის სრული მდგომარეობის შესახებ. ვინაიდან დაფა წარმოადგენდა საერთო გლობალურ სახელმწიფოს, აშკარა გამოსავალი იყო ქეშირების გამოყენება. ჩვენ გადავწყვიტეთ ქეში ჩაგვეყენებინა CDN (სწრაფად) დონეზე, რადგან მისი დანერგვა უფრო ადვილი იყო, ხოლო ქეში მიღებულ იქნა კლიენტებთან ყველაზე ახლოს, რამაც შეამცირა პასუხის მიღების დრო.
მოთხოვნები სრული დაფის მდგომარეობაზე ქეშირებული იყო Fastly-ის მიერ წამის დროით. Თავიდან ასაცილებლად დიდი რიცხვიითხოვს, როდესაც ვადა ამოიწურა, ჩვენ გამოვიყენეთ stale-while-revalidate header. Fastly მხარს უჭერს დაახლოებით 33 POP-ს, რომლებიც დამოუკიდებლად ქეშირებენ ერთმანეთს, ამიტომ ველოდით, რომ მივიღებდით 33-მდე სრული დაფის სტატუსის მოთხოვნას წამში.
ყველა კლიენტისთვის განახლებების გამოსაქვეყნებლად, ჩვენ გამოვიყენეთ ჩვენი ვებსოკეტის სერვისი. ჩვენ ადრე წარმატებით ვიყენებდით Reddit.Live-ს 100000-ზე მეტ ერთდროულად მომხმარებელთან ერთად Live პირადი შეტყობინების შეტყობინებებისა და სხვა ფუნქციებისთვის. მომსახურებაც იყო ქვაკუთხედიჩვენი წარსული პირველი აპრილის პროექტები - The Button and Robin. r/Place-ის შემთხვევაში, კლიენტებმა მხარი დაუჭირეს ვებსოკეტის კავშირებს, რათა მიეღოთ რეალურ დროში განახლებები ფილების განთავსებაზე.
API
სრული დაფის მდგომარეობის მიღება
![](https://i2.wp.com/habrastorage.org/files/c6b/c1b/5e7/c6bc1b5e76f443d5867d93cd0fb120c0.png)
თავდაპირველად, მოთხოვნები წავიდა Fastly-ში. თუ მას ჰქონდა დაფის მოქმედი ასლი, ის დაუყოვნებლივ დააბრუნებდა მას Reddit-ის აპლიკაციის სერვერებთან დაკავშირების გარეშე. თუ არა, ან ასლი ძალიან ძველი იყო, მაშინ Reddit აპი წაიკითხა სრული დაფა Redis-დან და დააბრუნა Fastly-ში, რათა შეძლოს მისი ქეშირება და კლიენტისთვის დაბრუნება.
![](https://i2.wp.com/habrastorage.org/files/16e/ee3/8bc/16eee38bcb1c43d99700a9d1425e2dcd.png)
გაითვალისწინეთ, რომ მოთხოვნის სიჩქარე არასოდეს აღწევდა 33 წამში, რაც იმას ნიშნავს, რომ ქეშირება Fastly-ით ძალიან იყო ეფექტური საშუალებები Reddit აპის დაცვა უმეტესი მოთხოვნებისგან.
![](https://i1.wp.com/habrastorage.org/files/245/f4c/700/245f4c7007914e29a61c9c8cef1f0fdb.png)
და როდესაც მოთხოვნამ მიაღწია განაცხადს, რედისმა ძალიან სწრაფად უპასუხა.
კრამიტის დახატვა
![](https://i0.wp.com/habrastorage.org/files/7ce/d3f/c1e/7ced3fc1e0e7426592a3d1afe77543d5.png)
კრამიტის დახატვის ეტაპები:
- მომხმარებლის მიერ კრამიტის ბოლო განთავსების დროის ანაბეჭდი იკითხება კასანდრადან. თუ ხუთ წუთზე ნაკლები იყო, მაშინ არაფერს ვაკეთებთ და შეცდომა უბრუნდება მომხმარებელს.
- კრამიტის დეტალები ეწერება რედისს და კასანდრას.
- მიმდინარე დრო ჩაწერილია კასანდრაში, როგორც ბოლო დროს, როდესაც ფილა მოათავსეს მომხმარებლის მიერ.
- ვებსოკეტის სერვისი უგზავნის შეტყობინებას ყველა დაკავშირებულ კლიენტს ახალი კრამიტის შესახებ.
მკაცრი თანმიმდევრულობის შესანარჩუნებლად, ყველა ჩაწერა და წაკითხვა კასანდრაში შესრულდა QUORUM თანმიმდევრულობის ფენის გამოყენებით.
სინამდვილეში, ჩვენ გვქონდა რბოლა აქ, სადაც მომხმარებლებს შეეძლოთ ერთდროულად რამდენიმე ფილების განთავსება. 1-3 ეტაპებზე არ იყო დაბლოკვა, ამიტომ ფილების დახატვის ერთდროული მცდელობა შეიძლება გაიაროს შემოწმება პირველ ეტაპზე და დახაზულიყო მეორეში. როგორც ჩანს, ზოგიერთმა მომხმარებელმა აღმოაჩინა ეს შეცდომა (ან გამოიყენეს ბოტები, რომლებიც იგნორირებას უკეთებდნენ მოთხოვნის სიხშირის ლიმიტს) - და შედეგად, დაახლოებით 15,000 ფილა განთავსდა მისი გამოყენებით (~0,09% საერთო).
მოთხოვნის განაკვეთები და პასუხების დრო, რომელიც იზომება Reddit აპლიკაციით:
![](https://i0.wp.com/habrastorage.org/files/360/16d/850/36016d850d0349d88b12e971c372a723.png)
ფილების განლაგების პიკი იყო თითქმის 200 წამში. ეს ჩვენს სავარაუდო ლიმიტს 333 ფილა/წმ-ზე დაბალია (საშუალოდ იმ ვარაუდით, რომ 100 000 მომხმარებელი ათავსებს ფილებს ყოველ ხუთ წუთში).
![](https://i0.wp.com/habrastorage.org/files/ecd/ca9/7a7/ecdca97a7ee64bf5ad6c982938365598.png)
დეტალების მიღება კონკრეტული ფილისთვის
![](https://i2.wp.com/habrastorage.org/files/12f/b92/563/12fb925631094e738354c4ad3b186320.png)
კონკრეტული ფილების მოთხოვნისას, მონაცემები პირდაპირ კასანდრადან იკითხებოდა.
მოთხოვნის განაკვეთები და პასუხების დრო, რომელიც იზომება Reddit აპლიკაციით:
![](https://i1.wp.com/habrastorage.org/files/49b/157/286/49b157286eed4041962eae41c0337de8.png)
ეს მოთხოვნა ძალიან პოპულარული აღმოჩნდა. კლიენტის რეგულარული მოთხოვნის გარდა, ადამიანებს აქვთ დაწერილი სკრიპტები, რომ მოიძიონ მთელი დაფა ერთი ფილა ერთდროულად. ვინაიდან ეს მოთხოვნა არ იყო ქეშირებული CDN-ში, ყველა მოთხოვნას ემსახურებოდა Reddit აპლიკაცია.
![](https://i0.wp.com/habrastorage.org/files/730/443/62b/73044362b2b44ab0805a5fad19639cdd.png)
ამ თხოვნებზე რეაგირების დრო საკმაოდ მოკლე იყო და პროექტის მთელი ცხოვრების მანძილზე რჩებოდა იმავე დონეზე.
ვებსოკეტები
ჩვენ არ გვაქვს ინდივიდუალური მეტრიკა, რომელიც აჩვენებს, თუ როგორ იმოქმედა r/Place-მა websocket სერვისზე. მაგრამ ჩვენ შეგვიძლია შევაფასოთ მნიშვნელობები პროექტის დაწყებამდე და მისი დასრულების შემდეგ მონაცემების შედარებით.
ვებსოკეტის სერვისთან კავშირების საერთო რაოდენობა:
![](https://i0.wp.com/habrastorage.org/files/7f0/a07/fdb/7f0a07fdbf164baba18d5f3749fad963.png)
საბაზისო დატვირთვა r/Place-ის გაშვებამდე იყო დაახლოებით 20000 კავშირი, პიკი იყო 100000 კავშირი. ასე რომ, პიკზე ჩვენ ალბათ გვყავდა დაახლოებით 80,000 კონკურენტი მომხმარებელი დაკავშირებული r/Place-თან.
Websocket სერვისის გამტარუნარიანობა:
![](https://i1.wp.com/habrastorage.org/files/b72/cfb/6d4/b72cfb6d4b054a538711d760008d1448.png)
r/Place-ზე დატვირთვის პიკზე, websocket სერვისმა გადაიტანა 4 გბიტ/წმ-ზე მეტი (150 Mbps თითო ინსტანციაზე, სულ 24 შემთხვევა).
Frontend: ვებ და მობილური კლიენტები
Place-ის ფრონტენტის შექმნის პროცესში ჩვენ მოგვიწია მრავალი რთული პრობლემის გადაჭრა, რომლებიც დაკავშირებულია კროს-პლატფორმის განვითარებასთან. ჩვენ გვინდოდა, რომ პროექტი ერთნაირად მუშაობდეს ყველა ძირითად პლატფორმაზე, მათ შორის დესკტოპ კომპიუტერებზე და მობილურ მოწყობილობებზე iOS და Android-ზე.
მომხმარებლის ინტერფეისს სამი მნიშვნელოვანი ფუნქცია უნდა შეესრულებინა:
- დაფის სტატუსის ჩვენება რეალურ დროში.
- ნება მიეცით მომხმარებლებს ურთიერთქმედონ დაფასთან.
- იმუშავეთ ყველა პლატფორმაზე, მათ შორის მობილურ აპლიკაციებზე.
ინტერფეისის მთავარი ობიექტი იყო ტილო და Canvas API იდეალური იყო მისთვის. ჩვენ გამოვიყენეთ ელემენტი
ტილოს დახატვა
ტილო რეალურ დროში უნდა ასახავდეს დაფის მდგომარეობას. საჭირო იყო მთელი დაფის დახატვა, როდესაც გვერდი ჩაიტვირთა და დასრულებულიყო ვებსოკეტების მეშვეობით შემოსული განახლებების ნახაზი. ტილოს ელემენტი, რომელიც იყენებს CanvasRenderingContext2D ინტერფეისს, შეიძლება განახლდეს სამი გზით:
- დახაზეთ არსებული სურათი ტილოში drawImage()-ის გამოყენებით.
- ფორმების დახატვა გამოყენებით სხვადასხვა მეთოდებიხატვის ფორმები. მაგალითად, fillRect() ავსებს მართკუთხედს გარკვეული ფერით.
- შექმენით ImageData ობიექტი და დახატეთ იგი ტილოზე putImageData()-ის გამოყენებით.
პირველი ვარიანტი არ შეგვეფერა, რადგან არ გვქონდა დაფა მზა გამოსახულების სახით. ეს დარჩა 2 და 3 ვარიანტები. უმარტივესი გზა იყო ცალკეული ფილების განახლება fillRect()-ის გამოყენებით: როდესაც განახლება მოდის websocket-ის მეშვეობით, ჩვენ უბრალოდ ვხატავთ 1x1 ოთხკუთხედს (x, y) პოზიციაზე. ზოგადად, მეთოდი მუშაობდა, მაგრამ არ იყო ძალიან მოსახერხებელი დაფის საწყისი მდგომარეობის დასახატად. putImageData() მეთოდი ბევრად უკეთესი იყო: ჩვენ შეგვიძლია განვსაზღვროთ თითოეული პიქსელის ფერი ერთ ImageData ობიექტში და ერთდროულად დავხატოთ მთელი ტილო.
დაფის საწყისი მდგომარეობის დახატვა
putImageData()-ის გამოყენება მოითხოვს დაფის მდგომარეობის განსაზღვრას Uint8ClampedArray-ის სახით, სადაც თითოეული მნიშვნელობა არის რვა ბიტიანი ხელმოუწერელი რიცხვი 0-დან 255-მდე დიაპაზონში. თითოეული მნიშვნელობა წარმოადგენს ფერის არხს (წითელი, მწვანე, ლურჯი, ალფა) და თითოეული პიქსელს სჭირდება ოთხი ელემენტი მასივში. 2x2 ტილო მოითხოვს 16-ბაიტიან მასივს, რომელშიც პირველი ოთხი ბაიტი წარმოადგენს ტილოს ზედა მარცხენა პიქსელს, ხოლო ბოლო ოთხი წარმოადგენს ქვედა მარჯვენა პიქსელს.
აი, როგორ უკავშირდება ტილოს პიქსელები მათ Uint8ClampedArray წარმოდგენებს:
![](https://i0.wp.com/habrastorage.org/files/5d9/738/4f0/5d97384f09ef4b648f3b5a97338b5199.png)
ჩვენი პროექტის ტილოსთვის დაგვჭირდა ოთხი მილიონი ბაიტის მასივი - 4 მბ.
უკანა ნაწილში, დაფის მდგომარეობა ინახება ოთხბიტიან ველად. თითოეული ფერი წარმოდგენილია რიცხვით 0-დან 15-მდე, რაც საშუალებას გვაძლევს შეგვეკრა ორი პიქსელი თითოეულ ბაიტში. კლიენტის მოწყობილობაზე გამოსაყენებლად, თქვენ უნდა გააკეთოთ სამი რამ:
- გადაიტანეთ ორობითი მონაცემები ჩვენი API-დან კლიენტზე.
- ამოალაგეთ მონაცემები.
- გადაიყვანეთ ოთხბიტიანი ფერები 32-ბიტიანში.
ორობითი მონაცემების გადასატანად, ჩვენ გამოვიყენეთ Fetch API იმ ბრაუზერებში, რომლებიც მხარს უჭერენ მას. და მათ, ვინც მხარს არ უჭერს, ჩვენ გამოვიყენეთ XMLHttpRequest answerType-ზე დაყენებულია “arraybuffer”-ზე.
API-დან მიღებული ბინარული მონაცემები შეიცავს ორ პიქსელს თითოეულ ბაიტში. ყველაზე პატარა TypedArray კონსტრუქტორი, რომელიც ჩვენ გვქონდა, საშუალებას გაძლევთ იმუშაოთ ბინარულ მონაცემებთან ერთბაიტიანი ერთეულების სახით. მაგრამ მათი გამოყენება რთულია კლიენტის მოწყობილობებზე, ამიტომ ჩვენ გავხსენით მონაცემები, რათა გაადვილებულიყო მუშაობა. პროცესი მარტივია: ჩვენ გავიმეორეთ შეფუთული მონაცემების მეშვეობით, ამოვიღეთ მაღალი და დაბალი რიგის ბიტები და შემდეგ დავაკოპირეთ ისინი ცალკეულ ბაიტებად სხვა მასივში.
საბოლოოდ, ოთხი ბიტიანი ფერები უნდა გადაექცია 32 ბიტიანზე.
![](https://i0.wp.com/habrastorage.org/files/890/500/cb8/890500cb8f6b4dfd82ea1f708753935b.png)
ImageData სტრუქტურა, რომელიც გვჭირდებოდა putImageData()-ის გამოსაყენებლად ამას მოითხოვს საბოლოო შედეგიიყო Uint8ClampedArray-ის სახით ბაიტებით, რომლებიც კოდირებენ ფერთა არხებს RGBA თანმიმდევრობით. ეს ნიშნავს, რომ ჩვენ გვჭირდებოდა კიდევ ერთი დეკომპრესია, თითოეული ფერის დაყოფა არხის კომპონენტურ ბაიტებად და განთავსება მათ სწორ ინდექსში. არ არის ძალიან მოსახერხებელი პიქსელზე ოთხი ჩაწერის შესრულება. მაგრამ, საბედნიეროდ, სხვა ვარიანტიც იყო.
TypedArray ობიექტები არსებითად ArrayBuffer-ის მასივის წარმოდგენებია. აქ არის ერთი სიფრთხილე: რამდენიმე TypedArray ინსტანციას შეუძლია წაიკითხოს და ჩაწეროს იმავე ArrayBuffer მაგალითზე. ჩაწერის ნაცვლად ოთხი ღირებულებარვა-ბიტიან მასივში შეგვიძლია ჩავწეროთ ერთი მნიშვნელობა 32-ბიტიანში! წერისთვის Uint32Array-ის გამოყენებით, ჩვენ შევძელით ადვილად განვაახლოთ კრამიტის ფერები მხოლოდ ერთი მასივის ინდექსის განახლებით. თუმცა, ჩვენ უნდა შევინახოთ ჩვენი ფერის პალიტრა დიდი ბაიტის თანმიმდევრობით (ABGR), რათა ბაიტები ავტომატურად დასრულდეს სწორ ადგილებში Uint8ClampedArray-ის გამოყენებით წაკითხვისას.
![](https://i1.wp.com/habrastorage.org/files/f10/6bd/3d0/f106bd3d01b84a699a11d40a5904c6bd.png)
მიმდინარეობს ვებსოკეტით მიღებული განახლებების დამუშავება
drawRect() მეთოდი კარგი იყო ცალკეული პიქსელების განახლებების გამოსაყენებლად მათი მიღებისას, მაგრამ იყო ერთი სისუსტე: განახლებების დიდმა პარტიამ, რომელიც ერთბაშად მოვიდა, შეიძლება გამოიწვიოს ბრაუზერების შენელება. ჩვენ გვესმოდა, რომ საბჭოს სტატუსის განახლებები შეიძლება ძალიან ხშირად მოხდეს, ამიტომ პრობლემა როგორმე უნდა მოგვარებულიყო.
იმის ნაცვლად, რომ დაუყოვნებლივ გადაგვეხატა ტილო ყოველ ჯერზე, როდესაც განახლება მიიღება ვებსოკეტის საშუალებით, ჩვენ გადავწყვიტეთ, რომ ის ისე გაგვეკეთებინა, რომ ვებსოკეტის განახლებები, რომლებიც ერთსა და იმავე დროს მოდის, შესაძლებელი იყოს ჯგუფური და მასობრივად გადაცემა. ამის მისაღწევად ორი ცვლილება განხორციელდა:
- შეწყვიტე drawRect()-ის გამოყენება - აღმოვაჩინეთ მოსახერხებელი გზაგანაახლეთ მრავალი პიქსელი ერთდროულად putImageData() გამოყენებით.
- ტილოს რენდერის გადატანა requestAnimationFrame ციკლში.
რენდერის ანიმაციის მარყუჟში გადატანით, ჩვენ შევძელით დაუყოვნებლივ ჩაგვეწერა ვებსოკეტის განახლებები ArrayBuffer-ზე, ხოლო რეალური რენდერის გადადება. ყველა websocket განახლება, რომელიც მოდის ჩარჩოებს შორის (დაახლოებით 16 ms) დაჯგუფებული და ერთდროულად გადაიცემა. requestAnimationFrame-ის გამოყენების წყალობით, თუ რენდერირებას ძალიან დიდი დრო დასჭირდა (16 ms-ზე მეტი), ეს გავლენას მოახდენდა მხოლოდ ტილოს განახლების სიხშირეზე (ვიდრე მთელი ბრაუზერის მუშაობის შემცირებას).
ტილოსთან ურთიერთობა
მნიშვნელოვანია აღინიშნოს, რომ ტილო იყო საჭირო იმისათვის, რომ მომხმარებლებისთვის უფრო მოსახერხებელი ყოფილიყო სისტემასთან ურთიერთობა. ურთიერთქმედების მთავარი სცენარი არის ფილების განთავსება ტილოზე.
მაგრამ თითოეული პიქსელის ზუსტი რენდერის გაკეთება 1:1 მასშტაბით ძალიან რთული იქნება და შეცდომებს არ ავიცილებთ თავიდან. ასე რომ, ჩვენ გვჭირდებოდა (დიდი!) მასშტაბირება. გარდა ამისა, მომხმარებლებს სჭირდებოდათ ტილოზე ადვილად ნავიგაცია, რადგან ის ძალიან დიდი იყო ეკრანების უმეტესობისთვის (განსაკუთრებით მასშტაბირების გამოყენებისას).
მასშტაბირება
ვინაიდან მომხმარებლებს შეეძლოთ ფილების განთავსება ხუთ წუთში ერთხელ, განლაგების შეცდომები მათთვის განსაკუთრებით იმედგაცრუებული იქნებოდა. საჭირო იყო ისეთი ფაქტორის გადიდების განხორციელება, რომ ფილა საკმარისად დიდი ყოფილიყო და ადვილად მოთავსებულიყო Სწორი ადგილი. ეს განსაკუთრებით მნიშვნელოვანი იყო სენსორულ მოწყობილობებზე.
ჩვენ განვახორციელეთ 40x მასშტაბირება, ანუ თითოეულ ფილას ჰქონდა ზომა 40x40. ჩვენ შევფუთეთ ელემენტი