Заливка зображенням
У розділі 1 ми дізналися, що Canvas може заливати фігури кольором та градієнтом. Також можна залити фігуру зображеннями, заданими як візерунок. Повторенням візерунка можна керувати подібно до фонових зображень у CSS.
Як і градієнти, візерунки малюється щодо поточної системи координат. Ось чому я зробив зсув на 200 пікселів праворуч перед малюванням другого прямокутника. Спробуйте перетягнути значення, щоб побачити, як це працює.
<code data-language="javascript">var pat1=ctx.createPattern(img,'repeat'); ctx.fillStyle=pat1; ctx.fillRect(<b id="imagefill_var1">0</b>,0,<b id="imagefill_var2">100</b>,100); var pat2=ctx.createPattern(img,'repeat-y'); ctx.fillStyle=pat2; ctx.translate(200,0); ctx.fillRect(<b id="imagefill_var3">0</b>,0,<b id="imagefill_var4">100</b>,100);
Зверніть увагу, що заливка зображенням працює, тільки якщо зображення вже завантажене, тому не забудьте робити малювання з функції зворотного виклику onload.
Прозорість
Canvas API дозволяє керувати прозорістю через властивість globalAlpha. У наступній демонстрації малюються два червоні квадрати, через які видно зміни globalAlpha перед кожною операцією малювання.
<code data-language="javascript">ctx.fillStyle='red'; //ділимо на 100 щоб одержати дріб між 0 і 1 ctx.globalAlpha=<b id="opacitydemo_var1">50</b>/100; ctx.fillRect(0,0,50,50); ctx.globalAlpha=30</b>/100; ctx.fillRect(25,25,50,50); ctx.globalAlpha=1.0;
Налаштування прозорості працюють з усіма операціями малювання. Спробуйте змінити прозорість, щоб побачити ефект. Не забудьте повернути його назад в 1 після всього, щоб не вплинути на подальше малювання. Властивість globalAlpha має бути значенням від 0 до 1, інакше вона буде проігнорована (або може викликати несподівану поведінку на деяких платформах).
Трансформація
<У розділі про діаграми ми малювали один і той же прямокутник знову і знову тільки з різними координатами х і у. Замість модифікації цих координат ми могли б використовувати функцію translate. Кожну ітерацію циклу ми можемо викликати translate зі 100 пікселями для переміщення наступного стовпця вправо.<code data-language="javascript">ctx.fillStyle="red"; for(var i=0; i<data.length; i++) { var dp=data[i]; ctx.translate(<b id="translatedemo_var1">100</b>, 0); ctx.fillRect(0,0,50,dp); }
Спробуйте пересувати змінну х, щоб побачити, як ефект проявляє себе на графіку.
Як і більшість двовимірних API, Canvas підтримує стандартні функції трансформації translate, rotate та scale. Це дозволяє малювати фігури та трансформувати їх на екрані без ручного обчислення нових точок. Canvas вирішує математику за вас. Ви також можете комбінувати трансформації, викликаючи їх по черзі. Наприклад, щоб намалювати прямокутник, зрушити його в центр, а потім повернути на 30 градусів ви можете зробити наступне:
<code data-language="javascript">ctx.fillStyle="red"; ctx.translate(<b id="rotatedemo_x1">50</b>,<b id="rotatedemo_y1">50</b>); //Перетворимо кути на радіани var rads=<b id="rotatedemo_rot1">30</b> * Math.PI*2.0/360.0; ctx.rotate(rads) ctx.fillRect(0,0,100,100);
Кожного разу, коли ви викликаєте translate, rotate або scale вона додається до попередньої трансформації. Згодом це може призвести до плутанини, звісно. Ви можете скасувати трансформацію так:
<code data-language="javascript">for(var i=0; i<data.length; i++) { c.translate(40+i*100, 460-dp * 4); var dp=data[i]; c.fillRect(0,0,50,dp*4); c.translate(-40-i*100,-450+dp*4); }
Але доводиться писати багато набридливого коду. Якщо ви одного разу забули скасувати його, то виявитеся розвиненим і витратите годинник на перегляд коду для цієї однієї помилки. Натомість Canvas пропонує API для збереження станів.
Збереження стану
Об'єкт context2D представляє поточний стан малюнка. У цій книзі я завжди використовую змінну ctx для збереження цього контексту. Стан включає поточну трансформацію, кольори заливки та обведення, поточний шрифт і деякі інші змінні. Ви можете зберегти цей стан, перемістивши його в стек за допомогою функції save(). Після збереження стану можна вносити зміни, а потім відновити у попередній стан функцією restore(). Canvas дбає про бухгалтерію за вас. Ось попередній приклад переписаний із збереженням стану. Зверніть увагу, що нам не потрібно робити крок для скасування translate.
<code data-language="javascript">for(var i=0; i< ;data.length; i++) { c.save(); c.translate(40+i*100, 460-dp*4); var dp=data[i]; c.fillRect(0,0,50,dp*4); c.restore(); }
Маскування
Іноді вам потрібно намалювати лише частину фігури. Це можна зробити за допомогою функції clip. Вона бере поточну фігуру і використовує її як маску для подальшого малювання. Це означає, що будь-який малюнок буде видно лише усередині маски. Все, що ви малюєте за межами маски, не буде показано на екрані. Це може бути корисно, коли ви хочете створити складну графіку за рахунок комбінування фігур або коли ви бажаєте оновити лише частину екрана для підвищення продуктивності. Ось приклад, де використовується трикутник як маска:
//малюємо прямокутник ctx.fillStyle='red'; ctx.fillRect(0,0,400,100); //створюємо трикутний контур ctx.beginPath(); ctx.moveTo(200,<b id="clippingdemo_var1">50</b>); ctx.lineTo(250,150); ctx.lineTo(150,150); ctx.closePath(); //обводимо трикутник, щоб побачити його ctx.lineWidth=10; ctx.stroke(); //використовуємо трикутник як маску ctx.clip(); //Заливаємо прямокутник жовтим кольором ctx.fillStyle='yellow'; ctx.fillRect(0,0,400,100);
Зверніть увагу, що перетин червоного прямокутника та трикутника заливається жовтим кольором. Зауважте також, що нижня частина трикутника має товсту межу, а верхня частина має більш тонку межу. Це відбувається тому, що межа центрується за реальними геометричними краями трикутної фігури. Жовтий накриває внутрішній кордон, коли він обрізається трикутником, але за межами кордон залишається не накритим.
Події
Canvas не визначає жодних нових подій. Ви можете відслідковувати ті самі події миші та торкання, з якими ви працювали десь ще. Це добре і погано.
Canvas тільки виглядає прямокутною областю пікселів у браузері. Браузер не знає ні про будь-які намальовані вами фігури. Якщо ви перетягнете курсор миші за межі полотна, то браузер відправить вам стандартні події перетягування для полотна повністю, а не до чогось конкретного всередині полотна. Це означає, що якщо ви хочете робити спеціальні штуки, на зразок створення кнопок або інструментів малювання, то вам самостійно доведеться обробляти події шляхом перетворення вихідних подій миші браузера у власну модель даних.
Обчислення, яка фігура зараз знаходиться під курсором миші може бути досить важким. На щастя, у Canvas є API для допомоги в цьому: isPointInPath. Ця функція повідомить вас, якщо задана координата знаходиться всередині поточного контуру. Ось простий приклад:
<code data-language="javascript">c.beginPath(); c.arc( 100,100, 40, //коло радіусом 40 пікселів з центром 100,100 0,Math.PI*2, //від 0 до 360 градусів для заливання кола); c.closePath(); var a=c.isPointInPath(80,0); //Повертає true var b=c.isPointInPath (200,100); //повертає false
Інший варіант полягає у використанні бібліотеки, такої як Amino, яка дозволяє працювати в термінах фігур замість пікселів. Вона оброблятиме події та перемальовуватиме за вас.