Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > ZackMercury

Оценить эту запись

Пишем круглый прогресс-бар.

Запись от ZackMercury размещена 20.03.2015 в 22:47
Обновил(-а) Zebestov 24.03.2015 в 02:01 (Исправление ошибки в сказке.)

Ну, разбирать не будем будем разбирать всё до деталей.

Сам класс:

Код AS3:
package com.zackmercury.tools
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
 
	/**
	 * Запрещаю продавать, разрешаю делиться и выкладывать в интернет(разумеется, с указанием автора и источника)
	 * Разрешаю совершенствовать.
	 *
	 * @author ZackMercury
	 */
	public class CircularBar extends Bitmap
	{
		private var _percent:Number;
		private var _width:int;
		private var _height:int;
		private var _shape:Shape;
		private var _canvas:Graphics;
		private var _step:Number;
		private var _color:uint;
		private var _thickness:int;
 
		private var scale:Number;
		private var halfWidth:int;
		private var halfHeight:int;
		private var halfWidthWithoutThickness:int;
		private var halfHeightWidthoutThickness:int;
 
		/**
		 * 
		 * @param	width     The width of the circular bar.
		 * @param	height    The height of the circular bar.
		 * @param	thickness Thickness of line that fills the bar.
		 * @param	color     Color of line that fills the bar.
		 * @param	step      Step is a step of a loops that drawing a circle(smaller == smoother).
		 * @param	value     Value is a default value of the bar.
		 */
		public function CircularBar(width:int = 100, height:int = 100, thickness:int = 30, color:uint = 0x66FF66, step:Number = 0.2, value:Number = 0.7)
		{
			super(new BitmapData(width, height, true, 0x00000000), "auto", true);
 
			_width = width;
			_height = height;
			_percent = value;
			_step = step;
			_shape = new Shape();
			_canvas = _shape.graphics;
			_color = color;
 
			if(thickness >= 0 && thickness <= int(width / 2))
				_thickness = thickness;
			else
				_thickness = int(width / 2);
 
 
 
			halfWidth = int(_width / 2);
			halfHeight = int(_width / 2);
			halfWidthWithoutThickness = int((_width - 2 * _thickness) / 2);
			halfHeightWidthoutThickness = int((_width - 2 * _thickness) / 2);
			scale = _height / _width;
 
			update();
		}
 
		private function update():void
		{
			_canvas.clear();
			_canvas.beginFill(_color);
			var endAngle:Number = _percent * 6.283185307179586;
 
			_canvas.moveTo(halfWidth + Math.cos(endAngle) * halfWidth, halfHeight + Math.sin(endAngle) * halfHeight);
 
			for (var angle1:Number = endAngle; angle1 > 0; angle1 -= _step)
			{
				_canvas.lineTo(halfWidth + Math.cos(angle1) * halfWidth, halfHeight + Math.sin(angle1) * halfHeight);
			}
 
			_canvas.lineTo(halfWidth + Math.cos(0) * halfWidth, halfHeight + Math.sin(0) * halfHeight);
 
			for (var angle2:Number = 0; angle2 < endAngle; angle2 += _step)
			{
				_canvas.lineTo(halfWidth + Math.cos(angle2) * halfWidthWithoutThickness, halfHeight + Math.sin(angle2) * halfHeightWidthoutThickness);
			}
 
			_canvas.lineTo(halfWidth + Math.cos(endAngle) * halfWidthWithoutThickness, halfHeight + Math.sin(endAngle) * halfHeightWidthoutThickness);
			_canvas.endFill();
			_shape.scaleY = scale;
 
			bitmapData.fillRect(new Rectangle(0, 0, bitmapData.width, bitmapData.height), 0x00000000);
			bitmapData.draw(_shape, _shape.transform.matrix);
 
			dispatchEvent(new Event(Event.CHANGE));
		}
 
		public function set value(value:Number):void
		{
			if (value < 0 || value > 1)
				return;
			_percent = value;
			update();
		}
 
		public function get value():Number
		{
			return _percent;
		}
	}
 
}
Как пользоваться:
Код AS3:
var bar:CircularBar = new CircularBar();
bar.value = .75;
addChild(bar);
Параметры, идущие в конструкторе документированы с помощью ASDoc

Демка:
main.swf   (22.8 Кб)


Код демки:
Код AS3:
package
{
	import com.zackmercury.bloodrain.App;
	import com.zackmercury.tools.CircularBar;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.utils.getTimer;
 
	public class Main extends Sprite
	{
		private var _bar:CircularBar;
		private var _bar2:CircularBar;
		private var _bar3:CircularBar;
		public function Main()
		{
			super();
 
			stage ? init() : addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void
		{
			if (hasEventListener(Event.ADDED_TO_STAGE)) removeEventListener(Event.ADDED_TO_STAGE, init);
			//entry point
 
			_bar = new CircularBar(200, 200, 50, 0x11CC22, 0.1);
			addChild(_bar);
			var _tf:TextField = new TextField();
			_tf.text = "width = 200, height = 200, thickness = 50, color = 0x11CC22, step = 0.1";
			_tf.multiline = true;
			_tf.wordWrap = true;
			_tf.y = _bar.height;
			_tf.x = (_bar.width - _tf.width) / 2;
			addChild(_tf);
 
			_bar2 = new CircularBar(150, 80, 70, 0xCCCC00, 0.1);
			addChild(_bar2);
			_bar2.x = _bar.x + _bar.width + 20;
			var _tf2:TextField = new TextField();
			_tf2.text = "width = 150, height = 80, thickness = 70, color = 0xCCCC00, 0.1";
			_tf2.multiline = true;
			_tf2.wordWrap = true;
			_tf2.y = _bar2.height;
			_tf2.x = _bar2.x + (_bar2.width - _tf2.width) / 2;
			addChild(_tf2);
 
			_bar3 = new CircularBar(100, 100, 50, 0xCC2222, 0.2);
			addChild(_bar3);
			_bar3.x = _bar2.x + _bar2.width + 20;
			var _tf3:TextField = new TextField();
			_tf3.text = "width = 100, height = 100, thickness = 50, color = 0xCC2222, 0.2";
			_tf3.multiline = true;
			_tf3.wordWrap = true;
			_tf3.y = _bar3.height;
			_tf3.x = _bar3.x + (_bar3.width - _tf3.width) / 2;
			addChild(_tf3);
 
			addEventListener(Event.ENTER_FRAME, update);
		}
 
		private function update(e:Event = null):void
		{
			var value:Number = (1 + Math.sin(getTimer() / 2000)) / 2;
			_bar.value = value;
			_bar2.value = value;
			_bar3.value = value;
		}
	}
}
А теперь сказка о том, как делалось.

Жил-был прогресс-бар. Но был он прямоугольным и некрасивым.
Был он таким много лет, пока люди не додумались скрутить его в трубочку.

Вот так вот просто взять и скрутить.

Ладно, давайте вспомним, что такое круг и как его нарисовать средствами флеш?
Вы тоже об этом подумали? Graphics.drawCircle()? Вы почти у цели.

Ладно, как же нарисовать круг с помощью lineTo?
Как нам описать круг в пространстве по точкам?
В этом нам поможет замечательный цикл for и число 6.283185307179586, что приблизительно равно PI*2.

Код AS3:
var width, height:int;
width = height = 100;
 
var shape:Shape = new Shape();
var _canvas = shape.graphics;
 
with(_canvas)
{
	beginFill(0xFF00FF);
	moveTo( width, height / 2 ); //именно в этой точке начинается отсчёт градусов
 
	for(var angle:Number = 0; angle <= 6.283185307179586; angle += 0.1)
	{
		lineTo(width / 2 + Math.cos(angle) * width / 2, height / 2 + Math.sin(angle) * height / 2);
	}
}
Именно так мы получаем целый круг.
Но для отображения прогресса, нам не нужен целый круг, верно? Нам нужен лишь его кусок.
Для этого мы делаем вот так:
Код AS3:
var width, height:int;
width = height = 100;
 
var percent:Number = 0.75;
 
var shape:Shape = new Shape();
var _canvas = shape.graphics;
 
with(_canvas)
{
	beginFill(0xFF00FF);
	moveTo( width/2, height / 2 ); //начинаем из центра, абы выглядело как нам надо
 
 
	for(var angle:Number = 0; angle <= percent * 6.283185307179586; angle += 0.1)
	{
		lineTo(width / 2 + Math.cos(angle) * width / 2, height / 2 + Math.sin(angle) * height / 2);
	}
}
Выходит что-то вроде круговой диаграммы. Уже неплохо.
Но нам-то нужна полоска!

Что-ж, выходит, для этого нам нужно нарисовать внешнюю её границу, срезы и внутреннюю границу.
Внешняя и внутренняя границы имеют формы круга, а значит, делать их нужно циклами, проходящими от нуля до 2Пи и обратно.

Пишем вот так:
Код AS3:
var width, height:int;
width = height = 100;
 
var percent:Number = 0.75;
 
var shape:Shape = new Shape();
var _canvas = shape.graphics;
 
with(_canvas)
{
	beginFill(0xFF00FF);
	moveTo(width / 2 + Math.cos(0) * width / 2, height / 2 + Math.sin(0) * height / 2); //двигаем курсор в нулевую позицию уже не руками
 
	for(var angle:Number = 0; angle <= percent * 6.283185307179586; angle += 0.1)
	{
		lineTo(width / 2 + Math.cos(angle) * width / 2, height / 2 + Math.sin(angle) * height / 2);
	}
 
	lineTo(width / 2 + Math.cos(percent * 6.283185307179586) * width / 2, height / 2 + Math.sin(percent * 6.283185307179586) * height / 2); // Вручную делаем скос, ибо цикл сам не дойдёт до него.
 
	for(var angle:Number = percent * 6.283185307179586; angle > 0 ; angle -= 0.1)
	{
		lineTo(width / 2 + Math.cos(angle) * width / 3, height / 2 + Math.sin(angle) * height / 3);
	}
 
	lineTo(width / 2 + Math.cos(0) * width / 3, height / 2 + Math.sin(0) * height / 3); // Вручную делаем скос, ибо цикл сам не дойдёт до него.
}
Здесь внутреннее кольцо я сделал без учёта ширины, хотя класс с учётом. Вместо этого я сделал его с радиусом width / 3.

Вуаля!
Круговые прогресс-бары рулят.

И в конец добавлю про то, что класс хоть и использует шейп, сам не является векторной графикой, он, как крем для производительности, наследует Bitmap и обновляет картинку с векторного шейпа только если его трогать за value, рисуя её в битмапдату наследуемого Bitmap.

Вложения
Тип файла: swf main.swf (22.8 Кб, 866 просмотров)
Всего комментариев 28

Комментарии

Старый 21.03.2015 16:27 samana вне форума
samana
 
Аватар для samana
Ещё классно, если можно было бы передать для этого прогресс бар какой нибудь визуальный объект, на который автоматически наложится такая циркулярная маска.
Старый 21.03.2015 19:56 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
samana, да, я тоже об этом думал. Но это уже сверх логики самого прогресс-бара, и кому надо пусть расширяют до SkinnedCircularBar, и реализуют и заднюю подкладку, и маску самого прогресса(например, с скруглёнными краями начала и конца).

Правда так то лучше будет сделать некоторые поля protected.

Кстати, думал насчёт программного скругления краёв, абы выглядело красиво, но с реализацией возникли сложности. Хотя примерно я представляю, как должно быть:
1) Делаем цикл 0.5 PI косинус синус умножаем на половину толщины бара.(начинаем с верху, т.е. цикл с 1.5PI до 2PI)
2) Вычитаем потраченный угол на скругление из процента, дважды(на конце полоски также), тут операции с шириной и высотой, а также толщиной.
3) Ведём ведём сколько надо проценту, из которого уже вычтены затраты на скругление.
4) А вот тут немного застопорился, ведь угол уже не под прямым углом то... Хорошо бы и первый угол тоже реализовать не вручную(ставя в верх или вправо) а в зависимости от положения на кругу, т.е. процента, т.е. текущего градуса.

И далее, возникает ещё одна проблемка по этому алгоритму, когда процент 0, к примеру, полукруг всё равно будет рисоваться, таким образом нужно как-то резать и сам полукруг.
Обновил(-а) ZackMercury 21.03.2015 в 20:15
Старый 21.03.2015 20:32 samana вне форума
samana
 
Аватар для samana
Цитата:
Кстати, думал насчёт программного скругления краёв
Так же стоит учесть, проблему скругления в момент, когда параметр thickness достаточно высокий (как в демке, второй вариант). И если скругление края будет тоже большим, то не понятно, как должна выглядеть внутренняя дырочка визуально.

Цитата:
я тоже об этом думал. Но это уже сверх логики самого прогресс-бара
Мне кажется это очень простая реализация, вам нужно будет всего лишь установить ваш бар в качестве маски)
Старый 21.03.2015 20:41 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
А, вы об этом... А в чём соль написать одну строчку
Код AS3:
someSprite.mask = new CircularBar(..., ..., ...);
чем
Код AS3:
new CircularBar(..., ..., ..., someSprite);
Не вижу неудобства в первом варианте, учитывая, что прогрессбару пофигшоВамнадо маска, допишите, если вам так удобней)
Старый 21.03.2015 21:26 samana вне форума
samana
 
Аватар для samana
Вы правы, можно и так сделать.
Ещё заметил, что появляются некрасивые вещи, если ширина отлична от высоты и thickness большой. Толщину наверно вообще стоило бы как-то ограничить в зависимости от масштаба бара.
Старый 21.03.2015 21:41 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
Ага, действительно. Сделаю вот как: ширина пусть задаёт масштаб для шейпа и высоты, и ширины, далее перед отрисовкой устанавливаем шейпу высоту какую надо.
Старый 23.03.2015 20:38 dimarik вне форума
dimarik
 
Аватар для dimarik
Если знать о полярных координатах, то второй цикл не нужен.

И еще:
Цитата:
Демка:
[Вложение #470 - не найдено]
Исправьте, пожалуйста.
Старый 24.03.2015 02:09 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Миленько.

1. Экранный объект я и сам смогу сплющить, перекосить, повернуть. Так может не надо этих эллиптических уточнений?

2. Как-то привычней и понятней выглядел бы такой набор параметров:

- color (задается всегда)
- outerRadius (внешний радиус, задается всегда)
- innerRadius (по умолчанию равен нулю, потому и идет последним)

оно вроде как-то более привычно для людей, которые пользуются редакторами, что позволяют всякие кольца/торы, там так.
Старый 24.03.2015 20:13 dimarik вне форума
dimarik
 
Аватар для dimarik
Вот теперь демку видно! Красиво, молодец!
Старый 25.03.2015 16:37 alatar вне форума
alatar
 
Аватар для alatar
Если заменить lineTo на curveTo можно кардинально сократить число проходов по циклу.
https://github.com/alatarus/gauges/b.../DonutSlice.as
Старый 25.03.2015 22:58 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
alatar, а это имеет смысл? Я просто думал, curveTo - это обёртка над lineTo. Верней, догадывался.
Попробуем сиё и даже проведём тест по скорости.

Цитата:
Если знать о полярных координатах, то второй цикл не нужен.
Не пробовал, но может действительно сэкономит по производительности?

А ещё в некоторых источниках советуют использовать закешированную хеш-таблицу значений тригонометрических функций. Возможно, это как-то поможет сэкономить ресурсы?

Zebestov, ну, если редакторами то да. Но мы то кодом всё пилим) Материал я дал для того, чтобы спилить как удобно.
Старый 26.03.2015 05:06 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Спорить не стану, это личное предпочтение, которое, возможно, найдет отклик. Мне лишь кажется логичным всегда знать, каков внешний и внутренний радиус кольца.
Старый 26.03.2015 13:39 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
dimarik, я тут почитал, да, думаю, действительно, сэкономит рассчёты рисование в одном цикле.
Но что конкретно имелось в виду? Рисовать 2 палки сразу на двух уровнях, с помощью moveTo?
Старый 26.03.2015 14:07 alatar вне форума
alatar
 
Аватар для alatar
Цитата:
Я просто думал, curveTo - это обёртка над lineTo.
Алгоритмы отрисовки линии и кривой совершенно разные.
Старый 27.03.2015 11:21 dimarik вне форума
dimarik
 
Аватар для dimarik
ZackMercury, думаю, да.
moveTo(prev_position_outer), curveTo(new_position_outer), moveTo(prev_position_inner), curveTo(new_position_inner),
Старый 28.03.2015 20:36 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
dimarik, при таком раскладе заливка исчезает.
Даже при рисовании обычного круга со смещением курсора в его же координаты.

Код AS3:
var shp:Shape = new Shape();
var last:Point = new Point();
with(shp.graphics)
{
	beginFill(0x00FFFF);
	lineStyle(2, 0);
	last.x = Math.cos(0)*50;
	last.y = Math.sin(0)*50;
	for(var ang:Number = 0; ang < 6.28; ang += 0.1)
	{
		moveTo(last.x, last.y);
		last.x = Math.cos(ang)*50;
		last.y = Math.sin(ang)*50;
		lineTo(last.x, last.y);
	}
 
	moveTo(last.x, last.y);
	lineTo(Math.cos(0)*50, Math.sin(0)*50);
}
 
addChild(shp);
shp.x = shp.y = 50;
P.S. Заливки не наблюдается даже вот так:
Код AS3:
var shp:Shape = new Shape();
with(shp.graphics)
{
	beginFill(0xFFFF00);
	lineStyle(2, 0);
	moveTo(0, 0);
	lineTo(100, 100);
	moveTo(100,100);
	lineTo(0, 100);
	moveTo(0, 100);
	lineTo(0, 0);
	endFill();
}
addChild(shp);
Похоже, что одним циклом не сделать.
Ну да ладно, пока что попробую оптимизировать с помощью 2-ух вещей - curveTo и потом ещё drawCircle + вырезание кусков.
Обновил(-а) ZackMercury 30.03.2015 в 01:50
Старый 30.03.2015 20:57 dimarik вне форума
dimarik
 
Аватар для dimarik
ZackMercury, если рисовать по нарисованному, оно стирается. Сделай так, чтобы новая заливка образовывала новый контур.
Старый 31.03.2015 01:33 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
dimarik, ткните меня носом где я рисую по нарисованному. Попробуйте выполнить первый код что я скинул в чистом проекте и второй. И исправьте, чтобы заливка появилась. Лично я не вижу, что в коде рисуется по нарисованному. (эти 2 теста никак не относятся к прогресс-бару, если что, просто тесты)

Если убрать в последнем 2 последних moveTo, то заливка появляется.
Я подозреваю, что нельзя двигать курсор после начала заливки.
Старый 31.03.2015 10:42 dimarik вне форума
dimarik
 
Аватар для dimarik
Пожалуйста, две отдельные заливки.
Код AS3:
const g:Graphics = this.graphics;
g.beginFill(0xFF0000, 1.0);
g.drawRect(0, 0, 100, 100);
// Отдельная заливка. Стирается часть предыдущей заливки
g.drawRect(50, 50, 200, 200);
// Просто отдельная заливка
// g.drawRect(101, 101, 200, 200);
g.endFill();
Старый 31.03.2015 12:10 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
... И где в моём коде что-то подобное?

Цитата:
dimarik, ткните меня носом где я рисую по нарисованному. Попробуйте выполнить первый код что я скинул в чистом проекте и второй. И исправьте, чтобы заливка появилась.
Старый 31.03.2015 16:03 dimarik вне форума
dimarik
 
Аватар для dimarik
Я имел ввиду что-то типа такого
Код AS3:
var shp:Shape = new Shape();
const g:Graphics = shp.graphics;
var p1:	Point;
var p2:	Point;
 
const step:		Number = Math.PI / 8;
const inner:	Number = 50;
const outer:	Number = 100;
 
for (var ang:Number = 0; ang < Math.PI + Math.PI / 3; ang += step) {
	g.beginFill(0x000000);
 
	p1 = Point.polar(inner, ang);
	g.moveTo(p1.x, p1.y);
 
	p2 = Point.polar(outer, ang);
	g.lineTo(p2.x, p2.y);
 
	p2 = Point.polar(outer, ang + step);
	g.lineTo(p2.x, p2.y);
 
	p2 = Point.polar(inner, ang + step);
	g.lineTo(p2.x, p2.y);
 
	g.lineTo(p1.x, p1.y);
 
	g.endFill();
}
addChild(shp);
shp.x = shp.y = 250;
Старый 31.03.2015 16:53 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
dimarik, так бы и написали, что сделать не одной заливкой а на каждый степ по заливке, а то загадками говорите

Сейчас проведу тест по скорости.
Обновил(-а) ZackMercury 31.03.2015 в 18:27
Старый 31.03.2015 18:27 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
UPD: Результаты вполне ожидаемые. (Тестил в релизной, по клику, и стендалон плеер и браузер - одинаково почти)
Вариант с двумя циклами: 1768; Вариант с полярными координатами: 7370;

Код теста
Код AS3:
package com.zackmercury
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.display.Graphics;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.utils.getTimer;
 
	/**
	 * ...
	 * @author ZackMercury
	 */
 
	public class Main extends Sprite
	{
		private var _tf:TextField = new TextField();
		private var shp2:Shape;
		private var shp:Shape;
 
		private var rOuter:int = 50;
		private var rInner:int = 30;
		private var step:Number = Math.PI / 16;
 
		public function Main()
		{
			if (stage)
				init();
			else
				addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		public function init(e:Event = null):void
		{
			if (hasEventListener(Event.ADDED_TO_STAGE))
				removeEventListener(Event.ADDED_TO_STAGE, init);
			//entry
			var btn:MyButton = new MyButton("Test");
			btn.onClick = beginTest;
			addChild(btn);
			addChild(_tf);
			_tf.text = "Results here.";
			_tf.x = _tf.y = 100;
 
			shp = new Shape();
			shp2 = new Shape();
 
			addChild(shp);
			addChild(shp2);
			shp.x = 200;
			shp2.x = 400;
 
			shp.y = shp2.y = rOuter;
		}
 
		private function beginTest(e:MouseEvent):void
		{
			var time1:int = getTimer();
			for (var i:int = 0; i < 100000; i++)
			{
				var g:Graphics = shp.graphics;
				g.clear();
				var percent = (1 + Math.sin(i / 1000)) / 2;
				var reqAngle:Number = percent * 6.283185307179586;
				g.beginFill(0xFFAA00);
				g.moveTo(Math.cos(0) * rOuter, Math.sin(0) * rOuter);
 
				for (var ang:Number = 0; ang < reqAngle; ang += step)
				{
					g.lineTo(Math.cos(ang) * rOuter, Math.sin(ang) * rOuter);
				}
 
				g.lineTo(Math.cos(reqAngle) * rOuter, Math.sin(reqAngle) * rOuter);
 
				for (var ang:Number = reqAngle; ang > 0; ang -= step)
				{
					g.lineTo(Math.cos(ang) * rInner, Math.sin(ang) * rInner);
				}
 
				g.lineTo(Math.cos(0) * rInner, Math.sin(0) * rInner);
			}
			var time2:int = getTimer();
			for (var i:int = 0; i < 100000; i++)
			{
				var g:Graphics = shp2.graphics;
				g.clear();
				var percent = (1 + Math.sin(i / 1000)) / 2;
				var reqAngle:Number = percent * 6.283185307179586;
				var p1:Point;
				var p2:Point;
 
				var ang:Number;
 
				for (ang = 0; ang < reqAngle; ang += step)
				{
					g.beginFill(0xF08801);
 
					p1 = Point.polar(rInner, ang);
					g.moveTo(p1.x, p1.y);
 
					p2 = Point.polar(rOuter, ang);
					g.lineTo(p2.x, p2.y);
 
					p2 = Point.polar(rOuter, ang + step);
					g.lineTo(p2.x, p2.y);
 
					p2 = Point.polar(rInner, ang + step);
					g.lineTo(p2.x, p2.y);
 
					g.lineTo(p1.x, p1.y);
 
					g.endFill();
				}
			}
			var time3:int = getTimer();
 
			_tf.text = "1: " + (time2 - time1) + "; 2: " + (time3 - time2) + ";";
		}
	}
}
MyButton.as
Код AS3:
package com.zackmercury
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
 
	/**
	 * ...
	 * @author ZackMercury
	 */
	public class MyButton extends Sprite 
	{
		private static const NORMAL:ColorTransform = new ColorTransform(1, 1, 1, 1);
		private static const PRESSED:ColorTransform = new ColorTransform(0.7, 0.7, 0.7);
		private static const OVER:ColorTransform = new ColorTransform(1.1, 1.1, 1.1);
 
		private var _caption:String;
		private var _buttonText:TextField;
		private var _holded:Boolean = false;
		private var _callback:Function;
 
		public function MyButton(caption:String) 
		{
			super.mouseChildren = false;
			drawButton();
			this.caption = caption;
			addEventListener(MouseEvent.MOUSE_DOWN, mDown);
			addEventListener(MouseEvent.MOUSE_UP, mUp);
			addEventListener(MouseEvent.MOUSE_OVER, mOver);
			addEventListener(MouseEvent.MOUSE_OUT, mOut);
		}
 
		public function set onClick(onClick:Function):void
		{
			_callback = onClick;
		}
 
		public function mDown(e:MouseEvent = null):void
		{
			this.transform.colorTransform = PRESSED;
			_holded = true;
		}
 
		public function mUp(e:MouseEvent = null):void
		{
			this.transform.colorTransform = OVER;
			if (_holded)
				_callback(e);
			_holded = false;
		}
 
		public function mOver(e:MouseEvent = null):void
		{
			if (!_holded)
				this.transform.colorTransform = OVER;
		}
 
		public function mOut(e:MouseEvent = null):void
		{
			if (!_holded)
				this.transform.colorTransform = NORMAL;
			else
			{
				_holded = false;
				this.transform.colorTransform = NORMAL;
			}
		}
 
		public function set caption(caption:String):void
		{
			_caption = caption;
			if (!_buttonText)
			{
				_buttonText = new TextField();
				_buttonText.selectable = false;
				_buttonText.defaultTextFormat = new TextFormat("Consolas", 10, 0xFFFFFF, false, false, false, null, null, TextFormatAlign.CENTER);
				_buttonText.autoSize = TextFieldAutoSize.CENTER;
				addChild(_buttonText);
			}
			_buttonText.text = _caption;
		}
 
		private function drawButton():void
		{
			var g:Graphics = this.graphics;
			g.beginFill(0x22AA22);
			g.drawRect(0, 0, 100, 20);
			g.endFill();
		}
 
		public function get caption():String
		{
			return _caption;
		}
	}
 
}
http://rghost ru/7bggH6Bp7 - Флешка
Старый 31.03.2015 20:46 dimarik вне форума
dimarik
 
Аватар для dimarik
Да, там немного неоптимизировано. Поинты каждый раз заново создаются через Point#polar(), так же можно избежать рисовать отдельными заливками. Но это я оставлю вам в качестве домашнего задания. Сразу отвечу на вопрос, что я останусь при своем мнении. Прошу меня больше с этой темой не беспокоить.
Старый 08.04.2015 17:46 dark256 вне форума
dark256
 
Аватар для dark256
Я и не подозревал, что нынче о такой фигне блоги пишут
Лет 7 назад написано на curveTo. От построения отрезками я, разумеется, отказался из сображений производительности.

http://188.226.221.96/SOUNDSTAGE/drawSectors.swf
Старый 08.04.2015 18:11 ZackMercury вне форума
ZackMercury
 
Аватар для ZackMercury
dark256, ну а шо, вдруг кому-то пригодится с:
А зачем в градусах? Радианы же удобней и для формул и для восприятия...
К тому же, новичку трудно оптимизировать, когда у него нет большого опыта за спиной.
Кстати, спасибо за код, я всё ломал голову над контрольной точкой в curveTo, не получалось установить её в нужное место х)
Старый 08.04.2015 19:20 dark256 вне форума
dark256
 
Аватар для dark256
Мне вот градусы для восприятия как-то вот в разы удобнее
Код - декомпильнул чтоли?
Старый 20.04.2015 17:11 Wolsh вне форума
Wolsh
 
Аватар для Wolsh
 

 


Часовой пояс GMT +4, время: 00:20.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.