Hi guys,I was trying to adjust the labels font for a set of pie charts that I need to include on my application (ie. reduce or increase the size and use different font styles), but I didn't find a direct way to do it, so I solved the problem adding a setLabelsFont function (with the corresponding labelsFont function) to the WPieChart class.
The setLabelsFont function just set a WPieChart class's private data member (WFont *labelsFont_). At WPieChart construction time, lablesFont_ is initialized to 0 (nullptr). Finally I added the following lines to paintEvent function:
if (labelsFont_) painter.setFont(*labelsFont_);Is there a direct way to set the label font for a WPieChart object? I have attached the modified WPieChart.c and WPieChart source files.
Thanks. Regards. ________________________ Mario Diethelm Guallar
/* * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium. * * See the LICENSE file for terms of use. */ #include <cmath> #include <cstdio> #include "Wt/Chart/WPieChart" #include "Wt/Chart/WStandardPalette" #include "Wt/WAbstractItemModel" #include "Wt/WContainerWidget" #include "Wt/WCssDecorationStyle" #include "Wt/WText" #include "Wt/WPainter" #include "Wt/WPolygonArea" #include "Wt/WApplication" #include "Wt/WEnvironment" #include "Wt/WException" #include "WebUtils.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace Wt { namespace Chart { WPieChart::PieData::PieData() : customBrush(false), explode(0) { } WPieChart::WPieChart(WContainerWidget *parent) : WAbstractChart(parent), labelsColumn_(-1), dataColumn_(-1), height_(0.0), startAngle_(45), avoidLabelRendering_(0.0), labelOptions_(0), shadow_(false), labelsFont_(nullptr), labelFormat_(WString::fromUTF8("%.3g%%")) { setPalette(new WStandardPalette(WStandardPalette::Neutral)); setPlotAreaPadding(5); } void WPieChart::setLabelsColumn(int modelColumn) { if (labelsColumn_ != modelColumn) { labelsColumn_ = modelColumn; update(); } } void WPieChart::setLabelFormat(const WString& format) { labelFormat_ = format; update(); } WString WPieChart::labelFormat() const { return labelFormat_; } void WPieChart::setDataColumn(int modelColumn) { if (dataColumn_ != modelColumn) { dataColumn_ = modelColumn; update(); } } void WPieChart::setBrush(int modelRow, const WBrush& brush) { pie_[modelRow].customBrush = true; pie_[modelRow].brush = brush; update(); } WBrush WPieChart::brush(int modelRow) const { if (pie_[modelRow].customBrush) return pie_[modelRow].brush; else return palette()->brush(modelRow); } void WPieChart::setExplode(int modelRow, double factor) { pie_[modelRow].explode = factor; update(); } double WPieChart::explode(int modelRow) const { return pie_[modelRow].explode; } void WPieChart::setPerspectiveEnabled(bool enabled, double height) { if ((!enabled && height_ != 0.0) || height_ != height) { height_ = enabled ? height : 0.0; update(); } } void WPieChart::setShadowEnabled(bool enabled) { if (shadow_ != enabled) { shadow_ = enabled; update(); } } void WPieChart::setStartAngle(double startAngle) { if (startAngle_ != startAngle) { startAngle_ = startAngle; update(); } } void WPieChart::setAvoidLabelRendering(double avoidLabelRendering) { if (avoidLabelRendering_ != avoidLabelRendering) { avoidLabelRendering_ = avoidLabelRendering; update(); } } void WPieChart::setDisplayLabels(WFlags<LabelOption> options) { labelOptions_ = options; update(); } WWidget* WPieChart::createLegendItemWidget(int index, WFlags<LabelOption> options) { WContainerWidget* legendItem = new WContainerWidget(); legendItem->setPadding(4); WText* colorText = new WText(); legendItem->addWidget(colorText); colorText->setPadding(10, Left | Right); colorText->decorationStyle().setBackgroundColor(brush(index).color()); if (WApplication::instance()->environment().agentIsIE()) colorText->setAttributeValue("style", "zoom: 1;"); double total = 0; if (dataColumn_ != -1) for (int i = 0; i < model()->rowCount(); ++i) { double v = asNumber(model()->data(i, dataColumn_)); if (!Utils::isNaN(v)) total += v; } double value = asNumber(model()->data(index, dataColumn_)); if (!Utils::isNaN(value)) { WString label = labelText(index, value, total, options); if (!label.empty()) { WText* l = new WText(label); l->setPadding(5, Left); l->setToolTip(asString(model()->data(index, dataColumn_, ToolTipRole))); legendItem->addWidget(l); } } return legendItem; } void WPieChart::paint(WPainter& painter, const WRectF& rectangle) const { double total = 0; if (dataColumn_ != -1) for (int i = 0; i < model()->rowCount(); ++i) { double v = asNumber(model()->data(i, dataColumn_)); if (!Utils::isNaN(v)) total += v; } if (!painter.isActive()) throw WException("WPieChart::paint(): painter is not active."); WRectF rect = rectangle; if (rect.isNull() || rect.isEmpty()) rect = painter.window(); rect.setX(rect.x() + plotAreaPadding(Left)); rect.setY(rect.y() + plotAreaPadding(Top)); rect.setWidth(rect.width() - plotAreaPadding(Left) - plotAreaPadding(Right)); rect.setHeight(rect.height() - plotAreaPadding(Top) - plotAreaPadding(Bottom)); double side = std::min(rect.width(), rect.height()); painter.save(); painter.translate(rect.left() + (rect.width() - side)/2, rect.top() + (rect.height() - side)/2); if (!title().empty()) painter.translate(0, 15); double cx = std::floor(side/2) + 0.5; double cy = cx; double r = (int)(side/2 + 0.5); double h = height_ * r; painter.save(); if (h > 0.0) { painter.translate(0, r/2 - h/4); painter.scale(1, 0.5); } drawPie(painter, cx, cy, r, h, total); painter.restore(); painter.translate(0, -h/4); if (labelOptions_) { if (total != 0) { double currentAngle = startAngle_; for (int i = 0; i < model()->rowCount(); ++i) { double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double spanAngle = -v / total * 360; double midAngle = currentAngle + spanAngle / 2.0; double endAngle = currentAngle + spanAngle; if (endAngle < 0) endAngle += 360; if (midAngle < 0) midAngle += 360; double width = 200; double height = 30; double left; double top; double f; if (labelOptions_ & Outside) f = pie_[i].explode + 1.1; else f = pie_[i].explode + 0.7; double px = cx + f * r * std::cos(-midAngle / 180.0 * M_PI); double py = cy + f * r * std::sin(-midAngle / 180.0 * M_PI) * (h > 0 ? 0.5 : 1); WFlags<AlignmentFlag> alignment; WColor c = painter.pen().color(); if (labelOptions_ & Outside) { if (midAngle < 90) { left = px; top = py - height; alignment = AlignLeft | AlignBottom; } else if (midAngle < 180) { left = px - width; top = py - height; alignment = AlignRight | AlignBottom; } else if (midAngle < 270) { left = px - width; top = py + h/2; alignment = AlignRight | AlignTop; } else { left = px; top = py + h/2; alignment = AlignLeft | AlignTop; } } else { left = px - width/2; top = py - height/2; alignment = AlignCenter | AlignMiddle; c = palette()->fontColor(i); } if ((v / total * 100) >= avoidLabelRendering_) { painter.setPen(WPen(c)); painter.drawText(WRectF(left, top, width, height), alignment, labelText(i, v, total, labelOptions_)); } currentAngle = endAngle; } } } if (!title().empty()) { WFont oldFont = painter.font(); painter.setFont(titleFont()); painter.drawText(cx - 50, cy - r, 100, 50, AlignCenter | AlignTop, title()); painter.setFont(oldFont); } painter.restore(); } WString WPieChart::labelText(int index, double v, double total, WFlags<LabelOption> options) const { WString text; if (options & TextLabel) if (labelsColumn_ != -1) text += asString(model()->data(index, labelsColumn_)); if (options & TextPercentage) { std::string label; double u = v / total * 100; std::string format = labelFormat().toUTF8(); if (format.empty()) label = WLocale::currentLocale().toString(u).toUTF8() + "%"; else { #ifndef WT_TARGET_JAVA char buf[30]; #else char *buf = 0; #endif #ifdef WT_TARGET_JAVA buf = #endif // WT_TARGET_JAVA std::sprintf(buf, format.c_str(), u); label = buf; } if (!text.empty()) text += ": "; text += WString::fromUTF8(label); } return text; } void WPieChart::setShadow(WPainter& painter) const { painter.setShadow(WShadow(5, 15, WColor(0, 0, 0, 20), 40)); } void WPieChart::drawPie(WPainter& painter, double cx, double cy, double r, double h, double total) const { /* * Draw sides where applicable */ if (h > 0) { if (total == 0) { if (shadow_) setShadow(painter); drawOuter(painter, cx, cy, r, 0, -180, h); if (shadow_) painter.setShadow(WShadow()); } else { if (shadow_) { setShadow(painter); painter.setBrush(WBrush(black)); drawSlices(painter, cx, cy + h, r, total, true); painter.setShadow(WShadow()); } /* * Pre-processing: determine start and mid angles of each pie, * and get the index of the one that contains 90 degrees (which is * the one at the back */ #ifndef WT_TARGET_JAVA std::vector<double> startAngles(model()->rowCount()); std::vector<double> midAngles(model()->rowCount()); #else std::vector<double> startAngles, midAngles; startAngles.insert(startAngles.end(), model()->rowCount(), 0.0); midAngles.insert(midAngles.end(), model()->rowCount(), 0.0); #endif // WT_TARGET_JAVA int index90 = 0; double currentAngle = startAngle_; for (int i = 0; i < model()->rowCount(); ++i) { startAngles[i] = currentAngle; double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double spanAngle = -v / total * 360; midAngles[i] = currentAngle + spanAngle / 2.0; double endAngle = currentAngle + spanAngle; double to90 = currentAngle - 90; if (to90 < 0) to90 += 360; if (spanAngle <= -to90) index90 = i; if (endAngle < 0) endAngle += 360; currentAngle = endAngle; } /* * Draw clock wise side */ for (int j = 0; j < model()->rowCount(); ++j) { int i = (index90 + j) % model()->rowCount(); double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double midAngle = midAngles[i]; double endAngle = startAngles[(i + 1) % model()->rowCount()]; int n = nextIndex(i); bool visible = (endAngle <= 90) || (endAngle >= 270); bool drawS2 = visible && ((pie_[i].explode > 0.0) || (pie_[n].explode > 0.0)); if (drawS2) { double pcx = cx + r * pie_[i].explode * std::cos(-midAngle / 180.0 * M_PI); double pcy = cy + r * pie_[i].explode * std::sin(-midAngle / 180.0 * M_PI); painter.setBrush(darken(brush(i))); drawSide(painter, pcx, pcy, r, endAngle, h); } if (!visible) break; } /* * Draw counter-clock wise side */ for (int j = model()->rowCount(); j > 0; --j) { int i = (index90 + j) % model()->rowCount(); double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double startAngle = startAngles[i]; double midAngle = midAngles[i]; int p = prevIndex(i); bool visible = (startAngle >= 90) && (startAngle <= 270); bool drawS1 = visible && ((pie_[i].explode > 0.0) || (pie_[p].explode > 0.0)); if (drawS1) { double pcx = cx + r * pie_[i].explode * std::cos(-midAngle / 180.0 * M_PI); double pcy = cy + r * pie_[i].explode * std::sin(-midAngle / 180.0 * M_PI); painter.setBrush(darken(brush(i))); drawSide(painter, pcx, pcy, r, startAngle, h); } if (!visible) break; } /* * Outside */ for (int j = 0; j < model()->rowCount(); ++j) { int i = (index90 + j) % model()->rowCount(); double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double startAngle = startAngles[i]; double midAngle = midAngles[i]; double endAngle = startAngles[(i + 1) % model()->rowCount()]; double spanAngle = endAngle - startAngle; if (spanAngle > 0) spanAngle -= 360; bool drawBorder = startAngle > 180 || endAngle > 180 || spanAngle < -180 || model()->rowCount() == 1; if (drawBorder) { painter.setBrush(darken(brush(i))); double pcx = cx + r * pie_[i].explode * std::cos(-midAngle / 180.0 * M_PI); double pcy = cy + r * pie_[i].explode * std::sin(-midAngle / 180.0 * M_PI); double a1 = (startAngle < 180 ? 360 : startAngle); double a2 = (endAngle < 180 ? 180 : endAngle); drawOuter(painter, pcx, pcy, r, a1, a2, h); } } } } /* * Draw top */ if (total == 0) painter.drawArc(cx - r, cy - r, r*2, r*2, 0, 16*360); else drawSlices(painter, cx, cy, r, total, false); } void WPieChart::drawSlices(WPainter& painter, double cx, double cy, double r, double total, bool shadow) const { double currentAngle = startAngle_; for (int i = 0; i < model()->rowCount(); ++i) { double v = asNumber(model()->data(i, dataColumn_)); if (Utils::isNaN(v)) continue; double spanAngle = -v / total * 360; double midAngle = currentAngle + spanAngle / 2.0; double pcx = cx + r * pie_[i].explode * std::cos(-midAngle / 180.0 * M_PI); double pcy = cy + r * pie_[i].explode * std::sin(-midAngle / 180.0 * M_PI); if (!shadow) painter.setBrush(brush(i)); if (v/total != 1.0) painter.drawPie(pcx - r, pcy - r, r*2, r*2, static_cast<int>(currentAngle * 16), static_cast<int>(spanAngle * 16)); else painter.drawEllipse(pcx - r, pcy - r, r*2, r*2); /* * See if we need to add an interactive area */ if (!shadow) { WModelIndex index = model()->index(i, dataColumn_); boost::any toolTip = index.data(ToolTipRole); if (!toolTip.empty()) { const int SEGMENT_ANGLE = 20; WPolygonArea *area = new WPolygonArea(); WTransform t = painter.worldTransform(); area->addPoint(t.map(WPointF(pcx, pcy))); double sa = std::fabs(spanAngle); for (double d = 0; d < sa; d += SEGMENT_ANGLE) { double a; if (spanAngle < 0) a = currentAngle - d; else a = currentAngle + d; area->addPoint(t.map(WPointF(pcx + r * std::cos(-a / 180.0 * M_PI), pcy + r * std::sin(-a / 180.0 * M_PI)))); } double a = currentAngle + spanAngle; area->addPoint(t.map(WPointF(pcx + r * std::cos(-a / 180.0 * M_PI), pcy + r * std::sin(-a / 180.0 * M_PI)))); area->setToolTip(asString(toolTip)); addDataPointArea(index, area); } } double endAngle = currentAngle + spanAngle; if (endAngle < 0) endAngle += 360; currentAngle = endAngle; } } void WPieChart::addDataPointArea(const WModelIndex& index, WAbstractArea *area) const { (const_cast<WPieChart *>(this))->addArea(area); } WBrush WPieChart::darken(const WBrush& brush) { WBrush result = brush; WColor c = result.color(); c.setRgb(c.red() * 3/4, c.green() * 3/4, c.blue() * 3/4, c.alpha()); result.setColor(c); return result; } void WPieChart::drawSide(WPainter& painter, double pcx, double pcy, double r, double angle, double h) const { WPainterPath path; path.arcMoveTo(pcx - r, pcy - r, 2 * r, 2 * r, angle); path.lineTo(path.currentPosition().x(), path.currentPosition().y() + h); path.lineTo(pcx, pcy + h); path.lineTo(pcx, pcy); path.closeSubPath(); painter.drawPath(path); } void WPieChart::drawOuter(WPainter& painter, double pcx, double pcy, double r, double a1, double a2, double h) const { WPainterPath path; path.arcMoveTo(pcx - r, pcy - r, 2 * r, 2 * r, a1); path.lineTo(path.currentPosition().x(), path.currentPosition().y() + h); path.arcTo(pcx, pcy + h, r, a1, a2 - a1); path.arcTo(pcx, pcy, r, a2, a1 - a2); path.closeSubPath(); painter.drawPath(path); } void WPieChart::paintEvent(WPaintDevice *paintDevice) { while (!areas().empty()) delete areas().front(); WPainter painter(paintDevice); painter.setRenderHint(WPainter::Antialiasing, true); if (labelsFont_) painter.setFont(*labelsFont_); paint(painter); } int WPieChart::nextIndex(int i) const { int r = model()->rowCount(); for (int n = (i + 1) % r; n != i; ++n) { double v = asNumber(model()->data(n, dataColumn_)); if (!Utils::isNaN(v)) return n; } return i; } int WPieChart::prevIndex(int i) const { int r = model()->rowCount(); for (int p = i - 1; p != i; --p) { if (p < 0) p += r; double v = asNumber(model()->data(p, dataColumn_)); if (!Utils::isNaN(v)) return p; } return i; } void WPieChart::modelReset() { if (model()->rowCount() != (int)pie_.size()) modelChanged(); else update(); } void WPieChart::modelChanged() { pie_.clear(); pie_.insert(pie_.begin(), model()->rowCount(), PieData()); update(); } void WPieChart::modelColumnsInserted(const WModelIndex& parent, int start, int end) { if (labelsColumn_ >= start) labelsColumn_ += (end - start + 1); if (dataColumn_ >= start) dataColumn_ += (end - start + 1); } void WPieChart::modelColumnsRemoved(const WModelIndex& parent, int start, int end) { bool needUpdate = false; if (labelsColumn_ >= start) { if (labelsColumn_ <= end) { labelsColumn_ = -1; needUpdate = true; } else labelsColumn_ -= (end - start + 1); } if (dataColumn_ >= start) { if (dataColumn_ <= end) { dataColumn_ = -1; needUpdate = true; } else dataColumn_ -= (end - start + 1); } if (needUpdate) update(); } void WPieChart::modelRowsInserted(const WModelIndex& parent, int start, int end) { for (int i = start; i <= end; ++i) pie_.insert(pie_.begin() + i, PieData()); update(); } void WPieChart::modelRowsRemoved(const WModelIndex& parent, int start, int end) { for (int i = end; i >= start; --i) pie_.erase(pie_.begin() + i); update(); } void WPieChart::modelDataChanged(const WModelIndex& topLeft, const WModelIndex& bottomRight) { if ((labelsColumn_ >= topLeft.column() && labelsColumn_ <= bottomRight.column()) || (dataColumn_ >= topLeft.column() && dataColumn_ <= bottomRight.column())) update(); } void WPieChart::modelHeaderDataChanged(Orientation orientation, int start, int end) { if ((labelsColumn_ >= start && labelsColumn_ <= end) || (dataColumn_ >= start && dataColumn_ <= end)) update(); } } }
WPieChart
Description: Binary data
------------------------------------------------------------------------------ Monitor Your Dynamic Infrastructure at Any Scale With Datadog! Get real-time metrics from all of your servers, apps and tools in one place. SourceForge users - Click here to start your Free Trial of Datadog now! http://pubads.g.doubleclick.net/gampad/clk?id=241902991&iu=/4140
_______________________________________________ witty-interest mailing list witty-interest@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/witty-interest