1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 10cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h" 11cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 12cb93a386Sopenharmony_ci#include "samplecode/Sample.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci// Generates y values for the chart plots. 15cb93a386Sopenharmony_cistatic void gen_data(SkScalar yAvg, SkScalar ySpread, int count, SkTDArray<SkScalar>* dataPts) { 16cb93a386Sopenharmony_ci dataPts->setCount(count); 17cb93a386Sopenharmony_ci static SkRandom gRandom; 18cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 19cb93a386Sopenharmony_ci (*dataPts)[i] = gRandom.nextRangeScalar(yAvg - SkScalarHalf(ySpread), 20cb93a386Sopenharmony_ci yAvg + SkScalarHalf(ySpread)); 21cb93a386Sopenharmony_ci } 22cb93a386Sopenharmony_ci} 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci// Generates a path to stroke along the top of each plot and a fill path for the area below each 25cb93a386Sopenharmony_ci// plot. The fill path is bounded below by the bottomData plot points or a horizontal line at 26cb93a386Sopenharmony_ci// yBase if bottomData == nullptr. 27cb93a386Sopenharmony_ci// The plots are animated by rotating the data points by leftShift. 28cb93a386Sopenharmony_cistatic void gen_paths(const SkTDArray<SkScalar>& topData, 29cb93a386Sopenharmony_ci const SkTDArray<SkScalar>* bottomData, 30cb93a386Sopenharmony_ci SkScalar yBase, 31cb93a386Sopenharmony_ci SkScalar xLeft, SkScalar xDelta, 32cb93a386Sopenharmony_ci int leftShift, 33cb93a386Sopenharmony_ci SkPathBuilder* plot, SkPathBuilder* fill) { 34cb93a386Sopenharmony_ci plot->incReserve(topData.count()); 35cb93a386Sopenharmony_ci if (nullptr == bottomData) { 36cb93a386Sopenharmony_ci fill->incReserve(topData.count() + 2); 37cb93a386Sopenharmony_ci } else { 38cb93a386Sopenharmony_ci fill->incReserve(2 * topData.count()); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci leftShift %= topData.count(); 42cb93a386Sopenharmony_ci SkScalar x = xLeft; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci // Account for the leftShift using two loops 45cb93a386Sopenharmony_ci int shiftToEndCount = topData.count() - leftShift; 46cb93a386Sopenharmony_ci plot->moveTo(x, topData[leftShift]); 47cb93a386Sopenharmony_ci fill->moveTo(x, topData[leftShift]); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci for (int i = 1; i < shiftToEndCount; ++i) { 50cb93a386Sopenharmony_ci plot->lineTo(x, topData[i + leftShift]); 51cb93a386Sopenharmony_ci fill->lineTo(x, topData[i + leftShift]); 52cb93a386Sopenharmony_ci x += xDelta; 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci for (int i = 0; i < leftShift; ++i) { 56cb93a386Sopenharmony_ci plot->lineTo(x, topData[i]); 57cb93a386Sopenharmony_ci fill->lineTo(x, topData[i]); 58cb93a386Sopenharmony_ci x += xDelta; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci if (bottomData) { 62cb93a386Sopenharmony_ci SkASSERT(bottomData->count() == topData.count()); 63cb93a386Sopenharmony_ci // iterate backwards over the previous graph's data to generate the bottom of the filled 64cb93a386Sopenharmony_ci // area (and account for leftShift). 65cb93a386Sopenharmony_ci for (int i = 0; i < leftShift; ++i) { 66cb93a386Sopenharmony_ci x -= xDelta; 67cb93a386Sopenharmony_ci fill->lineTo(x, (*bottomData)[leftShift - 1 - i]); 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci for (int i = 0; i < shiftToEndCount; ++i) { 70cb93a386Sopenharmony_ci x -= xDelta; 71cb93a386Sopenharmony_ci fill->lineTo(x, (*bottomData)[bottomData->count() - 1 - i]); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci } else { 74cb93a386Sopenharmony_ci fill->lineTo(x - xDelta, yBase); 75cb93a386Sopenharmony_ci fill->lineTo(xLeft, yBase); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci} 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci// A set of scrolling line plots with the area between each plot filled. Stresses out GPU path 80cb93a386Sopenharmony_ci// filling 81cb93a386Sopenharmony_ciclass ChartView : public Sample { 82cb93a386Sopenharmony_ci inline static constexpr int kNumGraphs = 5; 83cb93a386Sopenharmony_ci inline static constexpr int kPixelsPerTick = 3; 84cb93a386Sopenharmony_ci inline static constexpr int kShiftPerFrame = 1; 85cb93a386Sopenharmony_ci int fShift = 0; 86cb93a386Sopenharmony_ci SkISize fSize = {-1, -1}; 87cb93a386Sopenharmony_ci SkTDArray<SkScalar> fData[kNumGraphs]; 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci SkString name() override { return SkString("Chart"); } 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 92cb93a386Sopenharmony_ci bool sizeChanged = false; 93cb93a386Sopenharmony_ci if (canvas->getBaseLayerSize() != fSize) { 94cb93a386Sopenharmony_ci fSize = canvas->getBaseLayerSize(); 95cb93a386Sopenharmony_ci sizeChanged = true; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci SkScalar ySpread = SkIntToScalar(fSize.fHeight / 20); 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci SkScalar height = SkIntToScalar(fSize.fHeight); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci if (sizeChanged) { 103cb93a386Sopenharmony_ci int dataPointCount = std::max(fSize.fWidth / kPixelsPerTick + 1, 2); 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci for (int i = 0; i < kNumGraphs; ++i) { 106cb93a386Sopenharmony_ci SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1); 107cb93a386Sopenharmony_ci fData[i].reset(); 108cb93a386Sopenharmony_ci gen_data(y, ySpread, dataPointCount, fData + i); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci canvas->clear(0xFFE0F0E0); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci static SkRandom colorRand; 115cb93a386Sopenharmony_ci static SkColor gColors[kNumGraphs] = { 0x0 }; 116cb93a386Sopenharmony_ci if (0 == gColors[0]) { 117cb93a386Sopenharmony_ci for (int i = 0; i < kNumGraphs; ++i) { 118cb93a386Sopenharmony_ci gColors[i] = colorRand.nextU() | 0xff000000; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci static const SkScalar kStrokeWidth = SkIntToScalar(2); 123cb93a386Sopenharmony_ci SkPaint plotPaint; 124cb93a386Sopenharmony_ci SkPaint fillPaint; 125cb93a386Sopenharmony_ci plotPaint.setAntiAlias(true); 126cb93a386Sopenharmony_ci plotPaint.setStyle(SkPaint::kStroke_Style); 127cb93a386Sopenharmony_ci plotPaint.setStrokeWidth(kStrokeWidth); 128cb93a386Sopenharmony_ci plotPaint.setStrokeCap(SkPaint::kRound_Cap); 129cb93a386Sopenharmony_ci plotPaint.setStrokeJoin(SkPaint::kRound_Join); 130cb93a386Sopenharmony_ci fillPaint.setAntiAlias(true); 131cb93a386Sopenharmony_ci fillPaint.setStyle(SkPaint::kFill_Style); 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci SkPathBuilder plotPath, fillPath; 134cb93a386Sopenharmony_ci SkTDArray<SkScalar>* prevData = nullptr; 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci for (int i = 0; i < kNumGraphs; ++i) { 137cb93a386Sopenharmony_ci gen_paths(fData[i], 138cb93a386Sopenharmony_ci prevData, 139cb93a386Sopenharmony_ci height, 140cb93a386Sopenharmony_ci 0, 141cb93a386Sopenharmony_ci SkIntToScalar(kPixelsPerTick), 142cb93a386Sopenharmony_ci fShift, 143cb93a386Sopenharmony_ci &plotPath, 144cb93a386Sopenharmony_ci &fillPath); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci // Make the fills partially transparent 147cb93a386Sopenharmony_ci fillPaint.setColor((gColors[i] & 0x00ffffff) | 0x80000000); 148cb93a386Sopenharmony_ci canvas->drawPath(fillPath.detach(), fillPaint); 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci plotPaint.setColor(gColors[i]); 151cb93a386Sopenharmony_ci canvas->drawPath(plotPath.detach(), plotPaint); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci prevData = fData + i; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci fShift += kShiftPerFrame; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci}; 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ciDEF_SAMPLE( return new ChartView(); ) 161