Приводятся программы, иллюстрирующие доставку с уведомлением и преимущества такой доставки по сравнению с обыч-ной. Иллюстрация выполняется в виде анимации грузопотоков.
В первой анимации присутствуют два маршрута доставки и процессы доставки и им предшествующие события (уведомления). Вто-рая анимация показывает преимущества доставки с уведомлением по сравнению с обычной.
Обе анимации - это результат работы MAXScript-программ, код которых, снабженный подробным комментарием, приводится ни-же.
Выбранные маршруты весьма условны и легко могут быть заменены другими.
Для работы приводимых программ должны быть доступны файл с картой местности (рис. 1) и файл с картой Земли (рис. 2), используемые для создания соответствующих текстур.
Рис. 1. Пример карты местности
Рис. 2. Карта Земли
Уведомления, предшествующие доставке, показываются в виде колец, распространяющихся от к источника к цели.
Для надежности оповещение дублируется. Прозрачность дубля существенно выше прозрачности оригинала. По мере распростране-ния прозрачность колец возрастает.
После обработки уведомлений начинается процесс доставки, отображаемый разноцветными растущими цилиндрами.
Процессы показываются на виде Top.
Приведенная выше анимация обеспечивается следующим кодом:
fn sp r wClr ps = ( -- Рисует сферу
sgs = 32
sphere radius:r segs:sgs pos:ps wireColor:wClr
)
fn tb r ps = ( -- Рисует трубу (кольца на виде Top)
sgs = 32
tube radius1:r radius2:r height:2 pos:ps sides:sgs
)
delete $*
btMp = Bitmaptexture fileName:"C:\Shoya\erp2.jpg"
mt = standard diffuseMap:btMp showInViewport:on
w = 350
h = 0.73 * w
-- Плоскость с текстурой, созданной по файлу erp2.jpg
pln = plane width:w length:h material:mt
r = 2
wClr = color 255 255 255
-- Позиции сфер - пунктов отправки и назначения
-- Route 1
arrPs = #([62.4, 18.9, 0], [40.8, -25.14, 0], [36.03, -52.38, 0], [-6.92, -69.86, 0])
-- Позиции точек (сфер), из которых исходят (в которые приходят) цилиндры - маршруты
arrPs_2 = #([61.34, 15.22, 0], [39.7, -28.2, 0], [32.36, -53.87, 0], [-6.92, -69.86, 0])
-- Route 2
arrPs2 = #([9.2, 18.15, 0], [-38.0, -13.16, 0], [-8.4, -66.9, 0])
arrPs2_2 = #([58.7, 18.86, 0], [6.34, 14.73, 0], [-35.62, -16.53, 0], [-8.4, -66.9, 0])
cnt = arrPs.count
cnt2 = arrPs2.count
cnt2_1 = cnt2 - 1
cnt2_2 = arrPs2_2.count
rK = 1.05 * r
-- Массивы сфер - пунктов отправки и назначения
-- Route 1
arrSph = for k = 1 to cnt collect (sp rK wClr arrPs[k])
-- Route 2
arrSph2 = for k = 1 to cnt2_1 collect (sp rK wClr arrPs2[k])
-- Массивы сфер, излучающих и принимающих цилиндры
-- Route 1
arrSp = for k = 1 to cnt collect (sp r wClr arrPs[k])
arrSp_2 = for k = 1 to cnt - 1 collect (sp rK wClr arrPs_2[k])
-- Route 2
arrSp2 = for k = 1 to cnt2_1 collect (sp r wClr arrPs2[k])
arrSp2_2 = for k = 1 to cnt2_2 collect (sp rK wClr arrPs2_2[k])
-- Cylinders (rays)
-- Route 1
rCl = 0.55 * rK
arrCl = for k = 1 to cnt - 1 collect (cylinder pos:arrPs_2[k] height:0 radius:rCl)
-- Массивы высот и углов поворота цилиндров вокруг оси Z
arrClH = #()
arrClRtZ = #()
for k = 1 to cnt - 1 do (
dx = arrPs_2[k][1] - arrPs[k + 1][1]
dy = arrPs_2[k][2] - arrPs[k + 1][2]
append arrClH (sqrt (dx^2 + dy^2) - rCl)
append arrClRtZ (atan (dy / dx))
)
--for k = 1 to cnt - 1 do arrCl[k].height = arrClH[k] -- Для тестирования
for k = 1 to cnt - 1 do rotate arrCl[k] (angleaxis -90 [0, 1, 0])
for k = 1 to cnt - 1 do rotate arrCl[k] (angleaxis arrClRtZ[k] [0, 0, 1])
-- Route 2
arrCl2 = for k = 1 to cnt2 collect (cylinder pos:arrPs2_2[k] height:0 radius:rCl)
arrClH2 = #()
arrClRtZ2 = #()
for k = 1 to cnt2 do (
dx = arrPs2_2[k][1] - arrPs2[k][1]
dy = arrPs2_2[k][2] - arrPs2[k][2]
append arrClH2 (sqrt (dx^2 + dy^2) - rCl)
dxy = dy / dx
atn = atan dxy
append arrClRtZ2 (if dx > 0 then atn else 180 + atn)
)
for k = 1 to cnt2 do rotate arrCl2[k] (angleaxis -90 [0, 1, 0])
for k = 1 to cnt2 do rotate arrCl2[k] (angleaxis arrClRtZ2[k] [0, 0, 1])
-- Tubes (кольца на виде Top)
-- Route 1
arrTb = for k = 1 to cnt collect (tb 0 arrPs[k])
arrTb_2 = for k = 1 to cnt collect (tb 0 arrPs[k])
-- Route 2
arrTb2 = for k = 1 to cnt2_1 collect (tb 0 arrPs2[k])
arrTb2_2 = for k = 1 to cnt2_1 collect (tb 0 arrPs2[k])
-- Материалы сфер маршрутов 1 и 2
arrMtSp = #()
arrMtSp2 = #()
-- Материалы труб маршрутов 1 и 2
-- Прежде создаем массивы цветов
arrMt = #()
arrMt2 = #()
pct = 100 -- Непрозрачность
clr = [255, 0, 0]
clr2 = [135, 59, 8]
clr3 = [255, 255, 0]
clr4 = [0, 255, 0]
clr5 = [0, 0, 255]
clr6 = [88, 88, 225]
clr7 = [145, 28, 177]
arrClrSp = #(clr, clr4, clr6, clr5)
arrClrSp2 = #(clr3, clr2, clr)
arrClr = #(clr, clr2, clr3, clr4, clr, clr2, clr3, clr4)
arrClr2 = #(clr2, clr3, clr4, clr2, clr3, clr4)
sl = 80
gs = 75
pct2 = 0.6 * pct -- Непрозрачность дублирующей трубы
-- Материалы сфер маршрутов 1 и 2
for k = 1 to cnt do append arrMtSp (standard diffuse:arrClrSp[k] opacity:0 specularLevel:sl glossiness:gs showInViewport:on)
for k = 1 to cnt2 do append arrMtSp2 (standard diffuse:arrClrSp2[k] opacity:0 specularLevel:sl glossiness:gs showInViewport:on)
for k = 1 to cnt do arrSp[k].material = arrMtSp[k]
for k = 1 to cnt - 1 do (
rtMtrl = arrMtSp[k + 1]
arrSp_2[k].material = rtMtrl
arrCl[k].material = rtMtrl
)
for k = 1 to cnt2 do (
rtMtrl = arrMtSp2[k]
if k lt;= cnt2_1 do arrSp2[k].material = rtMtrl
arrSp2_2[k].material = rtMtrl
arrCl2[k].material = rtMtrl
)
rtMtrl = arrMtSp2[cnt2]
arrSp2_2[cnt2_2].material = rtMtrl
arrCl2[cnt2].material = rtMtrl
-- Материалы труб маршрутов 1 и 2
for k = 1 to 2 * cnt do append arrMt (standard diffuse:arrClr[k] opacity:0 specularLevel:sl glossiness:gs showInViewport:on)
for k = 1 to 2 * cnt2 do append arrMt2 (standard diffuse:arrClr2[k] opacity:0 specularLevel:sl glossiness:gs showInViewport:on)
for k = 1 to cnt do (
arrMt[k].opacity = pct
arrMt[k + cnt].opacity = pct2
arrTb[k].material = arrMt[k]
arrTb_2[k].material = arrMt[k + cnt]
)
for k = 1 to cnt2_1 do (
arrMt2[k].opacity = pct
arrMt2[k + cnt2].opacity = pct2
arrTb2[k].material = arrMt2[k]
arrTb2_2[k].material = arrMt2[k + cnt2]
)
dRT = 4
rRngs = 80
tRngs = 160
tPs = 150 -- Пауза для обработки уведомлений
tM = 0
tCrrnt = 0
tCrrnt1 = 0
tCrrnt2 = 0
tDvd = 3.0
animate on (
-- Трубы
-- Route 1
at time 5 (
for k = 1 to cnt do (
arrTb[k].radius1 = 0
arrTb[k].radius2 = 0
)
for k = 1 to cnt do (
arrTb_2[k].radius1 = 0
arrTb_2[k].radius2 = 0
)
)
at time 6 (
for k = 1 to cnt do (
arrTb[k].radius1 = 3 * dRT
arrTb[k].radius2 = 4 * dRT
)
for k = 1 to cnt do (
arrTb_2[k].radius1 = dRt
arrTb_2[k].radius2 = 2 * dRT
)
)
-- Route 2
at time 9 (
for k = 1 to cnt2_1 do (
arrTb2[k].radius1 = 0
arrTb2[k].radius2 = 0
)
for k = 1 to cnt2_1 do (
arrTb2_2[k].radius1 = 0
arrTb2_2[k].radius2 = 0
)
)
at time 10 (
for k = 1 to cnt2_1 do (
arrTb2[k].radius1 = 3 * dRT
arrTb2[k].radius2 = 4 * dRT
)
for k = 1 to cnt2_1 do (
arrTb2_2[k].radius1 = dRT
arrTb2_2[k].radius2 = 2 * dRT
)
)
at time tRngs (
-- Route 1
for k = 1 to cnt do (
arrTb[k].radius1 = rRngs
arrTb[k].radius2 = rRngs + dRT
arrTb_2[k].radius1 = rRngs - 2 * dRT
arrTb_2[k].radius2 = rRngs - dRT
)
-- Route 2
for k = 1 to cnt2_1 do (
arrTb2[k].radius1 = rRngs
arrTb2[k].radius2 = rRngs + dRT
arrTb2_2[k].radius1 = rRngs - 2 * dRT
arrTb2_2[k].radius2 = rRngs - dRT
)
)
at time (tRngs + 1) (
-- Route 1
for k = 1 to cnt do (
arrMt[k].opacity = 60
arrMt[k + cnt].opacity = 10
)
-- Route 2
for k = 1 to cnt2 do (
arrMt2[k].opacity = 60
arrMt2[k + cnt2].opacity = 10
)
)
at time (tRngs + 2) (
-- Route 1
for k = 1 to cnt do (
arrMt[k].opacity = 0
arrMt[k + cnt].opacity = 0
)
-- Route 2
for k = 1 to cnt2 do (
arrMt2[k].opacity = 0
arrMt2[k + cnt2].opacity = 0
)
)
tCrrnt = tRngs + 2 + tPs
-- Сферы - пункты отправки и доставки
at time tCrrnt (
-- Route 1
for k = 1 to cnt do arrSph[k].radius = rK
for k = 1 to cnt do arrMtSp[k].opacity = 0
-- Route 2
for k = 1 to cnt2_1 do arrSph2[k].radius = rK
for k = 1 to cnt2 do arrMtSp2[k].opacity = 0
)
tCrrnt += 1
at time tCrrnt (
-- Route 1
for k = 1 to cnt do arrSph[k].radius = 0
for k = 1 to cnt do arrMtSp[k].opacity = 100
-- Route 2
for k = 1 to cnt2_1 do arrSph2[k].radius = 0
for k = 1 to cnt2 do arrMtSp2[k].opacity = 100
)
-- Цилиндры
-- Route 1
tCrrnt2 = tCrrnt
tRt = 0
for k = 1 to cnt2 do (
hRt = arrClH[k]
tRt = hRt / tDvd
if k > 1 do at time (tCrrnt2 - 1) arrCl[k - 1].height = arrCl[k - 1].height
at time tCrrnt2 arrCl[k].height = 0
tCrrnt2 += tRt
at time tCrrnt2 arrCl[k].height = hRt
)
tCrrnt1 = tCrrnt2
-- Route 2
tCrrnt2 = tCrrnt
tRt = 0
for k = 1 to cnt2 do (
hRt = arrClH2[k]
tRt = hRt / tDvd
if k > 1 do at time (tCrrnt2 - 1) arrCl2[k - 1].height = arrCl2[k - 1].height
at time tCrrnt2 arrCl2[k].height = 0
tCrrnt2 += tRt
at time tCrrnt2 arrCl2[k].height = hRt
)
tCrrnt = amax tCrrnt1 tCrrnt2
)
-- Меняем анимационные сплайны Безье (радиусов колец) на прямые
for k = 1 to cnt do (
arrTb[k].radius1.controller.keys[1].outTangentType = #linear
arrTb[k].radius1.controller.keys[2].inTangentType = #linear
arrTb_2[k].radius1.controller.keys[1].outTangentType = #linear
arrTb_2[k].radius1.controller.keys[2].inTangentType = #linear
arrTb[k].radius2.controller.keys[1].outTangentType = #linear
arrTb[k].radius2.controller.keys[2].inTangentType = #linear
arrTb_2[k].radius2.controller.keys[1].outTangentType = #linear
arrTb_2[k].radius2.controller.keys[2].inTangentType = #linear
)
for k = 1 to cnt2_1 do (
arrTb2[k].radius1.controller.keys[1].outTangentType = #linear
arrTb2[k].radius1.controller.keys[2].inTangentType = #linear
arrTb2_2[k].radius1.controller.keys[1].outTangentType = #linear
arrTb2_2[k].radius1.controller.keys[2].inTangentType = #linear
arrTb2[k].radius2.controller.keys[1].outTangentType = #linear
arrTb2[k].radius2.controller.keys[2].inTangentType = #linear
arrTb2_2[k].radius2.controller.keys[1].outTangentType = #linear
arrTb2_2[k].radius2.controller.keys[2].inTangentType = #linear
)
animationRange = interval 1 (tCrrnt + 5)
--max zoom in 2x
-- playAnimation()
Доставка с уведомлением позволяет существенно экономить ресурсы, что образно показывает следующая анимация:
Чисто красный маршрут - это доставка без уведомления.
Элементы маршрута - это дуги, проводимые между пунктами отправки и назначения. Эти пункты обозначаются сферами.
Для обеспечения надлежащего поворота сфер их базовые точки помещаются в центр Земли - большой сферы.
В каждом промежуточном пункте места доставки и отправки отображаются в виде смежных сфер. Исключение составляют началь-ный и конечный пункты маршрута.
Процесс доставки иллюстрируется растущими дугами (меняется значение параметра from). Кроме того, до начала роста дуги ее render_thickness = 0, а в первый кадр перед ростом устанавливается render_thickness = 1.
Каждый маршрут оформляется в виде группы, которые поворачиваются вокруг оси X на заданный угол. Вторая группа (красный маршрут) поворачивается вдобавок и на небольшой угол вокруг оси Z. Это делается для выравнивания положения сфер (пунктов отправки и доставки) на параллельных маршрутах. (Маршруты, хотя и совпадают, показываются в виде параллельных фигур.)
В анимации в каждой из доставок две разновидности: доставки без обратной связи и с наличием обратной связи.
Обе разновидности обеспечиваются следующим кодом:
delete $*
nSgs = 32
btMp = Bitmaptexture fileName:"C:\Shoya\earth.jpg"
-- Материал для планеты Земля
mt = standard diffuseMap:btMp showInViewport:on
meditMaterials[1] = mt -- Для отладки
rZ = 53.712 -- Радиус Земли (вместо верного 63.712)
rZ = 0.5 * rZ
rZ2 = 1.3 * rZ
rCr = rZ2 + 3
rP = 0.025 * rZ
rT = 1.15 * rP
sp = sphere radius:rZ2 segs:nSgs
sp.material = mt
-- Вращаем Землю (для показа нужной части планеты)
rotate sp (angleaxis 22 [1, 0, 0])
rotate sp (angleaxis 25 [0, 1, 0])
rotate sp (angleaxis -95 [0, 0, 1])
-- Вспомогательная окружность, обеспечивающая надлежащий поворот групп - маршрутов
cr = circle radius:rCr
arrSp2 = #()
arrSp3 = #()
arrMt = #()
pct = 100 -- Непрозрачность
-- Цвета для дуг и материалов сфер
clr = [255, 0, 0]
clr2 = [135, 59, 8]
clr3 = [255, 255, 0]
clr4 = [0, 255, 0]
clr5 = [0, 0, 255]
clr6 = [88, 88, 225]
clr7 = [145, 28, 177]
arrClr = #(clr, clr2, clr3, clr4, clr5, clr6, clr7)
sl = 80
gs = 75
-- Число пунктов в маршруте
nK = 8
nK1 = nK - 1
nK2 = nK - 2
-- Материалы для сфер (пунктов отправки и доставки)
for k =1 to nK1 do append arrMt (standard diffuse:arrClr[k] opacity:pct specularLevel:sl glossiness:gs)
-- Массивы для дуг
arrRc = #()
arrNRc = #()
arrNRc2 = #()
-- Угол между пунктами
ngl0 = 35
ngl = ngl0
dst = 10.0 / 2
dcrs = 0.6
-- Угол между рядом расположенными сферами (пунктами доставки и отправки)
dNgl2 = 1.5 * asin (rP / rZ2)
nRc = 180 + ngl0
-- Group 1 (маршрут с уведомлением)
-- Располагаем сферы (пункты отправки и назначения) по дуге
for k = 1 to nK do (
-- Пункты отправки
if k < nK do (
sp2 = sphere radius:rP pos:[-rZ2 * cos ngl, -rZ2 * sin ngl, 0]
sp2.material = arrMt[k]
sp2.pivot = [0, 0, 0] -- Ставим базовую точку в центр Земли
append arrSp2 sp2
)
-- Пункты прибытия
if k > 1 do (
ngl2 = ngl - dNgl2
sp3 = sphere radius:rP pos:[-rZ2 * cos ngl2, -rZ2 * sin ngl2, 0]
sp3.material = arrMt[k - 1]
sp3.pivot = [0, 0, 0] -- Ставим базовую точку в центр Земли
append arrSp3 sp3
)
dNgl = 2.0 * asin (dst / rZ2)
dst -= dcrs
ngl += dNgl
nRc2 = nRc + dNgl - dNgl2
if k < nK do (
rc = Arc radius:rZ2 from:nRc to:nRc2 render_renderable:on render_displayRenderMesh:on wireColor:arrClr[k] rend-er_thickness:0
append arrNRc nRc
append arrNRc2 nRc2
append arrRc rc
)
nRc += dNgl
)
arrGr = #()
append arrGr cr
for k = 1 to nK1 do (
append arrGr arrSp2[k]
append arrGr arrSp3[k]
append arrGr arrRc[k]
)
gr = group arrGr
-- Угол поворота первой группы
nglGr = -40
rotate gr (angleaxis nglGr [1, 0, 0])
--
-- Group 2 (маршрут без уведомления)
-- Материал и массивы для второго маршрута
mtRed = standard diffuse:clr opacity:pct specularLevel:sl glossiness:gs
arrSp4 = #()
arrSp5 = #()
arrNRc3 = #()
arrNRc4 = #()
arrRc2 = #()
ngl = ngl0
dst = 10.0 / 2
nRc = 180 + ngl0
for k = 1 to nK do (
if k < nK do (
sp2 = sphere radius:rP pos:[-rZ2 * cos ngl, -rZ2 * sin ngl, 0]
sp2.material = mtRed
sp2.pivot = [0, 0, 0]
append arrSp4 sp2
)
if k > 1 do (
ngl2 = ngl - dNgl2
sp3 = sphere radius:rP pos:[-rZ2 * cos ngl2, -rZ2 * sin ngl2, 0]
sp3.material = mtRed
sp3.pivot = [0, 0, 0]
append arrSp5 sp3
)
dNgl = 2.0 * asin (dst / rZ2)
dst -= dcrs
ngl += dNgl
nRc2 = nRc + dNgl - dNgl2
if k < nK do (
rc = Arc radius:rZ2 from:nRc to:nRc2 render_renderable:on render_displayRenderMesh:on wireColor:red rend-er_thickness:0
append arrNRc3 nRc
append arrNRc4 nRc2
append arrRc2 rc
)
nRc += dNgl
)
arrGr2 = #()
cr2 = circle radius:rCr
append arrGr2 cr2
for k = 1 to nK1 do (
append arrGr2 arrSp4[k]
append arrGr2 arrSp5[k]
append arrGr2 arrRc2[k]
)
gr2 = group arrGr2
-- Угол поворота второй группы
nglGr2 = -38
rotate gr2 (angleaxis nglGr2 [1, 0, 0])
rotate gr2 (angleaxis 0.4 [0, 0, 1]) -- Калибруем положение второй группы
hide cr2
dt = 7
dt2 = 15 -- Для расчета паузы (dt2 * nDt ) перед началом доставки
dtRed = 30 -- Время доставки между пунктами маршрута без уведомлений
nDt = 18
-- Если rf = 0, то имеем маршрут с обратной связью (дуги задерживаются в сцене, дожидаясь конца доставки)
rf = 1 -- or rf = 0 or rf = 2
-- Начало изменений
t = if rf == 1 then dt2 else 1
flash = off -- Если flash = on, то перед началом доставки будем наблюдать мигающие сферы
animate on (
-- Route 1
at time 0
for k = 1 to nK1 do (
arrMt[k].opacity = if rf == 1 then 0 else 100
arrRc[k].to = arrNRc[k]
arrRc[k].render_thickness = 0
)
if flash then -- Мигающие сферы
for k = 1 to nDt / 2 do (
at time t for k = 1 to nK1 do arrMt[k].opacity = 0
t += dt2
at time t for k = 1 to nK1 do arrMt[k].opacity = 100
t += dt2
)
else (
if rf == 1 do (
at time (t - 1) for k = 1 to nK1 do arrMt[k].opacity = 0
at time t for k = 1 to nK1 do arrMt[k].opacity = 100
)
t += nDt * dt2
)
t12 = t
at time (t - 1) (
arrRc[1].to = arrNRc[1]
arrRc[1].render_thickness = 0
)
at time t arrRc[1].render_thickness =rT
for k = 1 to nK1 do (
t += dt
at time t (
arrRc[k].to = arrNRc2[k]
arrRc[k].render_thickness = rT
if k lt;nK1 do (
arrRc[k + 1].to = arrNRc[k + 1]
arrRc[k + 1].render_thickness = 0
)
)
if rf > 0 do (
at time (t + 1) (
arrRc[k].to = arrNRc[k]
arrRc[k].render_thickness = 0
)
)
)
if rf == 0 then (
for k = 1 to nK1 do (
t += dt
at time t (
arrRc[k].from = arrNRc[k]
arrRc[k].render_thickness = rT
)
t += dt
at time t (
arrRc[k].from = arrNRc2[k]
arrRc[k].render_thickness = 0
)
)
)
-- Route 2
t = if rf == 1 then dt2 else 1
at time 0 (
mtRed.opacity = if rf == 1 then 0 else 100
for k = 1 to nK1 do (
arrRc2[k].to = arrNRc3[k]
arrRc2[k].render_thickness = 0
)
if rf == 1 do (
at time (t - 1) mtRed.opacity = 0
at time t mtRed.opacity = 100
)
t += nDt * dt2
)
t = t12
at time (t - 1) (
arrRc2[1].to = arrNRc3[1]
arrRc2[1].render_thickness = 0
)
at time t arrRc2[1].render_thickness =rT
for k = 1 to nK1 do (
t += dt
at time t (
arrRc2[k].to = arrNRc4[k]
arrRc2[k].render_thickness = rT
if k < nK1 do (
arrRc2[k + 1].to = arrNRc3[k + 1]
arrRc2[k + 1].render_thickness = 0
)
)
t += dtRed
at time t (
arrRc2[k].to = arrNRc4[k]
arrRc2[k].render_thickness = rT
if k < nK1 do (
arrRc2[k + 1].to = arrNRc3[k + 1]
arrRc2[k + 1].render_thickness = 0
)
)
if rf > 0 do (
at time (t + 1) (
arrRc2[k].to = arrNRc3[k]
arrRc2[k].render_thickness = 0
)
)
)
if rf == 0 then (
for k = 1 to nK1 do (
t += dtRed
at time t (
arrRc2[k].from = arrNRc3[k]
arrRc2[k].render_thickness = rT
)
t += dt
at time t (
arrRc2[k].from = arrNRc4[k]
arrRc2[k].render_thickness = 0
)
)
)
)
rng = t + 5
animationRange = interval 1 rng
-- max zoom in 2x
--playAnimation()
Представленные анимации предназначены для продвижения доставок с уведомлением. Зритель может, во-первых, наблюдать порядок осуществления такой доставки, и, во-вторых, - ее преимущества.