updating chart pie package

main_design2.0
zaid_daoud 2 years ago
parent 9e2baae2e2
commit da7ec0b98e

@ -0,0 +1,58 @@
## [4.0.1]
* Fix README.md for broken images link
## [4.0.0] **Breaking**
* Wrap different parameters in chartValuesOptions, legendOptions
* Fix number of issues
## [3.1.1]
* Fix [#22](https://github.com/apgapg/pie_chart/issues/22) showLegends = false causes exception.
## [3.1.0]
* Add ring shape pie chart support
## [3.0.0] **Breaking**
* Migrate to AndroidX
* Add dark mode theme
* Remove color from default legendStyle to support dark mode
* Add enum LegendPosition to align chart legend **Breaking**
* Restructure whole project. Optimize code. Code Cleanup
Thanks [@xsahil03x](https://github.com/xsahil03x) for these changes
## [2.0.0]
* Fix padding, margin **Breaking**
* Fix error when parent is row
* Adapt to screen size **Breaking**
* Override chartRadius when screen is smaller compare to chartRadius **Breaking**
* Update example with macos and web support
## [1.3.0]
* Center text to sector center-line
* Add text labels
## [1.2.0]
* Merge [#12](https://github.com/apgapg/pie_chart/issues/12) Added option for showing decimal places in chart values. Thanks [@VB10](https://github.com/VB10) for PR
## [1.1.0]
* Merge [#11](https://github.com/apgapg/pie_chart/issues/11) Added option for changing initial angle of pie chart. Thanks [@mschneider](https://github.com/mschneider) for PR
## [1.0.0]
* Added [#8](https://github.com/apgapg/pie_chart/issues/8) Added option for showing chart values outside the pie chart [@guyzk](https://github.com/guyzk)
* Added [#7](https://github.com/apgapg/pie_chart/issues/7) Hide 0 values on pie chart. Thanks [@guyzk](https://github.com/https://github.com/guyzk)
* Added legend fontFamily support. Thanks [@MahdiPishguy](https://github.com/MahdiPishguy) for PR
## [0.9.0]
* Fixes [#5](https://github.com/apgapg/pie_chart/issues/5) Added custom colorlist optional parameter. Thanks [@SJente](https://github.com/SJente)
* Fixes [#3](https://github.com/apgapg/pie_chart/issues/3) Update PieChart when data changes. Thanks [@leehuwuj](https://github.com/https://github.com/leehuwuj)
* Fixes [#2](https://github.com/apgapg/pie_chart/issues/2) Added showLegends bool as optional Parameter. Thanks [@cuitao1988](https://github.com/https://github.com/cuitao1988)
* Fixes Exception when data length was greater than 5
* Added key to PieChart
## [0.8.0]
* Update README.md
* Format code
* Update min Dart SDK version
Thanks [@xsahil03x](https://github.com/xsahil03x) for this PR
## [0.7.0] - Initial Release

@ -0,0 +1,6 @@
library pie_chart;
export 'src/chart_values_options.dart';
export 'src/legend_options.dart';
export 'src/pie_chart.dart';
export 'src/utils.dart' hide defaultColorList;

@ -0,0 +1,153 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
class PieChartPainter extends CustomPainter {
List<Paint> _paintList = [];
List<double> _subParts;
List<String> _subTitles;
double _total = 0;
double _totalAngle = math.pi * 2;
final TextStyle chartValueStyle;
final Color chartValueBackgroundColor;
final double initialAngle;
final bool showValuesInPercentage;
final bool showChartValues;
final bool showChartValuesOutside;
final int decimalPlaces;
final bool showChartValueLabel;
final ChartType chartType;
final Function formatChartValues;
final double strokeWidth;
final bool selected;
final List<Color> colorList;
double _prevAngle = 0;
final TextStyle sideTextStyle;
PieChartPainter(
double angleFactor,
this.showChartValues,
this.showChartValuesOutside,
this.colorList, {
this.chartValueStyle,
this.chartValueBackgroundColor,
List<double> values,
List<String> titles,
this.initialAngle,
this.showValuesInPercentage,
this.decimalPlaces,
this.showChartValueLabel,
this.chartType,
this.formatChartValues,
this.strokeWidth,
this.selected = false,
this.sideTextStyle,
}) {
for (int i = 0; i < values.length; i++) {
final paint = Paint()..color = getColor(colorList, i);
if (chartType == ChartType.ring) {
paint.style = PaintingStyle.stroke;
paint.strokeWidth = strokeWidth;
}
_paintList.add(paint);
}
_totalAngle = angleFactor * math.pi * 2;
_subParts = values;
_subTitles = titles;
_total = values.fold(0, (v1, v2) => v1 + v2);
}
@override
void paint(Canvas canvas, Size size) {
final side = size.width < size.height ? size.width : size.height;
_prevAngle = this.initialAngle * math.pi / 180;
for (int i = 0; i < _subParts.length; i++) {
canvas.drawArc(
new Rect.fromLTWH(0.0, 0.0, side, size.height),
_prevAngle,
(((_totalAngle) / _total) * _subParts[i]),
chartType == ChartType.disc ? true : false,
_paintList[i],
);
if (selected)
canvas.drawArc(
new Rect.fromLTWH(-8, -8, side + 16, size.height + 16),
_prevAngle,
(((_totalAngle) / _total) * _subParts[i]),
chartType == ChartType.disc ? true : false,
_paintList[i]..color = _paintList[i].color.withOpacity(0.4),
);
final radius = showChartValuesOutside ? (side / 2) + 16 : side / 3;
final x = (radius) * math.cos(_prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2));
final y = (radius) * math.sin(_prevAngle + ((((_totalAngle) / _total) * _subParts[i]) / 2));
if (_subParts.elementAt(i).toInt() != 0) {
final value = formatChartValues != null ? formatChartValues(_subParts.elementAt(i)) : _subParts.elementAt(i).toStringAsFixed(this.decimalPlaces);
// final name = showValuesInPercentage
// ? (((_subParts.elementAt(i) / _total) * 100)
// .toStringAsFixed(this.decimalPlaces) +
// '%')
// : value;
// final name = showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : _subTitles.elementAt(i);
if (showChartValues) {
final name = _subTitles[i] + " " + (showValuesInPercentage ? (((_subParts.elementAt(i) / _total) * 100).toStringAsFixed(this.decimalPlaces) + '%') : value);
if (selected) _drawLabel(canvas, name, x, y - 30, side, true, statusColor: getColor(colorList, i));
_drawLabel(canvas, _subTitles[i], (y > 0 ? x - y : x * 1.7) - 32, y, side + 8, false);
}
}
_prevAngle = _prevAngle + (((_totalAngle) / _total) * _subParts[i]);
}
}
void _drawLabel(Canvas canvas, String name, double x, double y, double side, bool withBackground, {Color statusColor = Colors.white}) {
TextSpan span = TextSpan(
style: withBackground ? chartValueStyle : sideTextStyle,
text: name,
);
TextPainter tp = TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
tp.layout();
if (withBackground && showChartValueLabel) {
//Draw text background box
final rect = Rect.fromCenter(
center: Offset((side / 2 + (x + 16)), (side / 2 + y)),
width: tp.width + 45,
height: tp.height + 16,
);
final rect2 = Rect.fromCenter(
center: new Offset(
(side / 2 + x) - ((tp.width - 16) / 2),
(side / 2 + y) - ((tp.height - 16) / 2),
),
width: 12,
height: 12,
);
final rRect = RRect.fromRectAndRadius(rect, Radius.circular(8));
final rRect2 = RRect.fromRectAndRadius(rect2, Radius.circular(1));
final paint = Paint()
..color = chartValueBackgroundColor ?? Colors.grey[200]
..style = PaintingStyle.fill;
canvas.drawRRect(rRect, paint);
canvas.drawRRect(rRect2, paint..color = statusColor);
}
//Finally paint the text above box
tp.paint(
canvas,
new Offset(
(side / 2 + x) - ((tp.width - 50) / 2),
(side / 2 + y) - ((tp.height) / 2),
),
);
}
@override
bool shouldRepaint(PieChartPainter oldDelegate) => oldDelegate._totalAngle != _totalAngle || selected != oldDelegate.selected;
}

@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
import 'package:pie_chart/src/utils.dart';
class ChartValuesOptions {
final bool showChartValueBackground;
final int decimalPlaces;
final bool showChartValuesInPercentage;
final bool showChartValues;
final bool showChartValuesOutside;
final Color chartValueBackgroundColor;
final TextStyle chartValueStyle;
const ChartValuesOptions({
this.showChartValueBackground = true,
this.decimalPlaces = 1,
this.chartValueBackgroundColor,
this.showChartValuesInPercentage = false,
this.chartValueStyle = defaultChartValueStyle,
this.showChartValues = true,
this.showChartValuesOutside = false,
});
}

@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
class Legend extends StatelessWidget {
Legend({
@required this.title,
@required this.color,
@required this.style,
@required this.legendShape,
});
final String title;
final Color color;
final TextStyle style;
final BoxShape legendShape;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.symmetric(vertical: 2.0),
height: 20.0,
width: 18.0,
decoration: BoxDecoration(
shape: legendShape,
color: color,
),
),
SizedBox(
width: 8.0,
),
Flexible(
fit: FlexFit.loose,
child: Text(
title,
style: style,
softWrap: true,
),
),
SizedBox(
width: 8.0,
),
],
);
}
}

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
import 'package:pie_chart/src/utils.dart';
class LegendOptions {
final bool showLegends;
final bool showLegendsInRow;
final TextStyle legendTextStyle;
final BoxShape legendShape;
final LegendPosition legendPosition;
const LegendOptions({
this.showLegends = true,
this.showLegendsInRow = false,
this.legendTextStyle = defaultLegendStyle,
this.legendShape = BoxShape.circle,
this.legendPosition = LegendPosition.right,
});
}

@ -0,0 +1,260 @@
import 'package:flutter/material.dart';
import 'package:pie_chart/pie_chart.dart';
import 'chart_painter.dart';
import 'legend.dart';
import 'utils.dart';
enum LegendPosition { top, bottom, left, right }
enum ChartType { disc, ring }
class PieChart extends StatefulWidget {
PieChart({
@required this.dataMap,
this.chartType = ChartType.disc,
this.chartRadius,
this.animationDuration,
this.chartLegendSpacing = 48,
this.colorList = defaultColorList,
this.initialAngleInDegree = 0.0,
this.formatChartValues,
this.centerWidget,
this.ringStrokeWidth = 20.0,
this.legendOptions = const LegendOptions(),
this.chartValuesOptions = const ChartValuesOptions(),
this.sideTextStyle,
Key key,
}) : super(key: key);
final Map<String, double> dataMap;
final ChartType chartType;
final double chartRadius;
final Duration animationDuration;
final double chartLegendSpacing;
final List<Color> colorList;
final double initialAngleInDegree;
final Function formatChartValues;
final Widget centerWidget;
final double ringStrokeWidth;
final LegendOptions legendOptions;
final ChartValuesOptions chartValuesOptions;
final TextStyle sideTextStyle;
@override
_PieChartState createState() => _PieChartState();
}
class _PieChartState extends State<PieChart> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
double _animFraction = 0.0;
bool _selected = false;
List<String> legendTitles;
List<double> legendValues;
void initLegends() {
this.legendTitles = widget.dataMap.keys.toList(growable: false);
}
void initValues() {
this.legendValues = widget.dataMap.values.toList(growable: false);
}
void initData() {
assert(
widget.dataMap != null && widget.dataMap.isNotEmpty,
"dataMap passed to pie chart cant be null or empty",
);
initLegends();
initValues();
}
@override
void initState() {
super.initState();
initData();
controller = AnimationController(
duration: widget.animationDuration ?? Duration(milliseconds: 800),
vsync: this,
);
final Animation curve = CurvedAnimation(
parent: controller,
curve: Curves.decelerate,
);
animation = Tween<double>(begin: 0, end: 1).animate(curve)
..addListener(() {
setState(() {
_animFraction = animation.value;
});
});
controller.forward();
}
Widget _getChart() {
return Flexible(
child: Stack(
alignment: Alignment.center,
children: [
LayoutBuilder(
builder: (_, c) => Container(
height: widget.chartRadius != null
? c.maxWidth < widget.chartRadius
? c.maxWidth
: widget.chartRadius
: null,
child: InkWell(
onTap: () {
setState(() {
_selected = !_selected;
});
},
child: CustomPaint(
painter: PieChartPainter(
_animFraction,
widget.chartValuesOptions.showChartValues,
widget.chartValuesOptions.showChartValuesOutside,
widget.colorList,
chartValueStyle: widget.chartValuesOptions.chartValueStyle,
chartValueBackgroundColor: widget.chartValuesOptions.chartValueBackgroundColor,
values: legendValues,
titles: legendTitles,
initialAngle: widget.initialAngleInDegree,
showValuesInPercentage: widget.chartValuesOptions.showChartValuesInPercentage,
decimalPlaces: widget.chartValuesOptions.decimalPlaces,
showChartValueLabel: widget.chartValuesOptions.showChartValueBackground,
chartType: widget.chartType,
formatChartValues: widget.formatChartValues,
strokeWidth: widget.ringStrokeWidth,
selected: _selected,
sideTextStyle: widget.sideTextStyle,
),
child: AspectRatio(aspectRatio: 1),
),
),
),
),
if (widget.centerWidget != null) widget.centerWidget,
],
),
);
}
Widget _getPieChart() {
switch (widget.legendOptions.legendPosition) {
case LegendPosition.top:
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getLegend(
padding: EdgeInsets.only(
bottom: widget.chartLegendSpacing,
),
),
_getChart(),
],
);
case LegendPosition.bottom:
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getChart(),
_getLegend(
padding: EdgeInsets.only(
top: widget.chartLegendSpacing,
),
),
],
);
case LegendPosition.left:
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getLegend(
padding: EdgeInsets.only(
right: widget.chartLegendSpacing,
),
),
_getChart(),
],
);
case LegendPosition.right:
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getChart(),
_getLegend(
padding: EdgeInsets.only(
left: widget.chartLegendSpacing,
),
),
],
);
default:
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_getChart(),
_getLegend(
padding: EdgeInsets.only(
left: widget.chartLegendSpacing,
),
),
],
);
}
}
_getLegend({EdgeInsets padding}) {
if (widget.legendOptions.showLegends) {
return Padding(
padding: padding,
child: Wrap(
direction: widget.legendOptions.showLegendsInRow ? Axis.horizontal : Axis.vertical,
runSpacing: 8,
crossAxisAlignment: WrapCrossAlignment.start,
children: legendTitles
.map(
(item) => Legend(
title: item,
color: getColor(
widget.colorList,
legendTitles.indexOf(item),
),
style: widget.legendOptions.legendTextStyle,
legendShape: widget.legendOptions.legendShape,
),
)
.toList(),
),
);
} else
return SizedBox(
height: 0,
width: 0,
);
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8.0),
child: _getPieChart(),
);
}
@override
void didUpdateWidget(PieChart oldWidget) {
initData();
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
const defaultChartValueStyle = TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black,
);
const defaultLegendStyle = TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
);
const List<Color> defaultColorList = [
Color(0xFFff7675),
Color(0xFF74b9ff),
Color(0xFF55efc4),
Color(0xFFffeaa7),
Color(0xFFa29bfe),
Color(0xFFfd79a8),
Color(0xFFe17055),
Color(0xFF00b894),
];
Color getColor(List<Color> colorList, int index) {
if (index > (colorList.length - 1)) {
final newIndex = index % (colorList.length - 1);
return colorList.elementAt(newIndex);
}
return colorList.elementAt(index);
}

@ -0,0 +1,164 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
url: "https://pub.dev"
source: hosted
version: "2.10.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
url: "https://pub.dev"
source: hosted
version: "1.2.1"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
url: "https://pub.dev"
source: hosted
version: "1.17.0"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
js:
dependency: transitive
description:
name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
matcher:
dependency: transitive
description:
name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
url: "https://pub.dev"
source: hosted
version: "0.12.13"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
url: "https://pub.dev"
source: hosted
version: "0.2.0"
meta:
dependency: transitive
description:
name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
path:
dependency: transitive
description:
name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
url: "https://pub.dev"
source: hosted
version: "1.8.2"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
url: "https://pub.dev"
source: hosted
version: "1.9.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
url: "https://pub.dev"
source: hosted
version: "1.11.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
url: "https://pub.dev"
source: hosted
version: "0.4.16"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
sdks:
dart: ">=2.18.0 <3.0.0"

@ -0,0 +1,51 @@
name: pie_chart
description: A Flutter package for creating beautiful Pie Charts with awesome animation.
version: 4.0.1
environment:
sdk: ">=2.2.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.io/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.io/custom-fonts/#from-packages

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="pie_chart" width="76" height="20" viewBox="0 0 76 20"><defs><clipPath id="clip-path"><rect id="Rectangle_1" width="76" height="20" fill="#fff" data-name="Rectangle 1" rx="3"/></clipPath><linearGradient id="linear-gradient" x2="0" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#bbb" stop-opacity=".102"/><stop offset="1" stop-opacity=".102"/></linearGradient></defs><g id="Group_1" clip-path="url(#clip-path)" data-name="Group 1"><path id="Path_1" fill="#555" d="M0,0H31V20H0Z" data-name="Path 1"/><path id="Path_2" fill="#007ec6" d="M31,0H76V20H31Z" data-name="Path 2"/><path id="Path_3" fill="url(#linear-gradient)" d="M0,0H76V20H0Z" data-name="Path 3"/></g><g id="Group_2" data-name="Group 2"><text id="pub" fill="rgba(1,1,1,0.3)" font-family="Helvetica" font-size="11" transform="translate(16.5 15)"><tspan x="-9.177" y="0">pub</tspan></text><text id="pub-2" fill="#fff" data-name="pub" font-family="Helvetica" font-size="11" transform="translate(16.5 14)"><tspan x="-9.177" y="0">pub</tspan></text><text id="v0.1.0" fill="#fff" font-family="Helvetica" font-size="11" transform="translate(52.5 14)"><tspan x="-14.983" y="0">v0.3.0</tspan></text></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Loading…
Cancel
Save