1

I'm currently working on a Flutter project and am facing challenges in creating a tooth selection UI with 32 teeth. The UI should be in a oval form, and each tooth needs to be selectable with an icon that changes color when selected.

I've attempted various approaches, including using Stack and Positioned, as well as exploring the Flutter Shape Maker website (https://fluttershapemaker.com/). However, I've encountered issues with teeth overlapping or not being positioned correctly.

similar idea is here in that link : https://codepen.io/johnstuif/pen/JdOXWa .

are there any alternative libraries or methods better suited for creating this type of UI?

For clarity, I have attached an image illustrating the desired UI :

I tried the code from https://fluttershapemaker.com/ so i used CustomPainter but it didnt work properly ! , this is the code :

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'dart:ui' as ui;
import '../widgets/testselectedteeth.dart';

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {

  @override
  Widget build(BuildContext context) {
    return Container(child: Center(
      child: Center(
        child: CustomPaint(
          size: Size(Get.width, (Get.width*1.2188841201716738).toDouble()), //You can Replace [WIDTH] with your desired width for Custom Paint and height will be calculated automatically
          painter: RPSCustomPainter(),
        )
      )
    ),
    );
  }
}

//Copy this CustomPainter code to the Bottom of the File
class RPSCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {

Paint paint_0_fill = Paint()..style=PaintingStyle.fill;
paint_0_fill.color = Color(0xffffffff).withOpacity(1.0);
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(0,0,size.width,size.height),bottomRight: Radius.circular(size.width*0.02432046),bottomLeft:  Radius.circular(size.width*0.02432046),topLeft:  Radius.circular(size.width*0.02432046),topRight:  Radius.circular(size.width*0.02432046)),paint_0_fill);

Paint paint_1_stroke = Paint()..style=PaintingStyle.stroke..strokeWidth=size.width*0.0007153076;
paint_1_stroke.color=Color(0xffdae1eb).withOpacity(1.0);
canvas.drawRRect(RRect.fromRectAndCorners(Rect.fromLTWH(size.width*0.0003576538,size.height*0.0002934272,size.width*0.9992847,size.height*0.9994131),bottomRight: Radius.circular(size.width*0.02396280),bottomLeft:  Radius.circular(size.width*0.02396280),topLeft:  Radius.circular(size.width*0.02396280),topRight:  Radius.circular(size.width*0.02396280)),paint_1_stroke);

Path path_2 = Path();
path_2.moveTo(size.width*0.05117506,size.height*0.05854166);
path_2.cubicTo(size.width*0.04289034,size.height*0.05854162,size.width*0.01769391,size.height*0.05709627,size.width*0.009796846,size.height*0.05244336);
path_2.lineTo(size.width*0.009789679,size.height*0.05243913);
path_2.lineTo(size.width*0.009782254,size.height*0.05243520);
path_2.cubicTo(size.width*0.008867504,size.height*0.05195051,size.width*0.006506474,size.height*0.05030248,size.width*0.004452697,size.height*0.04846885);
path_2.cubicTo(size.width*0.001838086,size.height*0.04613452,size.width*0.0004222647,size.height*0.04417941,size.width*0.0003578660,size.height*0.04281425);
path_2.cubicTo(size.width*0.0003319522,size.height*0.03979083,size.width*0.002672476,size.height*0.03561353,size.width*0.004737604,size.height*0.03192767);
path_2.cubicTo(size.width*0.005781582,size.height*0.03006436,size.width*0.006767662,size.height*0.02830438,size.width*0.007241825,size.height*0.02700950);
path_2.lineTo(size.width*0.007319335,size.height*0.02678887);
path_2.cubicTo(size.width*0.01149954,size.height*0.01487530,size.width*0.01566505,size.height*0.006847222,size.width*0.01904950,size.height*0.004181510);
path_2.cubicTo(size.width*0.02376568,size.height*0.0007554657,size.width*0.02894936,size.height*0.0002934321,size.width*0.03339841,size.height*0.0002934321);
path_2.cubicTo(size.width*0.03570410,size.height*0.0002934321,size.width*0.03810776,size.height*0.0004343241,size.width*0.04065255,size.height*0.0005834908);
path_2.cubicTo(size.width*0.04347474,size.height*0.0007489250,size.width*0.04639303,size.height*0.0009199814,size.width*0.04949589,size.height*0.0009199814);
path_2.cubicTo(size.width*0.05584766,size.height*0.0009199814,size.width*0.06164476,size.height*0.001623655,size.width*0.06672616,size.height*0.003011460);
path_2.cubicTo(size.width*0.07210879,size.height*0.004481531,size.width*0.07657636,size.height*0.006694723,size.width*0.08000476,size.height*0.009589536);
path_2.cubicTo(size.width*0.08567570,size.height*0.01437790,size.width*0.08840723,size.height*0.02090861,size.width*0.08812347,size.height*0.02900025);
path_2.cubicTo(size.width*0.08795212,size.height*0.03388650,size.width*0.08693743,size.height*0.03827536,size.width*0.08510760,size.height*0.04204490);
path_2.cubicTo(size.width*0.08334477,size.height*0.04567644,size.width*0.08080683,size.height*0.04877303,size.width*0.07756432,size.height*0.05124865);
path_2.cubicTo(size.width*0.07440765,size.height*0.05365873,size.width*0.07055773,size.height*0.05550105,size.width*0.06612150,size.height*0.05672445);
path_2.cubicTo(size.width*0.06174984,size.height*0.05793004,size.width*0.05678756,size.height*0.05854133,size.width*0.05137254,size.height*0.05854133);
path_2.cubicTo(size.width*0.05130722,size.height*0.05854155,size.width*0.05124205,size.height*0.05854166,size.width*0.05117506,size.height*0.05854166);
path_2.close();

Paint paint_2_fill = Paint()..style=PaintingStyle.fill;
paint_2_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_2,paint_2_fill);

Path path_3 = Path();
path_3.moveTo(size.width*0.05117506,size.height*0.05883509);
path_3.lineTo(size.width*0.05117506,size.height*0.05824823);
path_3.cubicTo(size.width*0.05124152,size.height*0.05824823,size.width*0.05130619,size.height*0.05824813,size.width*0.05137254,size.height*0.05824790);
path_3.cubicTo(size.width*0.05674875,size.height*0.05824790,size.width*0.06167267,size.height*0.05764176,size.width*0.06600754,size.height*0.05644632);
path_3.cubicTo(size.width*0.07039522,size.height*0.05523631,size.width*0.07420151,size.height*0.05341529,size.width*0.07732067,size.height*0.05103385);
path_3.cubicTo(size.width*0.08052413,size.height*0.04858805,size.width*0.08303224,size.height*0.04552720,size.width*0.08477533,size.height*0.04193633);
path_3.cubicTo(size.width*0.08658962,size.height*0.03819880,size.width*0.08759582,size.height*0.03384363,size.width*0.08776597,size.height*0.02899181);
path_3.cubicTo(size.width*0.08804685,size.height*0.02098242,size.width*0.08534929,size.height*0.01452336,size.width*0.07974825,size.height*0.009794019);
path_3.cubicTo(size.width*0.07636018,size.height*0.006933256,size.width*0.07194091,size.height*0.004744934,size.width*0.06661320,size.height*0.003289864);
path_3.cubicTo(size.width*0.06156829,size.height*0.001912024,size.width*0.05580919,size.height*0.001213409,size.width*0.04949589,size.height*0.001213409);
path_3.cubicTo(size.width*0.04638026,size.height*0.001213409,size.width*0.04345552,size.height*0.001041965,size.width*0.04062706,size.height*0.0008761786);
path_3.cubicTo(size.width*0.03808881,size.height*0.0007273875,size.width*0.03569134,size.height*0.0005868593,size.width*0.03339841,size.height*0.0005868593);
path_3.cubicTo(size.width*0.03043328,size.height*0.0005868593,size.width*0.02806493,size.height*0.0008273992,size.width*0.02594504,size.height*0.001343843);
path_3.cubicTo(size.width*0.02346706,size.height*0.001947538,size.width*0.02129077,size.height*0.002946318,size.width*0.01929215,size.height*0.004397163);
path_3.cubicTo(size.width*0.01715795,size.height*0.006081325,size.width*0.01462593,size.height*0.01008079,size.width*0.01196878,size.height*0.01596501);
path_3.cubicTo(size.width*0.009818878,size.height*0.02072589,size.width*0.008196245,size.height*0.02535038,size.width*0.007663026,size.height*0.02687004);
path_3.lineTo(size.width*0.007584357,size.height*0.02709393);
path_3.cubicTo(size.width*0.007103041,size.height*0.02840837,size.width*0.006157461,size.height*0.03009605,size.width*0.005062569,size.height*0.03205022);
path_3.cubicTo(size.width*0.003115564,size.height*0.03552526,size.width*0.0006929543,size.height*0.03984942,size.width*0.0007154826,size.height*0.04280757);
path_3.cubicTo(size.width*0.0007790998,size.height*0.04408385,size.width*0.002199298,size.height*0.04602336,size.width*0.004716045,size.height*0.04827032);
path_3.cubicTo(size.width*0.006918534,size.height*0.05023672,size.width*0.009228849,size.height*0.05179267,size.width*0.009976302,size.height*0.05218871);
path_3.lineTo(size.width*0.01000547,size.height*0.05220503);
path_3.cubicTo(size.width*0.01340772,size.height*0.05420962,size.width*0.02059806,size.height*0.05586476,size.width*0.03079918,size.height*0.05699152);
path_3.cubicTo(size.width*0.03979848,size.height*0.05798554,size.width*0.04806258,size.height*0.05824822,size.width*0.05117506,size.height*0.05824823);
path_3.lineTo(size.width*0.05117506,size.height*0.05883509);
path_3.moveTo(size.width*0.05117506,size.height*0.05883509);
path_3.cubicTo(size.width*0.04382050,size.height*0.05883506,size.width*0.01780169,size.height*0.05752104,size.width*0.009588220,size.height*0.05268169);
path_3.cubicTo(size.width*0.007822196,size.height*0.05174594,size.width*0.0001532267,size.height*0.04619955,size.width*2.653126e-7,size.height*0.04282104);
path_3.cubicTo(size.width*-0.00004359735,size.height*0.03812524,size.width*0.005534400,size.height*0.03065252,size.width*0.006899293,size.height*0.02692508);
path_3.cubicTo(size.width*0.007755115,size.height*0.02449403,size.width*0.01334569,size.height*0.008259782,size.width*0.01880710,size.height*0.003965674);
path_3.cubicTo(size.width*0.02721102,size.height*-0.002143621,size.width*0.03709277,size.height*0.0006265542,size.width*0.04949589,size.height*0.0006265542);
path_3.cubicTo(size.width*0.07121770,size.height*0.0006265424,size.width*0.08918626,size.height*0.008897387,size.width*0.08848098,size.height*0.02900869);
path_3.cubicTo(size.width*0.08777570,size.height*0.04911998,size.width*0.07309436,size.height*0.05883476,size.width*0.05137254,size.height*0.05883476);
path_3.cubicTo(size.width*0.05130821,size.height*0.05883498,size.width*0.05124256,size.height*0.05883509,size.width*0.05117506,size.height*0.05883509);
path_3.close();

Paint paint_3_fill = Paint()..style=PaintingStyle.fill;
paint_3_fill.color = Color(0xff000000).withOpacity(1.0);
canvas.drawPath(path_3,paint_3_fill);

Path path_4 = Path();
path_4.moveTo(size.width*0.03568493,size.height*0.04873402);
path_4.cubicTo(size.width*0.02072166,size.height*0.04873402,size.width*0.01151754,size.height*0.03570276,size.width*0.005170671,size.height*0.02434997);
path_4.lineTo(size.width*0.004823818,size.height*0.02373040);
path_4.cubicTo(size.width*0.003182287,size.height*0.02080017,size.width*0.001631801,size.height*0.01803243,size.width*0.0008590400,size.height*0.01546018);
path_4.cubicTo(size.width*0.000004848288,size.height*0.01261681,size.width*0.0002322589,size.height*0.01043470,size.width*0.001574762,size.height*0.008592940);
path_4.cubicTo(size.width*0.003154362,size.height*0.006425897,size.width*0.006308110,size.height*0.004736918,size.width*0.01121624,size.height*0.003429501);
path_4.cubicTo(size.width*0.01671309,size.height*0.001965264,size.width*0.02429247,size.height*0.001003304,size.width*0.03438748,size.height*0.0004886674);
path_4.cubicTo(size.width*0.03692873,size.height*0.0003591134,size.width*0.03934453,size.height*0.0002934326,size.width*0.04156781,size.height*0.0002934326);
path_4.cubicTo(size.width*0.04778265,size.height*0.0002934326,size.width*0.05284011,size.height*0.0008076580,size.width*0.05659971,size.height*0.001821848);
path_4.cubicTo(size.width*0.05992714,size.height*0.002719442,size.width*0.06234814,size.height*0.004041026,size.width*0.06379548,size.height*0.005749888);
path_4.cubicTo(size.width*0.06542783,size.height*0.007677165,size.width*0.06591496,size.height*0.01015898,size.width*0.06528473,size.height*0.01333719);
path_4.cubicTo(size.width*0.06472583,size.height*0.01615572,size.width*0.06341363,size.height*0.01904874,size.width*0.06214462,size.height*0.02184651);
path_4.cubicTo(size.width*0.06168499,size.height*0.02285985,size.width*0.06125084,size.height*0.02381701,size.width*0.06086682,size.height*0.02474123);
path_4.cubicTo(size.width*0.06066591,size.height*0.02522478,size.width*0.06046409,size.height*0.02571463,size.width*0.06026036,size.height*0.02620918);
path_4.cubicTo(size.width*0.05821921,size.height*0.03116374,size.width*0.05590575,size.height*0.03677935,size.width*0.05231088,size.height*0.04109529);
path_4.cubicTo(size.width*0.04822286,size.height*0.04600331,size.width*0.04307797,size.height*0.04849693,size.width*0.03658219,size.height*0.04871864);
path_4.cubicTo(size.width*0.03628326,size.height*0.04872884,size.width*0.03598139,size.height*0.04873402,size.width*0.03568493,size.height*0.04873402);
path_4.close();

Paint paint_4_fill = Paint()..style=PaintingStyle.fill;
paint_4_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_4,paint_4_fill);

// and more ...

Paint paint_78_fill = Paint()..style=PaintingStyle.fill;
paint_78_fill.color = Color(0xffa7a3dd).withOpacity(1.0);
canvas.drawPath(path_78,paint_78_fill);

Path path_79 = Path();
path_79.moveTo(size.width*0.05142241,size.height*0.06928314);
path_79.lineTo(size.width*0.05142241,size.height*0.06869628);
path_79.lineTo(size.width*0.05158066,size.height*0.06869601);
path_79.cubicTo(size.width*0.06223917,size.height*0.06869600,size.width*0.07315905,size.height*0.06529163,size.width*0.08154031,size.height*0.05935583);
path_79.cubicTo(size.width*0.08585187,size.height*0.05630230,size.width*0.08928567,size.height*0.05274150,size.width*0.09174637,size.height*0.04877238);
path_79.cubicTo(size.width*0.09437383,size.height*0.04453425,size.width*0.09579065,size.height*0.03997355,size.width*0.09595748,size.height*0.03521695);
path_79.cubicTo(size.width*0.09611638,size.height*0.03068593,size.width*0.09536793,size.height*0.02642978,size.width*0.09373296,size.height*0.02256674);
path_79.cubicTo(size.width*0.09209037,size.height*0.01868573,size.width*0.08960145,size.height*0.01531958,size.width*0.08633536,size.height*0.01256181);
path_79.cubicTo(size.width*0.08009148,size.height*0.007289672,size.width*0.07125378,size.height*0.004502981,size.width*0.06077768,size.height*0.004502981);
path_79.cubicTo(size.width*0.05726373,size.height*0.004502981,size.width*0.05353583,size.height*0.004817125,size.width*0.04969754,size.height*0.005436690);
path_79.lineTo(size.width*0.04962915,size.height*0.005447735);
path_79.lineTo(size.width*0.04955945,size.height*0.005447735);
path_79.cubicTo(size.width*0.04568095,size.height*0.005447746,size.width*0.04179133,size.height*0.004293475,size.width*0.03767331,size.height*0.003071444);
path_79.cubicTo(size.width*0.03355714,size.height*0.001849942,size.width*0.02930081,size.height*0.0005868547,size.width*0.02507984,size.height*0.0005868547);
path_79.cubicTo(size.width*0.02237299,size.height*0.0005868547,size.width*0.01992540,size.height*0.001100364,size.width*0.01759724,size.height*0.002156737);
path_79.cubicTo(size.width*0.01490188,size.height*0.003379713,size.width*0.01240780,size.height*0.005299856,size.width*0.009973057,size.height*0.008026382);
path_79.cubicTo(size.width*0.008193026,size.height*0.01015761,size.width*0.006870651,size.height*0.01231404,size.width*0.006042500,size.height*0.01443601);
path_79.cubicTo(size.width*0.005335761,size.height*0.01624691,size.width*0.004968465,size.height*0.01808864,size.width*0.004950826,size.height*0.01991002);
path_79.cubicTo(size.width*0.004918451,size.height*0.02325195,size.width*0.006042271,size.height*0.02596329,size.width*0.006862843,size.height*0.02794302);
path_79.cubicTo(size.width*0.007483473,size.height*0.02944034,size.width*0.007931885,size.height*0.03052218,size.width*0.007650225,size.height*0.03132227);
path_79.lineTo(size.width*0.007648065,size.height*0.03132828);
path_79.cubicTo(size.width*0.007166749,size.height*0.03264275,size.width*0.006221155,size.height*0.03433045,size.width*0.005126248,size.height*0.03628465);
path_79.cubicTo(size.width*0.003177235,size.height*0.03976328,size.width*0.0007516270,size.height*0.04409255,size.width*0.0007792665,size.height*0.04705091);
path_79.lineTo(size.width*0.0007795956,size.height*0.04708717);
path_79.lineTo(size.width*0.0007744883,size.height*0.04712319);
path_79.cubicTo(size.width*0.0003597386,size.height*0.05004961,size.width*0.002127693,size.height*0.05311405,size.width*0.006029224,size.height*0.05623139);
path_79.cubicTo(size.width*0.009229667,size.height*0.05878855,size.width*0.01296161,size.height*0.06064540,size.width*0.01455522,size.height*0.06143830);
path_79.cubicTo(size.width*0.01481524,size.height*0.06156767,size.width*0.01502182,size.height*0.06167046,size.width*0.01516382,size.height*0.06174541);
path_79.cubicTo(size.width*0.02107513,size.height*0.06466784,size.width*0.02902164,size.height*0.06633468,size.width*0.03464872,size.height*0.06721869);
path_79.cubicTo(size.width*0.04159077,size.height*0.06830926,size.width*0.04802332,size.height*0.06869625,size.width*0.05142241,size.height*0.06869628);
path_79.lineTo(size.width*0.05142241,size.height*0.06928314);
path_79.moveTo(size.width*0.05142241,size.height*0.06928313);
path_79.cubicTo(size.width*0.04423216,size.height*0.06928308,size.width*0.02573646,size.height*0.06766158,size.width*0.01478529,size.height*0.06224344);
path_79.cubicTo(size.width*0.01301927,size.height*0.06130769,size.width*-0.001061721,size.height*0.05499817,size.width*0.00006397323,size.height*0.04705541);
path_79.cubicTo(size.width*0.00002011057,size.height*0.04235960,size.width*0.005598122,size.height*0.03488689,size.width*0.006963001,size.height*0.03115943);
path_79.cubicTo(size.width*0.007818823,size.height*0.02872839,size.width*-0.001106299,size.height*0.02024555,size.width*0.009389366,size.height*0.007687031);
path_79.cubicTo(size.width*0.02318283,size.height*-0.007768565,size.width*0.03715639,size.height*0.004860892,size.width*0.04955945,size.height*0.004860880);
path_79.cubicTo(size.width*0.08028566,size.height*-0.00009890341,size.width*0.09737776,size.height*0.01512252,size.width*0.09667248,size.height*0.03523383);
path_79.cubicTo(size.width*0.09596716,size.height*0.05534512,size.width*0.07330239,size.height*0.06928284,size.width*0.05158066,size.height*0.06928286);
path_79.cubicTo(size.width*0.05152842,size.height*0.06928304,size.width*0.05147591,size.height*0.06928313,size.width*0.05142241,size.height*0.06928313);
path_79.close();

Paint paint_79_fill = Paint()..style=PaintingStyle.fill;
paint_79_fill.color = Color(0xff000000).withOpacity(1.0);
canvas.drawPath(path_79,paint_79_fill);

}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

4

4 Answers 4

3

i have simplified your svg file, add it to assets/teeth.svg:

<svg id="svg68" version="1.1" viewBox="0 0 450 750" xmlns="http://www.w3.org/2000/svg">
 <path id="7" d="m205 74c-10 1.1-18-9.3-23-18l-0.3-0.5c-1.4-2.4-2.7-4.6-3.5-6.7-0.85-2.3-0.88-4.2-0.11-5.9 0.9-2 2.9-3.6 6.2-5.1 3.7-1.6 8.9-3 16-4.2a82 82 0 0 1 5-0.69c4.3-0.46 7.9-0.39 11 0.2 2.4 0.52 4.2 1.5 5.4 2.8 1.3 1.5 1.9 3.6 1.7 6.3-0.14 2.4-0.79 5-1.4 7.4-0.23 0.89-0.45 1.7-0.63 2.5l-0.29 1.3c-0.98 4.3-2.1 9.3-4.2 13-2.4 4.5-5.8 6.9-10 7.6-0.21 0.03-0.42 0.057-0.62 0.079z" fill="#a7a3dd"/>
 <path id="8" d="m246 32h1e-3c1.5 0.16 3.2 0.4 5 0.69 7 1.2 12 2.5 16 4.2 3.3 1.5 5.3 3.1 6.2 5.1 0.77 1.7 0.73 3.5-0.12 5.9-0.77 2.1-2.1 4.4-3.5 6.7l-0.3 0.5c-5.4 9.2-13 20-23 18a15 15 0 0 1-0.62-0.079c-4.5-0.66-7.9-3.2-10-7.6-2.1-3.9-3.2-8.9-4.2-13l-0.29-1.3c-0.18-0.81-0.4-1.7-0.63-2.5-0.63-2.5-1.3-5-1.4-7.4-0.15-2.7 0.41-4.8 1.7-6.3 1.2-1.3 3-2.3 5.4-2.8 2.7-0.58 6.3-0.65 11-0.19z" fill="#a7a3dd"/>
 <path id="6" d="m168 82c-2.9 1.2-6.4 0.91-11-1-3.7-1.7-7.9-4.5-13-8.8-0.54-0.44-1.1-0.86-1.6-1.3-2-1.6-3.8-3-5-4.4-1.3-1.5-1.9-2.7-1.7-4 0.17-1.6 1.4-3.3 3.9-5.3 2.6-2.1 6.8-4.5 13-7.4a105 105 0 0 1 5.9-2.8c6.4-2.7 10-3.3 13-2 2.5 1.6 2.7 5.7 3 11 0.073 1.5 0.15 3 0.28 4.6 0.61 7.4 0.52 12-0.3 15-0.86 3.2-2.6 5.2-5.8 6.6l-0.04 0.017z" fill="#a7a3dd"/>
 <path id="9" d="m292 47h1e-3c1.8 0.75 3.8 1.7 5.9 2.8 5.8 2.9 9.9 5.4 13 7.4 2.5 1.9 3.7 3.7 3.9 5.3 0.14 1.3-0.41 2.5-1.7 4-1.2 1.4-3 2.8-5 4.4-0.51 0.41-1 0.83-1.6 1.3-5.3 4.3-9.5 7.1-13 8.8-4.3 1.9-7.8 2.3-11 1l-0.04-0.018c-3.2-1.4-4.9-3.3-5.8-6.6-0.82-3.1-0.91-7.3-0.3-15 0.13-1.6 0.21-3.1 0.28-4.6 0.26-5.3 0.47-9.4 3-11 2.2-1.4 6.2-0.77 13 2z" fill="#a7a3dd"/>
 <path id="5" d="m144 104c-0.09 0.084-0.19 0.17-0.29 0.24-1.2 0.9-2.9 1.5-5.1 1.8-2.2 0.33-4.9 0.3-7.7-0.086-6.4-0.88-13-3.5-19-7.5-2.2-1.6-4-3.4-5.2-5.4a13 13 0 0 1-1.8-5.8c-0.18-2.6 0.36-5.4 1.6-8 1.1-2.3 2.6-4.5 4.3-6.1 0.36-0.34 0.73-0.65 1.1-0.92 1.4-1.1 4.4-2.7 7.8-4 2.8-1.1 6.8-2.2 10-1.8h8e-3c2.5 0.26 4.4 1.4 5.8 3.6 1.3 2 2.1 4.4 2.9 6.8 0.19 0.58 0.36 1.1 0.55 1.7 0.52 1.5 1.1 3.1 1.7 4.7 1.6 4.3 3.2 8.8 3.9 12 0.83 4.1 0.48 6.9-1.1 8.3z" fill="#a7a3dd"/>
 <path id="10" d="m339 73c1.7 1.6 3.2 3.7 4.3 6.1 1.2 2.7 1.8 5.5 1.6 8a13 13 0 0 1-1.8 5.8c-1.2 2-2.9 3.8-5.2 5.4-5.6 3.9-12 6.6-19 7.5-2.8 0.38-5.4 0.41-7.7 0.086-2.2-0.32-3.9-0.96-5.1-1.8a4 4 0 0 1-0.29-0.24c-1.6-1.4-1.9-4.2-1.1-8.3 0.75-3.7 2.4-8.2 3.9-12a301 301 0 0 0 1.7-4.7c0.18-0.54 0.36-1.1 0.55-1.7 0.77-2.4 1.6-4.8 2.9-6.8 1.5-2.2 3.4-3.4 5.8-3.6h5e-3l4e-3 -1e-3c3.3-0.45 7.3 0.71 10 1.8 3.4 1.3 6.4 3 7.8 4 0.36 0.27 0.73 0.58 1.1 0.92z" fill="#a7a3dd"/>
 <path id="4" d="m118 135a6.3 6.3 0 0 1-0.3 0.28c-2.4 2.1-6.6 2.8-12 2-5.4-0.85-11-3.3-16-6.8-5.7-4.1-9.3-9.3-9.7-14-0.28-3.4 0.92-6.6 3.5-9.2a16 16 0 0 1 1.6-1.4c8.7-6.6 22-4.9 29 3.7a26 26 0 0 1 4.2 7 27 27 0 0 1 1.8 7.4c0.47 4.9-0.57 9.1-2.8 11z" fill="#a7a3dd"/>
 <path id="11" d="m367 107h1e-3c2.6 2.6 3.8 5.7 3.5 9.2-0.42 5-3.9 10-9.7 14-5 3.6-11 6-16 6.8-5.1 0.81-9.4 0.076-12-2a6.3 6.3 0 0 1-0.3-0.28c-2.2-2.2-3.3-6.5-2.8-11a27 27 0 0 1 1.8-7.4 26 26 0 0 1 4.2-7c7.4-8.7 21-10 29-3.7a16 16 0 0 1 1.6 1.4z" fill="#a7a3dd"/>
 <path id="3" d="m73 168a39 39 0 0 1-0.2-0.1c-3.9-1.9-7.1-4.1-9.5-6.5-2.3-2.3-3.8-4.7-4.6-7.2a13 13 0 0 1-0.52-5.8c0.24-1.9 0.89-3.8 1.9-5.7 2.2-4.1 6.2-6.9 11-8 2.6-0.56 5.3-0.64 8.1-0.23 3 0.42 6 1.4 9 2.8 0.71 0.34 1.4 0.72 2.1 1.1 3.2 1.8 6.1 3.9 8.5 6.2 2.4 2.2 4.3 4.5 5.7 6.8s2.2 4.6 2.5 6.8c0.29 2.2-0.014 4.3-0.9 6.2-0.62 1.3-1.6 2.5-2.9 3.6-1.3 1-2.9 1.9-4.8 2.5-3.5 1.2-7.6 1.7-12 1.3-4.7-0.38-9.4-1.7-14-3.8z" fill="#a7a3dd"/>
 <path id="12" d="m362 137 2e-3 -1e-3c3-1.5 6-2.4 9-2.8 2.8-0.4 5.6-0.32 8.1 0.24 5 1.1 9 3.9 11 8 1 1.9 1.7 3.8 1.9 5.7a13 13 0 0 1-0.52 5.8c-0.8 2.5-2.4 5-4.6 7.2-2.4 2.4-5.6 4.6-9.5 6.5l-0.2 0.1c-4.3 2.1-9.1 3.4-14 3.8-4.3 0.35-8.5-0.11-12-1.3-1.9-0.65-3.5-1.5-4.8-2.5s-2.3-2.2-2.9-3.6c-0.89-1.9-1.2-4-0.9-6.2 0.28-2.2 1.1-4.5 2.5-6.8s3.3-4.6 5.7-6.8 5.3-4.3 8.5-6.2a37 37 0 0 1 2.1-1.1z" fill="#a7a3dd"/>
 <path id="2" d="m72 229c-0.72 0-1.5-0.018-2.2-0.053-8.3-0.39-16-2.8-21-6.7-3-2.1-5.3-4.7-6.9-7.5-1.7-3.1-2.6-6.6-2.6-10 0-2.7 0.77-5.6 2-7.3 0.41-0.58 1-1.2 1.7-1.9 1.2-1.2 2.6-2.7 3.4-4.4 0.41-0.98 0.45-2.4 0.5-4 0.072-2.5 0.16-5.6 1.8-8.1l4e-3 -7e-3 4e-3 -6e-3c1.4-2.4 3.6-4.1 6.6-5.1 2.4-0.79 5.4-1.1 9.5-1.1 4.7 0.79 9 2.2 13 4.3 3.9 2 7.3 4.6 10 7.5 2.8 3 4.9 6.4 6.3 10a27 27 0 0 1 1.6 12c-1.3 16-8.7 23-23 23z" fill="#a7a3dd"/>
 <path id="13" d="m378 229c-15 0-22-7.3-23-23-0.33-4.1 0.2-8 1.6-12 1.3-3.7 3.4-7 6.3-10 2.8-3 6.2-5.5 10-7.5 4-2.1 8.4-3.5 13-4.3 4.1 1e-3 7.1 0.36 9.5 1.1 3 0.98 5.2 2.6 6.6 5.1l4e-3 6e-3 4e-3 7e-3c1.6 2.4 1.7 5.5 1.8 8.1 0.046 1.6 0.087 3 0.5 4 0.76 1.8 2.1 3.2 3.4 4.4 0.65 0.66 1.3 1.3 1.7 1.9 1.2 1.7 2 4.5 2 7.3 0 3.8-0.87 7.2-2.6 10-1.6 2.9-3.9 5.4-6.9 7.5-5.5 3.9-13 6.3-21 6.7-0.76 0.035-1.5 0.053-2.2 0.053z" fill="#a7a3dd"/>
 <path id="1" d="m39 279c-3-0.96-6.3-2.5-8.5-6.2-1.5-2.9-2.2-10-1.8-21l6e-3 -0.19c0.026-1.2-0.17-2.8-0.37-4.5-0.4-3.4-0.86-7.3-0.045-9.8 0.4-1.1 1.9-2.4 4.2-3.7 1.8-1 3.9-1.9 4.6-2.1l6e-3 -1e-3 6e-3 -2e-3c6.5-2.1 24 2.2 29 4l0.13 0.043c3.6 1.2 6.7 2.7 9.3 4.7s4.7 4.3 6.2 6.9c1.5 2.7 2.4 5.8 2.6 9.1 0.22 3.4-0.26 7.2-1.4 11-1.9 6.6-5.5 11-11 14-3 1.6-6.6 2.4-11 2.5-3.7 0.027-7.8-0.66-12-2l-0.24-0.078c-2-0.63-3.9-1.1-5.7-1.6-1.7-0.43-3.4-0.83-4.9-1.3z" fill="#a7a3dd"/>
 <path id="14" d="m386 236c5.5-1.8 23-6.1 29-4l6e-3 2e-3 6e-3 1e-3c0.74 0.2 2.7 1 4.6 2.1 2.4 1.3 3.8 2.6 4.2 3.7 0.81 2.4 0.36 6.3-0.045 9.8-0.2 1.7-0.4 3.4-0.37 4.5l7e-3 0.2c0.36 11-0.3 18-1.8 21-2.2 3.8-5.6 5.3-8.5 6.2-1.5 0.5-3.2 0.9-4.9 1.3-1.9 0.48-3.9 0.97-6 1.6-4.2 1.4-8.3 2.1-12 2-4-0.028-7.5-0.86-11-2.5-5-2.7-8.6-7.4-11-14-1.2-4-1.7-7.8-1.4-11 0.22-3.3 1.1-6.4 2.6-9.1 1.5-2.6 3.5-5 6.2-6.9 2.6-1.9 5.7-3.5 9.3-4.7l0.13-0.043z" fill="#a7a3dd"/>
 <path id="0" d="m30 344c-1.8-0.6-3.4-1.6-4.7-3-1.5-1.6-2.7-3.7-3.6-6.5-0.63-2.1-0.94-4.2-0.94-6.1a16 16 0 0 1 0.73-4.7c0.87-2.8 2.3-4.7 3.4-6.2 0.78-1 1.3-1.8 1.4-2.4 0.026-1.2-0.17-2.8-0.37-4.5-0.4-3.4-0.86-7.3-0.044-9.8l5e-3 -0.015 3e-3 -0.015c0.51-2.5 2.5-4.7 6-6.4 2.8-1.4 5.8-2.1 7.1-2.4 0.21-0.049 0.37-0.088 0.48-0.12 4.7-1.1 10-0.73 14-0.23 4.9 0.62 9.3 1.7 12 2.4l0.1 0.034c7.1 2.3 14 7.5 18 14 4.3 7.1 5.5 15 3.3 23-1.1 3.7-2.7 7-4.8 9.8s-4.7 5-7.6 6.6c-5.6 3-12 3.3-19 1-2.4-0.76-4.8-1.8-7.2-3.2l-0.021-0.012-0.023-7e-3c-2.5-0.82-5.4-0.73-8.4-0.63-3.1 0.1-6.3 0.21-9.1-0.72z" fill="#a7a3dd"/>
 <path id="15" d="m384 294c2.3-0.74 6.7-1.8 12-2.4 4-0.5 9.7-0.87 14 0.23 0.11 0.03 0.28 0.068 0.48 0.12 1.3 0.3 4.3 1 7.1 2.4 3.5 1.7 5.5 3.9 6 6.4l3e-3 0.015 5e-3 0.015c0.82 2.4 0.36 6.3-0.044 9.8-0.2 1.7-0.4 3.4-0.37 4.5 0.021 0.63 0.58 1.4 1.4 2.4 1.1 1.4 2.6 3.4 3.4 6.2 0.48 1.5 0.72 3.1 0.73 4.7 8e-3 1.9-0.31 4-0.94 6.1-0.91 2.8-2.1 4.9-3.6 6.5-1.3 1.4-2.8 2.4-4.7 3-2.8 0.93-6 0.82-9.1 0.72-3-0.1-5.9-0.2-8.4 0.63l-0.023 7e-3 -0.021 0.011c-2.4 1.3-4.8 2.4-7.2 3.2-7 2.3-14 1.9-19-1-2.9-1.5-5.5-3.8-7.6-6.6s-3.8-6.1-4.8-9.8c-2.2-7.6-1.1-16 3.3-23 4-6.7 10-12 18-14l0.1-0.034z" fill="#a7a3dd"/>
 <path id="31" d="m66 456c-2.3 0.74-6.7 1.8-12 2.4-4 0.5-9.7 0.87-14-0.23a21 21 0 0 0-0.48-0.12c-1.3-0.3-4.3-1-7.1-2.4-3.5-1.7-5.5-3.9-6-6.4l-3e-3 -0.015-5e-3 -0.015c-0.82-2.4-0.36-6.3 0.044-9.8 0.2-1.7 0.4-3.4 0.37-4.5-0.021-0.63-0.58-1.4-1.4-2.4-1.1-1.4-2.6-3.4-3.4-6.2a16 16 0 0 1-0.73-4.7c-8e-3 -1.9 0.31-4 0.94-6.1 0.91-2.8 2.1-4.9 3.6-6.5 1.3-1.4 2.8-2.4 4.7-3 2.8-0.93 6-0.82 9.1-0.72 3 0.1 5.9 0.2 8.4-0.63l0.023-7e-3 0.021-0.011c2.4-1.3 4.8-2.4 7.2-3.2 7-2.3 14-1.9 19 1 2.9 1.5 5.5 3.8 7.6 6.6s3.8 6.1 4.8 9.8c2.2 7.6 1.1 16-3.3 23-4 6.7-10 12-18 14l-0.1 0.034z" fill="#a7a3dd"/>
 <path id="16" d="m420 406c1.8 0.6 3.4 1.6 4.7 3 1.5 1.6 2.7 3.7 3.6 6.5 0.63 2.1 0.94 4.2 0.94 6.1a16 16 0 0 1-0.73 4.7c-0.87 2.8-2.3 4.7-3.4 6.2-0.78 1-1.3 1.8-1.4 2.4-0.026 1.2 0.17 2.8 0.37 4.5 0.4 3.4 0.86 7.3 0.044 9.8l-5e-3 0.015-3e-3 0.015c-0.51 2.5-2.5 4.7-6 6.4-2.8 1.4-5.8 2.1-7.1 2.4-0.21 0.049-0.37 0.088-0.48 0.12-4.7 1.1-10 0.73-14 0.23-4.9-0.62-9.3-1.7-12-2.4l-0.1-0.034c-7.1-2.3-14-7.5-18-14-4.3-7.1-5.5-15-3.3-23 1.1-3.7 2.7-7 4.8-9.8s4.7-5 7.6-6.6c5.6-3 12-3.3 19-1 2.4 0.76 4.8 1.8 7.2 3.2l0.021 0.012 0.023 7e-3c2.5 0.82 5.4 0.73 8.4 0.63 3.1-0.1 6.3-0.21 9.1 0.72z" fill="#a7a3dd"/>
 <path id="30" d="m66 515c-5.5 1.8-23 6.1-29 4l-7e-3 -2e-3 -6e-3 -1e-3c-0.74-0.2-2.7-1-4.6-2.1-2.4-1.3-3.8-2.6-4.2-3.7-0.81-2.4-0.36-6.3 0.045-9.8 0.2-1.7 0.4-3.4 0.37-4.5l-7e-3 -0.2c-0.36-11 0.3-18 1.8-21 2.2-3.8 5.6-5.3 8.5-6.2 1.5-0.5 3.2-0.9 4.9-1.3 1.9-0.48 3.9-0.97 6-1.6 4.2-1.4 8.3-2.1 12-2 4 0.028 7.5 0.86 11 2.5 5 2.7 8.6 7.4 11 14 1.2 4 1.7 7.8 1.4 11-0.22 3.3-1.1 6.4-2.6 9.1-1.5 2.6-3.5 5-6.2 6.9-2.6 1.9-5.7 3.5-9.3 4.7l-0.13 0.043z" fill="#a7a3dd"/>
 <path id="17" d="m411 471c3 0.96 6.3 2.5 8.5 6.2 1.5 2.9 2.2 10 1.8 21l-6e-3 0.19c-0.026 1.2 0.17 2.8 0.37 4.5 0.4 3.4 0.86 7.3 0.045 9.8-0.4 1.1-1.9 2.4-4.2 3.7-1.8 1-3.9 1.9-4.6 2.1l-6e-3 1e-3 -6e-3 2e-3c-6.5 2.1-24-2.2-29-4a32 32 0 0 1-0.13-0.043c-3.6-1.2-6.7-2.7-9.3-4.7s-4.7-4.3-6.2-6.9c-1.5-2.7-2.4-5.8-2.6-9.1-0.22-3.4 0.26-7.2 1.4-11 1.9-6.6 5.5-11 11-14 3-1.6 6.6-2.4 11-2.5 3.7-0.027 7.8 0.66 12 2l0.24 0.078c2 0.63 3.9 1.1 5.7 1.6 1.7 0.43 3.4 0.83 4.9 1.3z" fill="#a7a3dd"/>
 <path id="29" d="m65 578c-4.1-1e-3 -7.1-0.36-9.5-1.1-3-0.98-5.2-2.6-6.6-5.1l-4e-3 -7e-3 -4e-3 -6e-3c-1.6-2.4-1.7-5.5-1.8-8.1-0.047-1.6-0.087-3-0.5-4-0.76-1.8-2.1-3.2-3.4-4.4-0.65-0.66-1.3-1.3-1.7-1.9-1.2-1.7-2-4.5-2-7.3 0-3.8 0.87-7.2 2.6-10 1.6-2.9 3.9-5.4 6.9-7.5 5.5-3.9 13-6.3 21-6.7 0.76-0.035 1.5-0.053 2.2-0.053 15 0 22 7.3 23 23 0.34 4.1-0.2 8-1.6 12-1.3 3.7-3.5 7-6.3 10s-6.2 5.5-10 7.5c-4 2.1-8.4 3.5-13 4.3z" fill="#a7a3dd"/>
 <path id="18" d="m386 578c-4.7-0.79-9-2.2-13-4.3-3.9-2-7.3-4.6-10-7.5-2.8-3-4.9-6.4-6.3-10a27 27 0 0 1-1.6-12c1.3-16 8.7-23 23-23 0.72 0 1.5 0.018 2.2 0.053 8.3 0.39 16 2.8 21 6.7 3 2.1 5.3 4.7 6.9 7.5 1.7 3.1 2.6 6.6 2.6 10 0 2.7-0.77 5.6-2 7.3-0.41 0.58-1 1.2-1.7 1.9-1.2 1.2-2.6 2.7-3.4 4.4-0.41 0.98-0.45 2.4-0.5 4-0.072 2.5-0.16 5.6-1.8 8.1l-8e-3 0.012c-1.4 2.4-3.6 4.1-6.6 5.1-2.4 0.79-5.4 1.1-9.5 1.1z" fill="#a7a3dd"/>
 <path id="28" d="m88 613-2e-3 1e-3c-3 1.5-6 2.4-9 2.8-2.8 0.4-5.6 0.32-8.1-0.24-5-1.1-9-3.9-11-8-1-1.9-1.7-3.8-1.9-5.7a13 13 0 0 1 0.52-5.8c0.8-2.5 2.4-5 4.6-7.2 2.4-2.4 5.6-4.6 9.5-6.5l0.2-0.1c4.3-2.1 9.1-3.4 14-3.8 4.3-0.35 8.5 0.11 12 1.3 1.9 0.65 3.5 1.5 4.8 2.5s2.3 2.2 2.9 3.6c0.89 1.9 1.2 4 0.9 6.2-0.28 2.2-1.1 4.5-2.5 6.8s-3.3 4.6-5.7 6.8-5.3 4.3-8.5 6.2c-0.7 0.4-1.4 0.78-2.1 1.1z" fill="#a7a3dd"/>
 <path id="19" d="m377 582 0.2 0.1c3.9 1.9 7.1 4.1 9.5 6.5 2.3 2.3 3.8 4.7 4.6 7.2 0.59 1.9 0.77 3.8 0.52 5.8-0.24 1.9-0.89 3.8-1.9 5.7-2.2 4.1-6.2 6.9-11 8-2.6 0.56-5.3 0.64-8.1 0.23-3-0.42-6-1.4-9-2.8a37 37 0 0 1-2.1-1.1c-3.2-1.8-6.1-3.9-8.5-6.2-2.4-2.2-4.3-4.5-5.7-6.8s-2.2-4.6-2.5-6.8c-0.29-2.2 0.014-4.3 0.9-6.2 0.62-1.3 1.6-2.5 2.9-3.6 1.3-1 2.9-1.9 4.8-2.5 3.5-1.2 7.6-1.7 12-1.3 4.7 0.38 9.4 1.7 14 3.8z" fill="#a7a3dd"/>
 <path id="27" d="m83 643h-1e-3c-2.6-2.6-3.8-5.7-3.5-9.2 0.42-5 3.9-10 9.7-14 5-3.6 11-6 16-6.8 5.1-0.81 9.4-0.076 12 2 0.1 0.089 0.2 0.18 0.3 0.28 2.2 2.2 3.3 6.5 2.8 11a27 27 0 0 1-1.8 7.4 26 26 0 0 1-4.2 7c-7.4 8.7-21 10-29 3.7a16 16 0 0 1-1.6-1.4z" fill="#a7a3dd"/>
 <path id="20" d="m332 615a6.3 6.3 0 0 1 0.3-0.28c2.4-2.1 6.6-2.8 12-2 5.4 0.85 11 3.3 16 6.8 5.7 4.1 9.3 9.3 9.7 14 0.28 3.4-0.92 6.6-3.5 9.2-0.49 0.49-1 0.96-1.6 1.4-8.7 6.6-22 4.9-29-3.7a26 26 0 0 1-4.2-7 27 27 0 0 1-1.8-7.4c-0.47-4.9 0.57-9.1 2.8-11z" fill="#a7a3dd"/>
 <path id="26" d="m111 677c-1.7-1.6-3.2-3.7-4.3-6.1-1.2-2.7-1.8-5.5-1.6-8a13 13 0 0 1 1.8-5.8c1.2-2 2.9-3.8 5.2-5.4 5.6-3.9 12-6.6 19-7.5 2.8-0.38 5.4-0.41 7.7-0.086 2.2 0.32 3.9 0.96 5.1 1.8 0.1 0.076 0.2 0.16 0.29 0.24 1.6 1.4 1.9 4.2 1.1 8.3-0.75 3.7-2.4 8.2-3.9 12a300 300 0 0 0-1.7 4.7c-0.18 0.54-0.36 1.1-0.55 1.7-0.77 2.4-1.6 4.8-2.9 6.8-1.5 2.2-3.4 3.4-5.8 3.6h-5e-3l-4e-3 1e-3c-3.3 0.45-7.3-0.71-10-1.8-3.4-1.3-6.4-3-7.8-4a13 13 0 0 1-1.1-0.92z" fill="#a7a3dd"/>
 <path id="21" d="m307 647c0.09-0.084 0.19-0.17 0.29-0.24 1.2-0.9 2.9-1.5 5.1-1.8 2.2-0.33 4.9-0.3 7.7 0.086 6.4 0.88 13 3.5 19 7.5 2.2 1.6 4 3.4 5.2 5.4a13 13 0 0 1 1.8 5.8c0.18 2.6-0.36 5.4-1.6 8-1.1 2.3-2.6 4.5-4.3 6.1-0.36 0.34-0.73 0.65-1.1 0.92-1.4 1.1-4.4 2.7-7.8 4-2.8 1.1-6.8 2.2-10 1.8h-8e-3c-2.5-0.26-4.4-1.4-5.8-3.6-1.3-2-2.1-4.4-2.9-6.8-0.19-0.58-0.36-1.1-0.55-1.7a301 301 0 0 0-1.7-4.7c-1.6-4.3-3.2-8.8-3.9-12-0.83-4.1-0.48-6.9 1.1-8.3z" fill="#a7a3dd"/>
 <path id="25" d="m158 704h-1e-3a105 105 0 0 1-5.9-2.8c-5.8-2.9-9.9-5.4-13-7.4-2.5-1.9-3.7-3.7-3.9-5.3-0.14-1.3 0.41-2.5 1.7-4 1.2-1.4 3-2.8 5-4.4 0.51-0.41 1-0.83 1.6-1.3 5.3-4.3 9.5-7.1 13-8.8 4.3-1.9 7.8-2.3 11-1l0.04 0.018c3.2 1.4 4.9 3.3 5.8 6.6 0.82 3.1 0.91 7.3 0.3 15-0.13 1.6-0.21 3.1-0.28 4.6-0.26 5.3-0.47 9.4-3 11-2.2 1.4-6.2 0.77-13-2z" fill="#a7a3dd"/>
 <path id="22" d="m283 669c2.9-1.2 6.4-0.91 11 1 3.7 1.7 7.9 4.5 13 8.8 0.54 0.44 1.1 0.86 1.6 1.3 2 1.6 3.8 3 5 4.4 1.3 1.5 1.9 2.7 1.7 4-0.17 1.6-1.4 3.3-3.9 5.3-2.6 2.1-6.8 4.5-13 7.4a105 105 0 0 1-5.9 2.8c-6.4 2.7-10 3.3-13 2-2.5-1.6-2.7-5.7-3-11-0.073-1.5-0.15-3-0.28-4.6-0.61-7.4-0.52-12 0.3-15 0.86-3.2 2.6-5.2 5.8-6.6l0.04-0.017z" fill="#a7a3dd"/>
 <path id="24" d="m205 718h-1e-3a82 82 0 0 1-5-0.69c-7-1.2-12-2.5-16-4.2-3.3-1.5-5.3-3.1-6.2-5.1-0.77-1.7-0.73-3.5 0.12-5.9 0.77-2.1 2.1-4.4 3.5-6.7l0.3-0.5c5.4-9.2 13-20 23-18 0.21 0.022 0.42 0.048 0.62 0.079 4.5 0.66 7.9 3.2 10 7.6 2.1 3.9 3.2 8.9 4.2 13l0.29 1.3c0.18 0.81 0.4 1.7 0.63 2.5 0.63 2.5 1.3 5 1.4 7.4 0.15 2.7-0.41 4.8-1.7 6.3-1.2 1.3-3 2.3-5.4 2.8-2.7 0.58-6.3 0.65-11 0.19z" fill="#a7a3dd"/>
 <path id="23" d="m245 677c10-1.1 18 9.3 23 18l0.3 0.5c1.4 2.4 2.7 4.6 3.5 6.7 0.85 2.3 0.88 4.2 0.11 5.9-0.9 2-2.9 3.6-6.2 5.1-3.7 1.6-8.9 3-16 4.2a82 82 0 0 1-5 0.69c-4.3 0.46-7.9 0.39-11-0.2-2.4-0.52-4.2-1.5-5.4-2.8-1.3-1.5-1.9-3.6-1.7-6.3 0.14-2.4 0.79-5 1.4-7.4a96 96 0 0 0 0.92-3.8c0.98-4.3 2.1-9.3 4.2-13 2.4-4.5 5.8-6.9 10-7.6 0.21-0.03 0.42-0.057 0.62-0.079z" fill="#a7a3dd"/>
</svg>

now you need to parse it somehow - you need two extra packages:

import 'package:path_drawing/path_drawing.dart';
import 'package:xml/xml.dart';

and this is a custom StatefulWidget widget to show it all:

typedef Data = ({Size size, Map<int, Tooth> teeth});

class Foo extends StatefulWidget {
  const Foo({
    super.key,
    required this.asset,
    required this.idToString,
  });
  final String asset;
  final String Function(int id) idToString;

  @override
  State<Foo> createState() => _FooState();
}

class _FooState extends State<Foo> {
  Data data = (size: Size.zero, teeth: {});

  @override
  void initState() {
    super.initState();
    loadTeeth(widget.asset).then((value) {
      setState(() => data = value);
    });
  }

  @override
  Widget build(BuildContext context) {
    if (data.size == Size.zero) return const UnconstrainedBox();

    return Card(
      child: FittedBox(
        child: SizedBox.fromSize(
          size: data.size,
          child: Stack(
            children: [
              // teeth
              for (final MapEntry(key: key, value: tooth) in data.teeth.entries)
                Positioned.fromRect(
                  rect: tooth.rect,
                  child: Tooltip(
                    message: 'tooth\n${widget.idToString(key)}',
                    textAlign: TextAlign.center,
                    preferBelow: false,
                    decoration: const BoxDecoration(
                      color: Colors.black87,
                      border: Border.symmetric(
                        horizontal: BorderSide(color: Colors.white54)
                      ),
                    ),
                    child: AnimatedContainer(
                      duration: const Duration(milliseconds: 750),
                      clipBehavior: Clip.antiAlias,
                      decoration: ShapeDecoration(
                        color: tooth.selected? Colors.teal.shade400 : Colors.white,
                        shadows: tooth.selected? [const BoxShadow(blurRadius: 4, offset: Offset(0, 6))] : null,
                        shape: ToothBorder(tooth.path),
                      ),
                      child: Material(
                        type: MaterialType.transparency,
                        child: InkWell(
                          splashColor: tooth.selected? Colors.white : Colors.teal.shade400,
                          highlightColor: Colors.transparent,
                          onTap: () {
                            print('tooth ${widget.idToString(key)} pressed (id $key)');
                            setState(() => tooth.selected = !tooth.selected);
                          },
                        ),
                      ),
                    ),
                  ),
                ),
              // selected teeth list
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 125, vertical: 150),
                child: Center(
                  child: Builder(
                    builder: (context) {
                      final selected = data.teeth.entries
                        .where((e) => e.value.selected)
                        .map((e) => Text(widget.idToString(e.key)))
                        .toList();
                      return DefaultTextStyle(
                        style: Theme.of(context).textTheme.headlineMedium!,
                        textAlign: TextAlign.center,
                        child: AnimatedOpacity(
                          duration: const Duration(milliseconds: 500),
                          opacity: selected.isNotEmpty? 1 : 0,
                          child: DecoratedBox(
                            decoration: const BoxDecoration(
                              border: Border.symmetric(
                                horizontal: BorderSide(width: 3, color: Colors.black26)
                              ),
                            ),
                            child: ListView(
                              shrinkWrap: true,
                              children: selected,
                            ),
                          ),
                        ),
                      );
                    }
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<Data> loadTeeth(String asset) async {
    final xml = await rootBundle.loadString(asset);

    final doc = XmlDocument.parse(xml);
    final viewBox = doc.rootElement.getAttribute('viewBox')!.split(' ');
    final w = double.parse(viewBox[2]);
    final h = double.parse(viewBox[3]);

    final teeth = doc.rootElement.findAllElements('path');
    print('loaded ${teeth.length} paths');
    return (
      size: Size(w, h),
      teeth: <int, Tooth>{
        for (final tooth in teeth)
          int.parse(tooth.getAttribute('id')!): Tooth(parseSvgPathData(tooth.getAttribute('d')!)),
      },
    );
  }
}

class Tooth {
  Tooth(Path originalPath) {
    rect = originalPath.getBounds();
    path = originalPath.shift(-rect.topLeft);
  }

  late final Path path;
  late final Rect rect;
  bool selected = false;
}

class ToothBorder extends ShapeBorder {
  const ToothBorder(this.path);

  final Path path;

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) => getOuterPath(rect);

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    return rect.topLeft == Offset.zero? path : path.shift(rect.topLeft);
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
    final paint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2
      ..color = Colors.black54;
    canvas.drawPath(getOuterPath(rect), paint);
  }

  @override
  ShapeBorder scale(double t) => this;
}

now you can use it like this:

child: Foo(
  asset: 'assets/teeth.svg',
  idToString: adultIdToString,
),

where adultIdToString is a function for adult teeth layout:

String adultIdToString(int id) {
  final (up, left, number) = switch (id) {
    < 8 => (true, false, 8 - id),
    < 16 => (true, true, id - 8 + 1),
    < 24 => (false, true, 24 - id),
    _ => (false, false, id - 24 + 1),
  };
  return '${up? 'up' : 'down'} ${left? 'left' : 'right'} #$number';
}

and this is a similar function for a child:

String childIdToString(int id) {
  final (up, left, number) = switch (id) {
    < 6 => (true, false, 6 - id),
    < 12 => (true, true, id - 6 + 1),
    < 18 => (false, true, 18 - id),
    _ => (false, false, id - 18 + 1),
  };
  return '${up? 'up' : 'down'} ${left? 'left' : 'right'} #$number';
}

this way you can use the same code base for both adult and child teeth layout

Sign up to request clarification or add additional context in comments.

12 Comments

is there any tool to simplify svg as you did ?, i tried to do the same with anouther svg file ( baby teeth ) but it didnt work properly svg file : drive.google.com/file/d/1gP-aIeaCEhFfg_AvlelB632tsHqE_rck/…
inkscape.org i used File > Save As... and choose "optimized svg"
please would you tell me if there s something needs to be changed in the code ! I'm seeking your expertise to help me resolve it: the problem is that when I change the SVG files, the teeth appear to be large and compressed, with some overlapping each other. I have tried optimizing the SVG files using Inkscape, but the issue persists. if nothing needs to be changed in the code can you try this file of svg and lemme know if it gives same result ? : drive.google.com/file/d/1gP-aIeaCEhFfg_AvlelB632tsHqE_rck/…
with inkscape you first have to select any tooth and then Object > Ungroup then File > Save As - basically you cannot have any "transform" in output file
once you do that everything works fine (ok you need to change IDs to 0..23 and modify _idToString method since there is 24 teeth, not 32
|
0

enter image description hereThis is my example:

[![import 'package:flutter/material.dart';
import 'dart:math'; // Import the math library for sin and cos functions

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: ToothUShape(),
        ),
      ),
    );
  }
}

class ToothUShape extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 400.0,
      height: 200.0, // Adjust the height based on your design
      child: Stack(
        children: _buildTeeth(),
      ),
    );
  }

  List<Widget> _buildTeeth() {
    List<Widget> teeth = \[\];
    final double toothWidth = 12.5;
    final double toothHeight = 25.0;
    final double curveRadius = 100.0; 
    for (int i = 0; i < 32; i++) {
      double angle = i / 31 * pi;
      double x = curveRadius * (1 - cos(angle));
      double y = curveRadius * sin(angle);

      teeth.add(
        Positioned(
          left: x,
          top: y,
          child: Tooth(),
        ),
      );
    }

    return teeth;
  }
}

class Tooth extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 12.5,
      height: 25.0, // Adjust the height based on your design
      decoration: BoxDecoration(
        color: Colors.blue, // Tooth color
        borderRadius: BorderRadius.vertical(
          top: Radius.circular(12.5), // Adjust the circular radius
        ),
      ),
      child: Center(
        child: Text(
          'TOOTH',
          style: TextStyle(
            color: Colors.white,
          ),
        ),
      ),
    );
  }
}][1]][1]

1 Comment

I tried a similar example, but it's not like the UI I provided! I want to achieve the same UI , thank you
0

Unfortunately, I came to this question very late. I created the same model by calculating Stack left & top positions in Flutter 5 months ago, where each tooth is clickable and some color is applied over tooth if you select some complaints against a tooth and update the Map. This is also responsive in any device. See the image, reach out to me if you still need it.

Tooth Selection UI Model

1 Comment

Hi. I need this UI that you did, could you share this for me
0

For anyone stumbling across this issue I've made a flutter widget that includes both primary and permanent teeth, Also, it can select single or multiple teeth.: https://github.com/alselawi/teeth-selector.

Basic teeth selector Teeth selector with some options

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.