Просмотр полной версии : диаграмма секторов
Решил сделать такую штучку ради интереса, с математикой не силен, поэтому рассуждал логически.
ВОобщем задача такая - на вход подается кол-во элементов ( секторов ) и их процентная ставка, от чего собственно зависит высота сектора ( это потом, не важно ) , - на выходе получаем диаграмму этих секторов, распределенных по кругу.
http://stackoverflow.com/questions/14164038/draw-a-diagram-like-this-one
По ссылке выше пример того, что хочу получить, только без черной сетки и всегда с дугой.
Вот собственно так начал решать эту задачку :
public function drawDiagram(sectors:int , radius:Number , values:Array, triangulate:Boolean = false):void
{
var diameter:Number = radius * 2;
var sectorMaxWidth:Number = 360 / sectors;
var angleRotation:Number = 360 / sectors;
var currentAngle:Number = angleRotation;
var arcHeight:Number = radius - Math.sqrt(Math.abs(((Math.pow(radius,2) - Math.pow(sectorMaxWidth / 2, 2)))));
var circle:Shape = new Shape();
circle.graphics.beginFill(0);
circle.graphics.drawCircle(0, 0, radius);
addChild(circle)
for (var i:int = 0; i < sectors; i++)
{
var firstSector:Shape = new Shape();
firstSector.graphics.beginFill(randomColor);
firstSector.graphics.lineStyle(1,0xFFFFFF)
firstSector.graphics.lineTo( -sectorMaxWidth , -radius + arcHeight);
firstSector.graphics.curveTo( 0, -radius - arcHeight, sectorMaxWidth, -radius + arcHeight);
firstSector.graphics.lineTo(0, 0);
firstSector.rotation = currentAngle;
addChild(firstSector);
currentAngle += angleRotation;
}
}
private function get randomColor():int
{
return Math.random()*0xFFFFFF;
}
Собственно получается лажа, не могу понять именно в чем косяк, arcHeight ( взял формулу с нета ). Остальное собственно своими невеликими силами.
То есть по итогу, сектора должны занимать весь круг...
1. С каких это пор curveTo стала рисовать дугу окружности?
2. Вы предлагаете нам самим писать тестовый проект, чтобы узнать, в чем именно у Вас "получается лажа"?
Simplifier
21.04.2013, 03:47
Формулы - полный бред на вид. Где ты их выкопал?
Вот, например, это: var sectorMaxWidth:Number = 360 / sectors; Ширину считают, поделив градусы на количество 0_о
Циферки можно менять/удалять/добавлять новые:
SectorDiagram.swf
drawDiagram.aspackage
{
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Sprite;
/**
* ...
* @author wolsh
*/
public function drawDiagram (container:DisplayObjectContainer, radius:Number, values:Array):void
{
var k:Number = radius / Math.max.apply(null, values);
var sectors:uint = values.length;
var sectorAngle:Number = 2 * Math.PI / sectors;
for (var i:uint = 0; i < sectors; i++)
{
var color:uint = 0x808080 + Math.random() * 0x404040;
var startAngle:Number = i * sectorAngle;
var sectorRadius:Number = values[i] * k;
var sector:Sprite = new Sprite();
container.addChild(sector);
// calculate fragments (18 gradians max at one step for cute round curve)
var frags:Number = Math.abs( Math.ceil(sectorAngle * 10 / Math.PI) );
if (sectorAngle < 0) frags += 1;
var fragAngle:Number = sectorAngle / frags;
// control points radius
var controlOutRadius:Number = sectorRadius / Math.cos( -fragAngle / 2);
// start drawings
var g:Graphics = sector.graphics;
g.lineStyle(1, 0xFFFFFF)
g.beginFill(color);
g.moveTo(0, 0);
var startX:Number = sectorRadius * Math.cos(startAngle);
var startY:Number = sectorRadius * Math.sin(startAngle);
g.lineTo(startX, startY);
// arc
for (var j:uint = 1; j < frags + 1; j++)
{
var aA:Number = startAngle + fragAngle * j;
var aX:Number = sectorRadius * Math.cos(aA);
var aY:Number = sectorRadius * Math.sin(aA);
var cA:Number = aA - fragAngle / 2;
var cX:Number = controlOutRadius * Math.cos(cA);
var cY:Number = controlOutRadius * Math.sin(cA);
g.curveTo(cX, cY, aX, aY);
}
g.lineTo(0, 0);
}
}
}
Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* ...
* @author wolsh
*/
public class Main extends Sprite
{
private var _txt:TextField;
private var _diagram:Sprite;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
_diagram = new Sprite();
addChild(_diagram);
_diagram.x = _diagram.y = 220;
var data:Array = [300, 250, 320, 115, 234, 52, 186, 256, 370];
drawDiagram(_diagram, 200, data);
_txt = new TextField();
_txt.defaultTextFormat = new TextFormat("Arial", 18, 0x808080);
_txt.wordWrap = true;
_txt.type = "input";
_txt.background = true;
_txt.backgroundColor = 0x505050;
addChild(_txt);
_txt.x = 440;
_txt.y = 180;
_txt.width = 310;
_txt.height = 100;
_txt.text = data.toString();
_txt.addEventListener(Event.CHANGE, handlerChange);
}
private function handlerChange(event:Event):void
{
var data:Array = _txt.text.split(',');
_diagram.removeChildren();
drawDiagram(_diagram, 200, data);
}
}
}
in4core, если у вас много свободного времени могу подкинуть задачку на тему Трансформ менеджеров.
На сцене есть три спрайта, вложенных друг в друга и так же на сцене есть трансформ менеджер. Требуется корректно драгать им каждый из трех спрайтов.
shaman4d
21.04.2013, 14:11
На что надеялся ТС ? Наверное на то что дадут ссылку на готовове решение....
Wolsh - круто, спасибо, все таки заинтересовала тебя задача. Но тебе видишь все понятно и просто, а я почитав код половину не понимаю. Если тебе не лень давай порассуждаем : какие реально данные нам нужны?
1. Ширина сектора ( расстояние между 2мя конечными точками )
2. Высота дуги сектора.
3. Угол поворота
Что имеем изначально : только радиус и кол-во секторов. Будем рассуждать в контексте , что все значения 1,1,1,1,1 , то есть получим круг.
И так если у нас есть радиус и кол-во, угол поворота каждого сектора 360 / numSectors . Думаю тут ошибок нет.
Ширина сектора ? - вот тут нам нужна формула , какая ?
http://www.mathopenref.com/arclength.html - вот что я вижу. Где C = 360 / numSectors. Но как я понимаю, здесь нужно переводить в другую систему измерения или нет?
Далее высота дуги http://www.mathopenref.com/arcradius.html так же формула, и видимо так же перевод в другую систему.
Что получается в итоге - 1 цикл, все данные инициализируются 1 раз до цикла. Я так вижу решение этой задачи, у тебя же получается в 10 раз больше данных , формул и т.п. Вообщем понятно, что любую задачу можно решить разными способами, мне хочется именно моим попробовать, вопрос лишь в том, что я не понимаю, и где не так рассуждаю, прошу пояснить, если не сложно!
Добавлено через 2 минуты
Babylon
Твоя задача давно решена, есть готовая библиотека TransformTool найдешь в нете, другой вопрос , что она очень косячная , и мне было оч тяжело переписывать ее под себя в одном из проектов, ну ниче справился
А то я про эти библиотеки ничего не знаю...
Что такое "ширина сектора"?
У сектора есть угол (в нашем случае тот же 360 / numSectors).
Есть две прямые линии — радиус сектора, и дуга этого радиуса.
Дуга это не любая кривая, и уж точно не кривая второго порядка, а часть окружности. Ее не нарисовать за один проход curveTo(). Будет.. кривая Кривая. Для 200-360 секторов это не будет заметно, но два будут выглядеть яйцами. Чтобы кривая была похожа на часть окружности, надо рисовать ее фрагментиками градусов по 15-30 (зависит от длины дуги конечно, но в среднем так). Поэтому угол сектора делится на фрагменты и во внутреннем цикле рисуются эти короткие кривые не более 18 градусов.
Нельзя посчитать "высоту дуги" один раз для всех секторов — она у всех разная, потому что радиус дуги разный (из values). Однако поскольку все фрагменты одного сектора имеют один радиус и одинаковый угол дуги, длина луча к контрольным точкам кривых тоже одинаковая и считается один раз для сектора.
Я не рисую все сектора "от ноля" с последующим поворотом спрайта. Мне так не нравится. Я рисую сектор там где он должен быть, поэтому первая точка дуги тоже ищется тригонометрически (можно через Point.polar()).
Для меня фраза "понятно, что любую задачу можно решить разными способами" приемлема только в том контексте, в котором задача действительно решается. Рисование окружности одним проходом curveTo извините, не решается никак. Какую бы "высоту дуги" Вы не посчитали.
Можно еще треугольные маски накладывать на красивые окружности от drawCircle(). Маску можно без дуги рисовать, обычный прямоугольный треугольник — посчитать проще, тем более если от нулевой оси.
не решается никак. Какую бы "высоту дуги" Вы не посчитали. Вот это видимо ключевая фраза, того, почему у меня не получалось все время. Однако не могу понять почему так, да если values разные - получается, как мы видим на рисунке разные дуги, но если все values одинаковые и образуют в итоге круг, то почему нельзя решить одним проходом? или можно? То есть когда я начинал решать задачу, мне стало непонятно именно это, ведь я сразу не стал лезть на values , а хотел получить круг из секторов
Simplifier
21.04.2013, 18:18
Дуга это не любая кривая, и уж точно не кривая второго порядка, а часть окружности
Ну, вообще-то, окружность (как и её часть) как раз таки самая что ни на есть кривая второго порядка=) Но выделить в явном виде многочлен от х не получится, да. Поэтому в целом curveTo() тут не подходит.
Рисование окружности одним проходом извините, не решается никак
Ну, если особая точность не требуется, а угловые меры дуг заведомо небольшие, то интерполяция дуги всего одним curveTo() может быть и сгодится, почему нет-то.
С другой стороны, in4core, тебе уже дали рабочее решение, бери и пользуйся, тем более что у самого справиться не выходит.
К чему этот пост о том, что было бы, если бы да кабы?
"Если бы флэшплеер рисовал кривую второго порядка, а не кривую Безье второго порядка"...
"Если бы было доподлинно известно, что секторов будет не меньше двадцати"...
Безье.
Неизвестно.
Для 200-360 секторов это не будет заметно, но два будут выглядеть яйцами. Чтобы кривая была похожа на часть окружности, надо рисовать ее фрагментиками градусов по 15-30 (зависит от длины дуги конечно, но в среднем так). Поэтому угол сектора делится на фрагменты и во внутреннем цикле рисуются эти короткие кривые не более 18 градусов.В 11 плеере есть cubicCurveTo (), им можно сразу 90 градусов рисовать.
Akopalipsis
23.09.2013, 18:30
Ну не смог я удержаться, простите - in4core вот Вы когда этот вопрос задавали, Вам не показалось, что Вы инвалид?
MikroAcse
23.09.2013, 18:34
Akopalipsis, это, как минимум, неприлично.
Если человек не понимает - почему он сразу инвалид?
Akopalipsis
23.09.2013, 18:39
MikroAcse - я полностью с Вами согласен. И я попросил прощения за свой дурной поступок.
http://flasher.ru/forum/showpost.php?p=1145711&postcount=6
Добавлено через 2 минуты
И я это к тому, что нельзя пришедшего за помощью человека на форум, называть "хоть как" .
MikroAcse
23.09.2013, 18:44
http://flasher.ru/forum/showpost.php?p=1145711&postcount=6
А, ну ясно теперь. Продолжайте без моего участия.
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.