Напишите свой собственный. Это не легко, я сейчас делаю то же самое. Вот как я это делаю:
Во-первых, не обращайте внимания на все ваши желания использовать UIScrollView, если хотите разрешить масштабирование. Это совершенно не стоит.
Во-вторых, создайте что-то вроде GraphElement
протокола. У меня есть иерархия, которая выглядит примерно так:
- GraphElement
- GraphPathElement
- GraphDataElement
- GraphDataSupplierElement
GraphElement содержит основные необходимые методы для элемента графа, включая способ рисования, максимальную ширину (для увеличения), находится ли точка внутри этого элемента (для касаний) и стандарт touchBegan
, touchMoved
, и touchEnded
функций.
GraphPathElement
содержит CGPath
, цвет и ширину линии, цвет заливки и режим рисования. Всякий раз, когда ему предлагается нарисовать, он просто добавляет путь к контексту, устанавливает цвета и ширину линии и рисует путь с заданным режимом рисования.
GraphDataElement
в качестве подкласса GraphPathElement
принимает набор данных в координатах x-y, типе графика (столбец или линия), фрейм и границы. Кадр - это фактический размер созданного выходного CGPath. Границы - это размер данных во входных координатах. По сути, это позволяет масштабировать данные до размера экрана.
Он создает график, сначала вычисляя аффинное преобразование для преобразования границ в фрейм, затем он проходит по каждой точке и добавляет его в виде данных к пути, применяя это преобразование к точке перед добавлением. Способ добавления данных зависит от типа.
Если это гистограмма, она создает прямоугольник шириной 0 с началом координат (x, frame.size.height-y) и height = y. Затем он «вставляет» график на -3 пикселя по горизонтали и добавляет его к пути.
Если это линейный график, это намного проще. Он просто перемещается в первую точку, затем для каждой другой точки он добавляет линию к этой точке, добавляет круг в прямоугольнике вокруг этой точки, а затем возвращается в эту точку, чтобы перейти к следующей точке.
GraphDataSupplierElement
- это интерфейс к моей базе данных, который фактически содержит все данные. Он определяет, какой граф это должен быть, форматирует данные в требуемый тип для GraphDataElement
и передает их с цветом, используемым для этого конкретного графика.
Для меня ось X - это время, и она представлена как NSTimeInterval
с. GraphDataSupplierElement
содержит minDate
и maxDate
, так что GraphDateElement
может рисовать метки оси X, как требуется.
Как только все это будет сделано, вам нужно создать реальный график. Вы можете сделать это несколькими способами. Один из вариантов - сохранить все элементы в NSArray
и, когда вызывается drawRect:
, перебирать каждый элемент и рисовать его. Другой вариант - создать CALayer
для каждого элемента и использовать GraphPathElement
в качестве делегата CALayer
. Или вы можете сделать GraphPathElement
расширенным от CALayer
напрямую. Это зависит от вас. Я еще не пробовал CALayer
с, я все еще застрял в простой стадии NSArray
. В какой-то момент я могу перейти к CALayer
s, как только я буду удовлетворен тем, как все выглядит.
Итак, в общем, идея в том, что вы создаете график за один или несколько CGPath
с заранее и просто рисуете это, когда вам нужно нарисовать график, вместо того, чтобы пытаться фактически анализировать данные всякий раз, когда вы получаете drawRect:
звонок.
Масштабирование можно выполнить, сохранив исходные данные в GraphDataElement
, и просто измените кадр так, чтобы масштабирование границ до кадра создавало CGPath
шире экрана или любых других ваших потребностей. Я в основном заново реализовал свой собственный пинч-зум для моего подкласса Graph UIView
, который масштабируется только горизонтально, изменяя его преобразование, затем по завершении получая текущий кадр, сбрасывая преобразование в идентичность, устанавливая кадр в сохраненное значение, и установите рамку всех GraphElement
на новую рамку, чтобы они масштабировались. Тогда просто позвоните [self setNeedsDisplay]
чтобы нарисовать.
В любом случае, это немного бессмысленно, но это набросок того, как я это сделал. Если у вас есть более конкретные вопросы, не стесняйтесь комментировать.