ChartGraphics.cs 205 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. //
  5. // Purpose: Chart graphic class is used for drawing Chart
  6. // elements as Rectangles, Pie slices, lines, areas
  7. // etc. This class is used in all classes where
  8. // drawing is necessary. The GDI+ graphic class is
  9. // used throw this class. Encapsulates a GDI+ chart
  10. // drawing functionality
  11. //
  12. using System;
  13. using System.Windows.Forms;
  14. using System.Diagnostics.CodeAnalysis;
  15. using System.Drawing;
  16. using System.Drawing.Drawing2D;
  17. using System.Drawing.Imaging;
  18. using FastReport.DataVisualization.Charting.Borders3D;
  19. using FastReport.DataVisualization.Charting.Utilities;
  20. namespace FastReport.DataVisualization.Charting
  21. {
  22. using Size = System.Drawing.Size;
  23. #region Enumerations
  24. /// <summary>
  25. /// Defines the style how the bars/columns are drawn.
  26. /// </summary>
  27. internal enum BarDrawingStyle
  28. {
  29. /// <summary>
  30. /// Default bar/column style.
  31. /// </summary>
  32. Default,
  33. /// <summary>
  34. /// Cylinder bar/column style.
  35. /// </summary>
  36. Cylinder,
  37. /// <summary>
  38. /// Emboss bar/column style.
  39. /// </summary>
  40. Emboss,
  41. /// <summary>
  42. /// LightToDark bar/column style.
  43. /// </summary>
  44. LightToDark,
  45. /// <summary>
  46. /// Wedge bar/column style.
  47. /// </summary>
  48. Wedge,
  49. }
  50. /// <summary>
  51. /// Defines the style how the pie and doughnut charts are drawn.
  52. /// </summary>
  53. internal enum PieDrawingStyle
  54. {
  55. /// <summary>
  56. /// Default pie/doughnut drawing style.
  57. /// </summary>
  58. Default,
  59. /// <summary>
  60. /// Soft edge shadow is drawn on the edges of the pie/doughnut slices.
  61. /// </summary>
  62. SoftEdge,
  63. /// <summary>
  64. /// A shadow is drawn from the top to the bottom of the pie/doughnut chart.
  65. /// </summary>
  66. Concave,
  67. }
  68. /// <summary>
  69. /// An enumeration of line styles.
  70. /// </summary>
  71. public enum ChartDashStyle
  72. {
  73. /// <summary>
  74. /// Line style not set
  75. /// </summary>
  76. NotSet,
  77. /// <summary>
  78. /// Specifies a line consisting of dashes.
  79. /// </summary>
  80. Dash,
  81. /// <summary>
  82. /// Specifies a line consisting of a repeating pattern of dash-dot.
  83. /// </summary>
  84. DashDot,
  85. /// <summary>
  86. /// Specifies a line consisting of a repeating pattern of dash-dot-dot.
  87. /// </summary>
  88. DashDotDot,
  89. /// <summary>
  90. /// Specifies a line consisting of dots.
  91. /// </summary>
  92. Dot,
  93. /// <summary>
  94. /// Specifies a solid line.
  95. /// </summary>
  96. Solid,
  97. }
  98. #endregion
  99. /// <summary>
  100. /// The ChartGraphics class provides all chart drawing capabilities.
  101. /// It contains methods for drawing 2D primitives and also exposes
  102. /// all ChartGraphics3D class methods for 3D shapes. Only this
  103. /// class should be used for any drawing in the chart.
  104. /// </summary>
  105. public partial class ChartGraphics : ChartElement
  106. {
  107. #region Fields
  108. // Common Elements
  109. private CommonElements _common;
  110. // Reusable objects
  111. private Pen _pen;
  112. private SolidBrush _solidBrush;
  113. private Matrix _myMatrix;
  114. // Private fields which represents picture size
  115. private int _width;
  116. private int _height;
  117. // Indicates that smoothing is applied while drawing shadows
  118. internal bool softShadows = true;
  119. // Anti aliasing flags
  120. private AntiAliasingStyles _antiAliasing = AntiAliasingStyles.All;
  121. // True if rendering into the metafile
  122. internal bool IsMetafile = false;
  123. #endregion
  124. #region Lines Methods
  125. /// <summary>
  126. /// Draws a line connecting the two specified points.
  127. /// </summary>
  128. /// <param name="color">Line color.</param>
  129. /// <param name="width">Line width.</param>
  130. /// <param name="style">Line style.</param>
  131. /// <param name="firstPointF">A Point that represents the first point to connect.</param>
  132. /// <param name="secondPointF">A Point that represents the second point to connect.</param>
  133. internal void DrawLineRel(
  134. Color color,
  135. int width,
  136. ChartDashStyle style,
  137. PointF firstPointF,
  138. PointF secondPointF
  139. )
  140. {
  141. DrawLineAbs(
  142. color,
  143. width,
  144. style,
  145. GetAbsolutePoint(firstPointF),
  146. GetAbsolutePoint(secondPointF) );
  147. }
  148. /// <summary>
  149. /// Draws a line connecting the two specified points using absolute coordinates.
  150. /// </summary>
  151. /// <param name="color">Line color.</param>
  152. /// <param name="width">Line width.</param>
  153. /// <param name="style">Line style.</param>
  154. /// <param name="firstPoint">A Point that represents the first point to connect.</param>
  155. /// <param name="secondPoint">A Point that represents the second point to connect.</param>
  156. internal void DrawLineAbs(
  157. Color color,
  158. int width,
  159. ChartDashStyle style,
  160. PointF firstPoint,
  161. PointF secondPoint
  162. )
  163. {
  164. // Do not draw line if width is 0 or style not set
  165. if( width == 0 || style == ChartDashStyle.NotSet )
  166. {
  167. return;
  168. }
  169. // Set a line color
  170. if(_pen.Color != color)
  171. {
  172. _pen.Color = color;
  173. }
  174. // Set a line width
  175. if(_pen.Width != width)
  176. {
  177. _pen.Width = width;
  178. }
  179. // Set a line style
  180. if(_pen.DashStyle != GetPenStyle( style ))
  181. {
  182. _pen.DashStyle = GetPenStyle( style );
  183. }
  184. // Remember SmoothingMode and turn off anti aliasing for
  185. // vertical or horizontal lines usinig 1 pixel dashed pen.
  186. // This prevents anialiasing from completly smoothing the
  187. // dashed line.
  188. SmoothingMode oldSmoothingMode = this.SmoothingMode;
  189. if(width <= 1 && style != ChartDashStyle.Solid)
  190. {
  191. if(firstPoint.X == secondPoint.X ||
  192. firstPoint.Y == secondPoint.Y)
  193. {
  194. this.SmoothingMode = SmoothingMode.Default;
  195. }
  196. }
  197. // Draw a line
  198. this.DrawLine(_pen,
  199. (float)Math.Round(firstPoint.X),
  200. (float)Math.Round(firstPoint.Y),
  201. (float)Math.Round(secondPoint.X),
  202. (float)Math.Round(secondPoint.Y) );
  203. // Return old smoothing mode
  204. this.SmoothingMode = oldSmoothingMode;
  205. }
  206. /// <summary>
  207. /// Draws a line with shadow connecting the two specified points.
  208. /// </summary>
  209. /// <param name="color">Line color.</param>
  210. /// <param name="width">Line width.</param>
  211. /// <param name="style">Line style.</param>
  212. /// <param name="firstPoint">A Point that represents the first point to connect.</param>
  213. /// <param name="secondPoint">A Point that represents the second point to connect.</param>
  214. /// <param name="shadowColor">Shadow Color.</param>
  215. /// <param name="shadowOffset">Shadow Offset.</param>
  216. internal void DrawLineRel(
  217. Color color,
  218. int width,
  219. ChartDashStyle style,
  220. PointF firstPoint,
  221. PointF secondPoint,
  222. Color shadowColor,
  223. int shadowOffset
  224. )
  225. {
  226. DrawLineAbs(
  227. color,
  228. width,
  229. style,
  230. GetAbsolutePoint(firstPoint),
  231. GetAbsolutePoint(secondPoint),
  232. shadowColor,
  233. shadowOffset );
  234. }
  235. /// <summary>
  236. /// Draws a line with shadow connecting the two specified points.
  237. /// </summary>
  238. /// <param name="color">Line color.</param>
  239. /// <param name="width">Line width.</param>
  240. /// <param name="style">Line style.</param>
  241. /// <param name="firstPoint">A Point that represents the first point to connect.</param>
  242. /// <param name="secondPoint">A Point that represents the second point to connect.</param>
  243. /// <param name="shadowColor">Shadow Color.</param>
  244. /// <param name="shadowOffset">Shadow Offset.</param>
  245. internal void DrawLineAbs(
  246. Color color,
  247. int width,
  248. ChartDashStyle style,
  249. PointF firstPoint,
  250. PointF secondPoint,
  251. Color shadowColor,
  252. int shadowOffset
  253. )
  254. {
  255. if(shadowOffset != 0)
  256. {
  257. // Shadow color
  258. Color shColor;
  259. // Make shadow semi transparent
  260. // if alpha value not used
  261. if( shadowColor.A != 255 )
  262. shColor = shadowColor;
  263. else
  264. shColor = Color.FromArgb(color.A/2, shadowColor);
  265. // Set shadow line position
  266. PointF firstShadow = new PointF( firstPoint.X + shadowOffset, firstPoint.Y + shadowOffset);
  267. PointF secondShadow = new PointF( secondPoint.X + shadowOffset, secondPoint.Y + shadowOffset );
  268. // Draw Shadow of Line
  269. DrawLineAbs( shColor, width, style, firstShadow, secondShadow );
  270. }
  271. // Draw Line
  272. DrawLineAbs( color, width, style, firstPoint, secondPoint );
  273. }
  274. #endregion
  275. #region Pen and Brush Methods
  276. /// <summary>
  277. /// Creates a Hatch Brush.
  278. /// </summary>
  279. /// <param name="hatchStyle">Chart Hatch style.</param>
  280. /// <param name="backColor">Back Color.</param>
  281. /// <param name="foreColor">Fore Color.</param>
  282. /// <returns>Brush</returns>
  283. internal Brush GetHatchBrush(
  284. ChartHatchStyle hatchStyle,
  285. Color backColor,
  286. Color foreColor
  287. )
  288. {
  289. // Convert Chart Hatch Style enum
  290. // to Hatch Style enum.
  291. HatchStyle hatch;
  292. hatch = (HatchStyle)Enum.Parse(typeof(HatchStyle),hatchStyle.ToString());
  293. // Create Hatch Brush
  294. return new HatchBrush( hatch, foreColor, backColor );
  295. }
  296. /// <summary>
  297. /// Creates a textured brush.
  298. /// </summary>
  299. /// <param name="name">Image file name or URL.</param>
  300. /// <param name="backImageTransparentColor">Image transparent color.</param>
  301. /// <param name="mode">Wrap mode.</param>
  302. /// <param name="backColor">Image background color.</param>
  303. /// <returns>Textured brush.</returns>
  304. internal Brush GetTextureBrush(
  305. string name,
  306. Color backImageTransparentColor,
  307. ChartImageWrapMode mode,
  308. Color backColor
  309. )
  310. {
  311. // Load a image
  312. System.Drawing.Image image = _common.ImageLoader.LoadImage( name );
  313. // Create a brush
  314. ImageAttributes attrib = new ImageAttributes();
  315. attrib.SetWrapMode((mode == ChartImageWrapMode.Unscaled) ? WrapMode.Clamp : ((WrapMode)mode));
  316. if(backImageTransparentColor != Color.Empty)
  317. {
  318. attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
  319. }
  320. // If image is a metafile background must be filled first
  321. // Solves issue that background is not cleared correctly
  322. if(backImageTransparentColor == Color.Empty &&
  323. image is Metafile &&
  324. backColor != Color.Transparent)
  325. {
  326. TextureBrush backFilledBrush = null;
  327. Bitmap bitmap = new Bitmap(image.Width, image.Height);
  328. using(Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
  329. {
  330. using(SolidBrush backBrush = new SolidBrush(backColor))
  331. {
  332. graphics.FillRectangle(backBrush, 0, 0, image.Width, image.Height);
  333. graphics.DrawImageUnscaled(image, 0, 0);
  334. backFilledBrush= new TextureBrush( bitmap, new RectangleF(0,0,image.Width,image.Height), attrib);
  335. }
  336. }
  337. return backFilledBrush;
  338. }
  339. TextureBrush textureBrush;
  340. if (ImageLoader.DoDpisMatch(image, this.Graphics))
  341. textureBrush = new TextureBrush(image, new RectangleF(0, 0, image.Width, image.Height), attrib);
  342. else // if the image dpi does not match the graphics dpi we have to scale the image
  343. {
  344. Image scaledImage = ImageLoader.GetScaledImage(image, this.Graphics);
  345. textureBrush = new TextureBrush(scaledImage, new RectangleF(0, 0, scaledImage.Width, scaledImage.Height), attrib);
  346. scaledImage.Dispose();
  347. }
  348. return textureBrush;
  349. }
  350. /// <summary>
  351. /// This method creates a gradient brush.
  352. /// </summary>
  353. /// <param name="rectangle">A rectangle which has to be filled with a gradient color.</param>
  354. /// <param name="firstColor">First color.</param>
  355. /// <param name="secondColor">Second color.</param>
  356. /// <param name="type ">Gradient type .</param>
  357. /// <returns>Gradient Brush</returns>
  358. internal Brush GetGradientBrush(
  359. RectangleF rectangle,
  360. Color firstColor,
  361. Color secondColor,
  362. GradientStyle type
  363. )
  364. {
  365. // Increse the brush rectangle by 1 pixel to ensure the fit
  366. rectangle.Inflate(1f, 1f);
  367. Brush gradientBrush = null;
  368. float angle = 0;
  369. // Function which create gradient brush fires exception if
  370. // rectangle size is zero.
  371. if( rectangle.Height == 0 || rectangle.Width == 0 )
  372. {
  373. gradientBrush = new SolidBrush( Color.Black );
  374. return gradientBrush;
  375. }
  376. // *******************************************
  377. // Linear Gradient
  378. // *******************************************
  379. // Check linear type .
  380. if( type == GradientStyle.LeftRight || type == GradientStyle.VerticalCenter )
  381. {
  382. angle = 0;
  383. }
  384. else if( type == GradientStyle.TopBottom || type == GradientStyle.HorizontalCenter )
  385. {
  386. angle = 90;
  387. }
  388. else if( type == GradientStyle.DiagonalLeft )
  389. {
  390. angle = (float)(Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI);
  391. }
  392. else if( type == GradientStyle.DiagonalRight )
  393. {
  394. angle = (float)(180 - Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI);
  395. }
  396. // Create a linear gradient brush
  397. if( type == GradientStyle.TopBottom || type == GradientStyle.LeftRight
  398. || type == GradientStyle.DiagonalLeft || type == GradientStyle.DiagonalRight
  399. || type == GradientStyle.HorizontalCenter || type == GradientStyle.VerticalCenter )
  400. {
  401. RectangleF tempRect = new RectangleF(rectangle.X,rectangle.Y,rectangle.Width,rectangle.Height);
  402. // For Horizontal and vertical center gradient types
  403. if( type == GradientStyle.HorizontalCenter )
  404. {
  405. // Resize and wrap gradient
  406. tempRect.Height = tempRect.Height / 2F;
  407. LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
  408. gradientBrush = linearGradientBrush;
  409. linearGradientBrush.WrapMode = WrapMode.TileFlipX;
  410. }
  411. else if( type == GradientStyle.VerticalCenter )
  412. {
  413. // Resize and wrap gradient
  414. tempRect.Width = tempRect.Width / 2F;
  415. LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
  416. gradientBrush = linearGradientBrush;
  417. linearGradientBrush.WrapMode = WrapMode.TileFlipX;
  418. }
  419. else
  420. {
  421. gradientBrush = new LinearGradientBrush( rectangle, firstColor, secondColor, angle );
  422. }
  423. return gradientBrush;
  424. }
  425. // *******************************************
  426. // Gradient is not linear : From Center.
  427. // *******************************************
  428. // Create a path
  429. GraphicsPath path = new GraphicsPath();
  430. // Add a rectangle to the path
  431. path.AddRectangle( rectangle );
  432. // Create a gradient brush
  433. PathGradientBrush pathGradientBrush = new PathGradientBrush(path);
  434. gradientBrush = pathGradientBrush;
  435. // Set the center color
  436. pathGradientBrush.CenterColor = firstColor;
  437. // Set the Surround color
  438. Color[] colors = {secondColor};
  439. pathGradientBrush.SurroundColors = colors;
  440. if( path != null )
  441. {
  442. path.Dispose();
  443. }
  444. return gradientBrush;
  445. }
  446. /// <summary>
  447. /// This method creates a gradient brush for pie. This gradient is one
  448. /// of the types used only with pie and doughnut.
  449. /// </summary>
  450. /// <param name="rectangle">A rectangle which has to be filled with a gradient color</param>
  451. /// <param name="firstColor">First color</param>
  452. /// <param name="secondColor">Second color</param>
  453. /// <returns>Gradient Brush</returns>
  454. internal Brush GetPieGradientBrush(
  455. RectangleF rectangle,
  456. Color firstColor,
  457. Color secondColor
  458. )
  459. {
  460. // Create a path that consists of a single ellipse.
  461. GraphicsPath path = new GraphicsPath();
  462. path.AddEllipse( rectangle );
  463. // Use the path to construct a brush.
  464. PathGradientBrush gradientBrush = new PathGradientBrush(path);
  465. // Set the color at the center of the path.
  466. gradientBrush.CenterColor = firstColor;
  467. // Set the color along the entire boundary
  468. // of the path to aqua.
  469. Color[] colors = {secondColor};
  470. gradientBrush.SurroundColors = colors;
  471. if( path != null )
  472. {
  473. path.Dispose();
  474. }
  475. return gradientBrush;
  476. }
  477. /// <summary>
  478. /// Converts GDI+ line style to Chart Graph line style.
  479. /// </summary>
  480. /// <param name="style">Chart Line style.</param>
  481. /// <returns>GDI+ line style.</returns>
  482. internal DashStyle GetPenStyle( ChartDashStyle style )
  483. {
  484. // Convert to chart line styles. The custom style doesn’t exist.
  485. switch( style )
  486. {
  487. case ChartDashStyle.Dash:
  488. return DashStyle.Dash;
  489. case ChartDashStyle.DashDot:
  490. return DashStyle.DashDot;
  491. case ChartDashStyle.DashDotDot:
  492. return DashStyle.DashDotDot;
  493. case ChartDashStyle.Dot:
  494. return DashStyle.Dot;
  495. }
  496. return DashStyle.Solid;
  497. }
  498. #endregion
  499. #region Markers
  500. /// <summary>
  501. /// Creates polygon for multi-corner star marker.
  502. /// </summary>
  503. /// <param name="rect">Marker rectangle.</param>
  504. /// <param name="numberOfCorners">Number of corners (4 and up).</param>
  505. /// <returns>Array of points.</returns>
  506. internal PointF[] CreateStarPolygon(RectangleF rect, int numberOfCorners)
  507. {
  508. int numberOfCornersX2;
  509. checked
  510. {
  511. numberOfCornersX2 = numberOfCorners * 2;
  512. }
  513. bool outside = true;
  514. PointF[] points = new PointF[numberOfCornersX2];
  515. PointF[] tempPoints = new PointF[1];
  516. // overflow check
  517. for (int pointIndex = 0; pointIndex < numberOfCornersX2; pointIndex++)
  518. {
  519. tempPoints[0] = new PointF(rect.X + rect.Width/2f, (outside == true) ? rect.Y : rect.Y + rect.Height/4f);
  520. Matrix matrix = new Matrix();
  521. matrix.RotateAt(pointIndex*(360f/(numberOfCorners*2f)), new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f));
  522. matrix.TransformPoints(tempPoints);
  523. points[pointIndex] = tempPoints[0];
  524. outside = !outside;
  525. }
  526. return points;
  527. }
  528. /// <summary>
  529. /// Draw marker using relative coordinates of the center.
  530. /// </summary>
  531. /// <param name="point">Coordinates of the center.</param>
  532. /// <param name="markerStyle">Marker style.</param>
  533. /// <param name="markerSize">Marker size.</param>
  534. /// <param name="markerColor">Marker color.</param>
  535. /// <param name="markerBorderColor">Marker border color.</param>
  536. /// <param name="markerBorderSize">Marker border size.</param>
  537. /// <param name="markerImage">Marker image name.</param>
  538. /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
  539. /// <param name="shadowSize">Marker shadow size.</param>
  540. /// <param name="shadowColor">Marker shadow color.</param>
  541. /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
  542. internal void DrawMarkerRel(
  543. PointF point,
  544. MarkerStyle markerStyle,
  545. int markerSize,
  546. Color markerColor,
  547. Color markerBorderColor,
  548. int markerBorderSize,
  549. string markerImage,
  550. Color markerImageTransparentColor,
  551. int shadowSize,
  552. Color shadowColor,
  553. RectangleF imageScaleRect
  554. )
  555. {
  556. DrawMarkerAbs(this.GetAbsolutePoint(point), markerStyle, markerSize, markerColor, markerBorderColor, markerBorderSize, markerImage, markerImageTransparentColor, shadowSize, shadowColor, imageScaleRect, false);
  557. }
  558. /// <summary>
  559. /// Draw marker using absolute coordinates of the center.
  560. /// </summary>
  561. /// <param name="point">Coordinates of the center.</param>
  562. /// <param name="markerStyle">Marker style.</param>
  563. /// <param name="markerSize">Marker size.</param>
  564. /// <param name="markerColor">Marker color.</param>
  565. /// <param name="markerBorderColor">Marker border color.</param>
  566. /// <param name="markerBorderSize">Marker border size.</param>
  567. /// <param name="markerImage">Marker image name.</param>
  568. /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
  569. /// <param name="shadowSize">Marker shadow size.</param>
  570. /// <param name="shadowColor">Marker shadow color.</param>
  571. /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
  572. /// <param name="forceAntiAlias">Always use anti aliasing when drawing the marker.</param>
  573. internal void DrawMarkerAbs(
  574. PointF point,
  575. MarkerStyle markerStyle,
  576. int markerSize,
  577. Color markerColor,
  578. Color markerBorderColor,
  579. int markerBorderSize,
  580. string markerImage,
  581. Color markerImageTransparentColor,
  582. int shadowSize,
  583. Color shadowColor,
  584. RectangleF imageScaleRect,
  585. bool forceAntiAlias
  586. )
  587. {
  588. // Hide border when zero width specified
  589. if(markerBorderSize <= 0)
  590. {
  591. markerBorderColor = Color.Transparent;
  592. }
  593. // Draw image instead of standart markers
  594. if(markerImage.Length > 0)
  595. {
  596. // Get image
  597. System.Drawing.Image image = _common.ImageLoader.LoadImage( markerImage );
  598. if (image != null)
  599. {
  600. // Calculate image rectangle
  601. RectangleF rect = RectangleF.Empty;
  602. if (imageScaleRect == RectangleF.Empty)
  603. {
  604. SizeF size = new SizeF();
  605. ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref size);
  606. imageScaleRect.Width = size.Width;
  607. imageScaleRect.Height = size.Height;
  608. }
  609. rect.X = point.X - imageScaleRect.Width / 2F;
  610. rect.Y = point.Y - imageScaleRect.Height / 2F;
  611. rect.Width = imageScaleRect.Width;
  612. rect.Height = imageScaleRect.Height;
  613. // Prepare image properties (transparent color)
  614. ImageAttributes attrib = new ImageAttributes();
  615. if (markerImageTransparentColor != Color.Empty)
  616. {
  617. attrib.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
  618. }
  619. // Draw image shadow
  620. if (shadowSize != 0 && shadowColor != Color.Empty)
  621. {
  622. ImageAttributes attribShadow = new ImageAttributes();
  623. attribShadow.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
  624. ColorMatrix colorMatrix = new ColorMatrix();
  625. colorMatrix.Matrix00 = 0.25f; // Red
  626. colorMatrix.Matrix11 = 0.25f; // Green
  627. colorMatrix.Matrix22 = 0.25f; // Blue
  628. colorMatrix.Matrix33 = 0.5f; // alpha
  629. colorMatrix.Matrix44 = 1.0f; // w
  630. attribShadow.SetColorMatrix(colorMatrix);
  631. this.DrawImage(image,
  632. new Rectangle((int)rect.X + shadowSize, (int)rect.Y + shadowSize, (int)rect.Width, (int)rect.Height),
  633. 0, 0, image.Width, image.Height,
  634. GraphicsUnit.Pixel,
  635. attribShadow);
  636. }
  637. // Draw image
  638. this.DrawImage(image,
  639. new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height),
  640. 0, 0, image.Width, image.Height,
  641. GraphicsUnit.Pixel,
  642. attrib);
  643. }
  644. }
  645. // Draw standart marker using style, size and color
  646. else if(markerStyle != MarkerStyle.None && markerSize > 0 && markerColor != Color.Empty)
  647. {
  648. // Enable antialising
  649. SmoothingMode oldSmoothingMode = this.SmoothingMode;
  650. if(forceAntiAlias)
  651. {
  652. this.SmoothingMode = SmoothingMode.AntiAlias;
  653. }
  654. // Create solid color brush
  655. using (SolidBrush brush = new SolidBrush(markerColor))
  656. {
  657. // Calculate marker rectangle
  658. RectangleF rect = RectangleF.Empty;
  659. rect.X = point.X - ((float)markerSize) / 2F;
  660. rect.Y = point.Y - ((float)markerSize) / 2F;
  661. rect.Width = markerSize;
  662. rect.Height = markerSize;
  663. // Draw marker depending on style
  664. switch (markerStyle)
  665. {
  666. case (MarkerStyle.Star4):
  667. case (MarkerStyle.Star5):
  668. case (MarkerStyle.Star6):
  669. case (MarkerStyle.Star10):
  670. {
  671. // Set number of corners
  672. int cornerNumber = 4;
  673. if (markerStyle == MarkerStyle.Star5)
  674. {
  675. cornerNumber = 5;
  676. }
  677. else if (markerStyle == MarkerStyle.Star6)
  678. {
  679. cornerNumber = 6;
  680. }
  681. else if (markerStyle == MarkerStyle.Star10)
  682. {
  683. cornerNumber = 10;
  684. }
  685. // Get star polygon
  686. PointF[] points = CreateStarPolygon(rect, cornerNumber);
  687. // Draw shadow
  688. if (shadowSize != 0 && shadowColor != Color.Empty)
  689. {
  690. Matrix translateMatrix = this.Transform.Clone();
  691. translateMatrix.Translate(shadowSize, shadowSize);
  692. Matrix oldMatrix = this.Transform;
  693. this.Transform = translateMatrix;
  694. this.FillPolygon(new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)), points);
  695. this.Transform = oldMatrix;
  696. }
  697. // Draw star
  698. this.FillPolygon(brush, points);
  699. this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
  700. break;
  701. }
  702. case (MarkerStyle.Circle):
  703. {
  704. // Draw marker shadow
  705. if (shadowSize != 0 && shadowColor != Color.Empty)
  706. {
  707. if (!softShadows)
  708. {
  709. using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
  710. {
  711. RectangleF shadowRect = rect;
  712. shadowRect.X += shadowSize;
  713. shadowRect.Y += shadowSize;
  714. this.FillEllipse(shadowBrush, shadowRect);
  715. }
  716. }
  717. else
  718. {
  719. // Add circle to the graphics path
  720. using (GraphicsPath path = new GraphicsPath())
  721. {
  722. path.AddEllipse(rect.X + shadowSize - 1, rect.Y + shadowSize - 1, rect.Width + 2, rect.Height + 2);
  723. // Create path brush
  724. using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
  725. {
  726. shadowBrush.CenterColor = shadowColor;
  727. // Set the color along the entire boundary of the path
  728. Color[] colors = { Color.Transparent };
  729. shadowBrush.SurroundColors = colors;
  730. shadowBrush.CenterPoint = new PointF(point.X, point.Y);
  731. // Define brush focus scale
  732. PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
  733. if (focusScale.X < 0)
  734. {
  735. focusScale.X = 0;
  736. }
  737. if (focusScale.Y < 0)
  738. {
  739. focusScale.Y = 0;
  740. }
  741. shadowBrush.FocusScales = focusScale;
  742. // Draw shadow
  743. this.FillPath(shadowBrush, path);
  744. }
  745. }
  746. }
  747. }
  748. this.FillEllipse(brush, rect);
  749. this.DrawEllipse(new Pen(markerBorderColor, markerBorderSize), rect);
  750. break;
  751. }
  752. case (MarkerStyle.Square):
  753. {
  754. // Draw marker shadow
  755. if (shadowSize != 0 && shadowColor != Color.Empty)
  756. {
  757. FillRectangleShadowAbs(rect, shadowColor, shadowSize, shadowColor);
  758. }
  759. this.FillRectangle(brush, rect);
  760. this.DrawRectangle(new Pen(markerBorderColor, markerBorderSize), (int)Math.Round(rect.X, 0), (int)Math.Round(rect.Y, 0), (int)Math.Round(rect.Width, 0), (int)Math.Round(rect.Height, 0));
  761. break;
  762. }
  763. case (MarkerStyle.Cross):
  764. {
  765. // Calculate cross line width and size
  766. float crossLineWidth = (float)Math.Ceiling(markerSize / 4F);
  767. float crossSize = markerSize;// * (float)Math.Sin(45f/180f*Math.PI);
  768. // Calculate cross coordinates
  769. PointF[] points = new PointF[12];
  770. points[0].X = point.X - crossSize / 2F;
  771. points[0].Y = point.Y + crossLineWidth / 2F;
  772. points[1].X = point.X - crossSize / 2F;
  773. points[1].Y = point.Y - crossLineWidth / 2F;
  774. points[2].X = point.X - crossLineWidth / 2F;
  775. points[2].Y = point.Y - crossLineWidth / 2F;
  776. points[3].X = point.X - crossLineWidth / 2F;
  777. points[3].Y = point.Y - crossSize / 2F;
  778. points[4].X = point.X + crossLineWidth / 2F;
  779. points[4].Y = point.Y - crossSize / 2F;
  780. points[5].X = point.X + crossLineWidth / 2F;
  781. points[5].Y = point.Y - crossLineWidth / 2F;
  782. points[6].X = point.X + crossSize / 2F;
  783. points[6].Y = point.Y - crossLineWidth / 2F;
  784. points[7].X = point.X + crossSize / 2F;
  785. points[7].Y = point.Y + crossLineWidth / 2F;
  786. points[8].X = point.X + crossLineWidth / 2F;
  787. points[8].Y = point.Y + crossLineWidth / 2F;
  788. points[9].X = point.X + crossLineWidth / 2F;
  789. points[9].Y = point.Y + crossSize / 2F;
  790. points[10].X = point.X - crossLineWidth / 2F;
  791. points[10].Y = point.Y + crossSize / 2F;
  792. points[11].X = point.X - crossLineWidth / 2F;
  793. points[11].Y = point.Y + crossLineWidth / 2F;
  794. // Rotate cross coordinates 45 degrees
  795. Matrix rotationMatrix = new Matrix();
  796. rotationMatrix.RotateAt(45, point);
  797. rotationMatrix.TransformPoints(points);
  798. // Draw shadow
  799. if (shadowSize != 0 && shadowColor != Color.Empty)
  800. {
  801. // Create translation matrix
  802. Matrix translateMatrix = this.Transform.Clone();
  803. translateMatrix.Translate(
  804. (softShadows) ? shadowSize + 1 : shadowSize,
  805. (softShadows) ? shadowSize + 1 : shadowSize);
  806. Matrix oldMatrix = this.Transform;
  807. this.Transform = translateMatrix;
  808. if (!softShadows)
  809. {
  810. using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
  811. {
  812. this.FillPolygon(softShadowBrush, points);
  813. }
  814. }
  815. else
  816. {
  817. // Add polygon to the graphics path
  818. using (GraphicsPath path = new GraphicsPath())
  819. {
  820. path.AddPolygon(points);
  821. // Create path brush
  822. using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
  823. {
  824. shadowBrush.CenterColor = shadowColor;
  825. // Set the color along the entire boundary of the path
  826. Color[] colors = { Color.Transparent };
  827. shadowBrush.SurroundColors = colors;
  828. shadowBrush.CenterPoint = new PointF(point.X, point.Y);
  829. // Define brush focus scale
  830. PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
  831. if (focusScale.X < 0)
  832. {
  833. focusScale.X = 0;
  834. }
  835. if (focusScale.Y < 0)
  836. {
  837. focusScale.Y = 0;
  838. }
  839. shadowBrush.FocusScales = focusScale;
  840. // Draw shadow
  841. this.FillPath(shadowBrush, path);
  842. }
  843. }
  844. }
  845. this.Transform = oldMatrix;
  846. }
  847. // Create translation matrix
  848. Matrix translateMatrixShape = this.Transform.Clone();
  849. Matrix oldMatrixShape = this.Transform;
  850. this.Transform = translateMatrixShape;
  851. this.FillPolygon(brush, points);
  852. this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
  853. this.Transform = oldMatrixShape;
  854. break;
  855. }
  856. case (MarkerStyle.Diamond):
  857. {
  858. PointF[] points = new PointF[4];
  859. points[0].X = rect.X;
  860. points[0].Y = rect.Y + rect.Height / 2F;
  861. points[1].X = rect.X + rect.Width / 2F;
  862. points[1].Y = rect.Top;
  863. points[2].X = rect.Right;
  864. points[2].Y = rect.Y + rect.Height / 2F;
  865. points[3].X = rect.X + rect.Width / 2F;
  866. points[3].Y = rect.Bottom;
  867. // Draw shadow
  868. if (shadowSize != 0 && shadowColor != Color.Empty)
  869. {
  870. Matrix translateMatrix = this.Transform.Clone();
  871. translateMatrix.Translate((softShadows) ? 0 : shadowSize,
  872. (softShadows) ? 0 : shadowSize);
  873. Matrix oldMatrix = this.Transform;
  874. this.Transform = translateMatrix;
  875. if (!softShadows)
  876. {
  877. using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
  878. {
  879. this.FillPolygon(softShadowBrush, points);
  880. }
  881. }
  882. else
  883. {
  884. // Calculate diamond size
  885. float diamondSize = markerSize * (float)Math.Sin(45f / 180f * Math.PI);
  886. // Calculate diamond rectangle position
  887. RectangleF diamondRect = RectangleF.Empty;
  888. diamondRect.X = point.X - ((float)diamondSize) / 2F;
  889. diamondRect.Y = point.Y - ((float)diamondSize) / 2F - shadowSize;
  890. diamondRect.Width = diamondSize;
  891. diamondRect.Height = diamondSize;
  892. // Set rotation matrix to 45
  893. translateMatrix.RotateAt(45, point);
  894. this.Transform = translateMatrix;
  895. FillRectangleShadowAbs(diamondRect, shadowColor, shadowSize, shadowColor);
  896. }
  897. this.Transform = oldMatrix;
  898. }
  899. this.FillPolygon(brush, points);
  900. this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
  901. break;
  902. }
  903. case (MarkerStyle.Triangle):
  904. {
  905. PointF[] points = new PointF[3];
  906. points[0].X = rect.X;
  907. points[0].Y = rect.Bottom;
  908. points[1].X = rect.X + rect.Width / 2F;
  909. points[1].Y = rect.Top;
  910. points[2].X = rect.Right;
  911. points[2].Y = rect.Bottom;
  912. // Draw image shadow
  913. if (shadowSize != 0 && shadowColor != Color.Empty)
  914. {
  915. Matrix translateMatrix = this.Transform.Clone();
  916. translateMatrix.Translate((softShadows) ? shadowSize - 1 : shadowSize,
  917. (softShadows) ? shadowSize + 1 : shadowSize);
  918. Matrix oldMatrix = this.Transform;
  919. this.Transform = translateMatrix;
  920. if (!softShadows)
  921. {
  922. using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
  923. {
  924. this.FillPolygon(softShadowBrush, points);
  925. }
  926. }
  927. else
  928. {
  929. // Add polygon to the graphics path
  930. GraphicsPath path = new GraphicsPath();
  931. path.AddPolygon(points);
  932. // Create path brush
  933. PathGradientBrush shadowBrush = new PathGradientBrush(path);
  934. shadowBrush.CenterColor = shadowColor;
  935. // Set the color along the entire boundary of the path
  936. Color[] colors = { Color.Transparent };
  937. shadowBrush.SurroundColors = colors;
  938. shadowBrush.CenterPoint = new PointF(point.X, point.Y);
  939. // Define brush focus scale
  940. PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
  941. if (focusScale.X < 0)
  942. {
  943. focusScale.X = 0;
  944. }
  945. if (focusScale.Y < 0)
  946. {
  947. focusScale.Y = 0;
  948. }
  949. shadowBrush.FocusScales = focusScale;
  950. // Draw shadow
  951. this.FillPath(shadowBrush, path);
  952. }
  953. this.Transform = oldMatrix;
  954. }
  955. this.FillPolygon(brush, points);
  956. this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
  957. break;
  958. }
  959. default:
  960. {
  961. throw (new InvalidOperationException(SR.ExceptionGraphicsMarkerStyleUnknown));
  962. }
  963. }
  964. }
  965. // Restore SmoothingMode
  966. if(forceAntiAlias)
  967. {
  968. this.SmoothingMode = oldSmoothingMode;
  969. }
  970. }
  971. }
  972. #endregion
  973. #region String Methods
  974. /// <summary>
  975. /// Measures the specified string when drawn with the specified
  976. /// Font object and formatted with the specified StringFormat object.
  977. /// </summary>
  978. /// <param name="text">String to measure.</param>
  979. /// <param name="font">Font object defines the text format of the string.</param>
  980. /// <param name="layoutArea">SizeF structure that specifies the maximum layout area for the text.</param>
  981. /// <param name="stringFormat">StringFormat object that represents formatting information, such as line spacing, for the string.</param>
  982. /// <param name="textOrientation">Text orientation.</param>
  983. /// <returns>This method returns a SizeF structure that represents the size, in pixels, of the string specified in the text parameter as drawn with the font parameter and the stringFormat parameter.</returns>
  984. internal SizeF MeasureString(
  985. string text,
  986. Font font,
  987. SizeF layoutArea,
  988. StringFormat stringFormat,
  989. TextOrientation textOrientation
  990. )
  991. {
  992. // Current implementation of the stacked text will simply insert a new
  993. // line character between all characters in the original string. This
  994. // apporach will not allow to show multiple lines of stacked text or
  995. // correctly handle text wrapping.
  996. if (textOrientation == TextOrientation.Stacked)
  997. {
  998. text = GetStackedText(text);
  999. }
  1000. return this.MeasureString(text, font, layoutArea, stringFormat);
  1001. }
  1002. /// <summary>
  1003. /// Measures the specified text string when drawn with
  1004. /// the specified Font object and formatted with the
  1005. /// specified StringFormat object.
  1006. /// </summary>
  1007. /// <param name="text">The string to measure</param>
  1008. /// <param name="font">The Font object used to determine the size of the text string. </param>
  1009. /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
  1010. /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
  1011. /// <param name="textOrientation">Text orientation.</param>
  1012. /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
  1013. internal SizeF MeasureStringRel(
  1014. string text,
  1015. Font font,
  1016. SizeF layoutArea,
  1017. StringFormat stringFormat,
  1018. TextOrientation textOrientation)
  1019. {
  1020. // Current implementation of the stacked text will simply insert a new
  1021. // line character between all characters in the original string. This
  1022. // apporach will not allow to show multiple lines of stacked text or
  1023. // correctly handle text wrapping.
  1024. if (textOrientation == TextOrientation.Stacked)
  1025. {
  1026. text = GetStackedText(text);
  1027. }
  1028. return this.MeasureStringRel(text, font, layoutArea, stringFormat);
  1029. }
  1030. /// <summary>
  1031. /// Draws the specified text string at the specified location with the specified Brush and Font objects using the formatting properties of the specified StringFormat object.
  1032. /// </summary>
  1033. /// <param name="text">String to draw.</param>
  1034. /// <param name="font">Font object that defines the text format of the string.</param>
  1035. /// <param name="brush">Brush object that determines the color and texture of the drawn text.</param>
  1036. /// <param name="rect">Position of the drawn text in pixels.</param>
  1037. /// <param name="format">StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
  1038. /// <param name="textOrientation">Text orientation.</param>
  1039. internal void DrawString(
  1040. string text,
  1041. Font font,
  1042. Brush brush,
  1043. RectangleF rect,
  1044. StringFormat format,
  1045. TextOrientation textOrientation
  1046. )
  1047. {
  1048. // Current implementation of the stacked text will simply insert a new
  1049. // line character between all characters in the original string. This
  1050. // apporach will not allow to show multiple lines of stacked text or
  1051. // correctly handle text wrapping.
  1052. if (textOrientation == TextOrientation.Stacked)
  1053. {
  1054. text = GetStackedText(text);
  1055. }
  1056. this.DrawString(text, font, brush, rect, format);
  1057. }
  1058. /// <summary>
  1059. /// Draw a string.
  1060. /// </summary>
  1061. /// <param name="text">Text.</param>
  1062. /// <param name="font">Text Font.</param>
  1063. /// <param name="brush">Text Brush.</param>
  1064. /// <param name="position">Text Position.</param>
  1065. /// <param name="format">Format and text alignment.</param>
  1066. /// <param name="angle">Text angle.</param>
  1067. /// <param name="textOrientation">Text orientation.</param>
  1068. internal void DrawStringRel(
  1069. string text,
  1070. System.Drawing.Font font,
  1071. System.Drawing.Brush brush,
  1072. PointF position,
  1073. System.Drawing.StringFormat format,
  1074. int angle,
  1075. TextOrientation textOrientation
  1076. )
  1077. {
  1078. // Current implementation of the stacked text will simply insert a new
  1079. // line character between all characters in the original string. This
  1080. // apporach will not allow to show multiple lines of stacked text or
  1081. // correctly handle text wrapping.
  1082. if (textOrientation == TextOrientation.Stacked)
  1083. {
  1084. text = GetStackedText(text);
  1085. }
  1086. this.DrawStringRel(text, font, brush, position, format, angle);
  1087. }
  1088. /// <summary>
  1089. /// Draw a string.
  1090. /// </summary>
  1091. /// <param name="text">Text.</param>
  1092. /// <param name="font">Text Font.</param>
  1093. /// <param name="brush">Text Brush.</param>
  1094. /// <param name="position">Text Position.</param>
  1095. /// <param name="format">Format and text alignment.</param>
  1096. /// <param name="textOrientation">Text orientation.</param>
  1097. internal void DrawStringRel(
  1098. string text,
  1099. System.Drawing.Font font,
  1100. System.Drawing.Brush brush,
  1101. RectangleF position,
  1102. System.Drawing.StringFormat format,
  1103. TextOrientation textOrientation
  1104. )
  1105. {
  1106. // Current implementation of the stacked text will simply insert a new
  1107. // line character between all characters in the original string. This
  1108. // apporach will not allow to show multiple lines of stacked text or
  1109. // correctly handle text wrapping.
  1110. if (textOrientation == TextOrientation.Stacked)
  1111. {
  1112. text = GetStackedText(text);
  1113. }
  1114. this.DrawStringRel(text, font, brush, position, format);
  1115. }
  1116. /// <summary>
  1117. /// Function returned stacked text by inserting new line characters between
  1118. /// all characters in the original string.
  1119. /// </summary>
  1120. /// <param name="text">Original text.</param>
  1121. /// <returns>Stacked text.</returns>
  1122. internal static string GetStackedText(string text)
  1123. {
  1124. string result = string.Empty;
  1125. foreach (char ch in text)
  1126. {
  1127. result += ch;
  1128. if (ch != '\n')
  1129. {
  1130. result += '\n';
  1131. }
  1132. }
  1133. return result;
  1134. }
  1135. /// <summary>
  1136. /// Draw a string and fills it's background
  1137. /// </summary>
  1138. /// <param name="common">The Common elements object.</param>
  1139. /// <param name="text">Text.</param>
  1140. /// <param name="font">Text Font.</param>
  1141. /// <param name="brush">Text Brush.</param>
  1142. /// <param name="position">Text Position.</param>
  1143. /// <param name="format">Format and text alignment.</param>
  1144. /// <param name="angle">Text angle.</param>
  1145. /// <param name="backPosition">Text background position.</param>
  1146. /// <param name="backColor">Back Color</param>
  1147. /// <param name="borderColor">Border Color</param>
  1148. /// <param name="borderWidth">Border Width</param>
  1149. /// <param name="borderDashStyle">Border Style</param>
  1150. /// <param name="series">Series</param>
  1151. /// <param name="point">Point</param>
  1152. /// <param name="pointIndex">Point index in series</param>
  1153. internal void DrawPointLabelStringRel(
  1154. CommonElements common,
  1155. string text,
  1156. System.Drawing.Font font,
  1157. System.Drawing.Brush brush,
  1158. RectangleF position,
  1159. System.Drawing.StringFormat format,
  1160. int angle,
  1161. RectangleF backPosition,
  1162. Color backColor,
  1163. Color borderColor,
  1164. int borderWidth,
  1165. ChartDashStyle borderDashStyle,
  1166. Series series,
  1167. DataPoint point,
  1168. int pointIndex)
  1169. {
  1170. // Start Svg/Flash Selection mode
  1171. this.StartHotRegion( point, true );
  1172. // Draw background
  1173. DrawPointLabelBackground(
  1174. common,
  1175. angle,
  1176. PointF.Empty,
  1177. backPosition,
  1178. backColor,
  1179. borderColor,
  1180. borderWidth,
  1181. borderDashStyle,
  1182. series,
  1183. point,
  1184. pointIndex);
  1185. // End Svg/Flash Selection mode
  1186. this.EndHotRegion( );
  1187. point._lastLabelText = text;
  1188. // Draw text
  1189. if (IsRightToLeft)
  1190. {
  1191. // datapoint label alignments should appear as not RTL.
  1192. using (StringFormat fmt = (StringFormat)format.Clone())
  1193. {
  1194. if (fmt.Alignment == StringAlignment.Far)
  1195. {
  1196. fmt.Alignment = StringAlignment.Near;
  1197. }
  1198. else if (fmt.Alignment == StringAlignment.Near)
  1199. {
  1200. fmt.Alignment = StringAlignment.Far;
  1201. }
  1202. DrawStringRel(text,font,brush,position,fmt,angle);
  1203. }
  1204. }
  1205. else
  1206. DrawStringRel(text, font, brush, position, format, angle);
  1207. }
  1208. /// <summary>
  1209. /// Draw a string and fills it's background
  1210. /// </summary>
  1211. /// <param name="common">The Common elements object.</param>
  1212. /// <param name="text">Text.</param>
  1213. /// <param name="font">Text Font.</param>
  1214. /// <param name="brush">Text Brush.</param>
  1215. /// <param name="position">Text Position.</param>
  1216. /// <param name="format">Format and text alignment.</param>
  1217. /// <param name="angle">Text angle.</param>
  1218. /// <param name="backPosition">Text background position.</param>
  1219. /// <param name="backColor">Back Color</param>
  1220. /// <param name="borderColor">Border Color</param>
  1221. /// <param name="borderWidth">Border Width</param>
  1222. /// <param name="borderDashStyle">Border Style</param>
  1223. /// <param name="series">Series</param>
  1224. /// <param name="point">Point</param>
  1225. /// <param name="pointIndex">Point index in series</param>
  1226. internal void DrawPointLabelStringRel(
  1227. CommonElements common,
  1228. string text,
  1229. System.Drawing.Font font,
  1230. System.Drawing.Brush brush,
  1231. PointF position,
  1232. System.Drawing.StringFormat format,
  1233. int angle,
  1234. RectangleF backPosition,
  1235. Color backColor,
  1236. Color borderColor,
  1237. int borderWidth,
  1238. ChartDashStyle borderDashStyle,
  1239. Series series,
  1240. DataPoint point,
  1241. int pointIndex)
  1242. {
  1243. // Start Svg/Flash Selection mode
  1244. this.StartHotRegion( point, true );
  1245. // Draw background
  1246. DrawPointLabelBackground(
  1247. common,
  1248. angle,
  1249. position,
  1250. backPosition,
  1251. backColor,
  1252. borderColor,
  1253. borderWidth,
  1254. borderDashStyle,
  1255. series,
  1256. point,
  1257. pointIndex);
  1258. // End Svg/Flash Selection mode
  1259. this.EndHotRegion( );
  1260. point._lastLabelText = text;
  1261. // Draw text
  1262. if (IsRightToLeft)
  1263. {
  1264. // datapoint label alignments should appear as not RTL
  1265. using (StringFormat fmt = (StringFormat)format.Clone())
  1266. {
  1267. if (fmt.Alignment == StringAlignment.Far)
  1268. {
  1269. fmt.Alignment = StringAlignment.Near;
  1270. }
  1271. else if (fmt.Alignment == StringAlignment.Near)
  1272. {
  1273. fmt.Alignment = StringAlignment.Far;
  1274. }
  1275. DrawStringRel(text,font,brush,position,fmt,angle);
  1276. }
  1277. }
  1278. else
  1279. DrawStringRel(text,font,brush,position,format,angle);
  1280. }
  1281. /// <summary>
  1282. /// Draw a string and fills it's background
  1283. /// </summary>
  1284. /// <param name="common">The Common elements object.</param>
  1285. /// <param name="angle">Text angle.</param>
  1286. /// <param name="textPosition">Text position.</param>
  1287. /// <param name="backPosition">Text background position.</param>
  1288. /// <param name="backColor">Back Color</param>
  1289. /// <param name="borderColor">Border Color</param>
  1290. /// <param name="borderWidth">Border Width</param>
  1291. /// <param name="borderDashStyle">Border Style</param>
  1292. /// <param name="series">Series</param>
  1293. /// <param name="point">Point</param>
  1294. /// <param name="pointIndex">Point index in series</param>
  1295. private void DrawPointLabelBackground(
  1296. CommonElements common,
  1297. int angle,
  1298. PointF textPosition,
  1299. RectangleF backPosition,
  1300. Color backColor,
  1301. Color borderColor,
  1302. int borderWidth,
  1303. ChartDashStyle borderDashStyle,
  1304. Series series,
  1305. DataPoint point,
  1306. int pointIndex)
  1307. {
  1308. // Draw background
  1309. if(!backPosition.IsEmpty)
  1310. {
  1311. RectangleF backPositionAbs = this.Round(this.GetAbsoluteRectangle(backPosition));
  1312. // Get rotation point
  1313. PointF rotationPoint = PointF.Empty;
  1314. if(textPosition.IsEmpty)
  1315. {
  1316. rotationPoint = new PointF(backPositionAbs.X + backPositionAbs.Width/2f, backPositionAbs.Y + backPositionAbs.Height/2f);
  1317. }
  1318. else
  1319. {
  1320. rotationPoint = this.GetAbsolutePoint(textPosition);
  1321. }
  1322. // Create a matrix and rotate it.
  1323. _myMatrix = this.Transform.Clone();
  1324. _myMatrix.RotateAt( angle, rotationPoint );
  1325. // Save old state
  1326. IGraphicsState graphicsState = this.Save();
  1327. // Set transformatino
  1328. this.Transform = _myMatrix;
  1329. // Check for empty colors
  1330. if( !backColor.IsEmpty ||
  1331. !borderColor.IsEmpty)
  1332. {
  1333. // Fill box around the label
  1334. using(Brush brush = new SolidBrush(backColor))
  1335. {
  1336. this.FillRectangle(brush, backPositionAbs);
  1337. }
  1338. // deliant: Fix VSTS #156433 (2) Data Label Border in core always shows when the style is set to NotSet
  1339. // Draw box border
  1340. if( borderWidth > 0 &&
  1341. !borderColor.IsEmpty && borderDashStyle != ChartDashStyle.NotSet)
  1342. {
  1343. AntiAliasingStyles saveAntiAliasing = this.AntiAliasing;
  1344. try
  1345. {
  1346. this.AntiAliasing = AntiAliasingStyles.None;
  1347. using(Pen pen = new Pen(borderColor, borderWidth))
  1348. {
  1349. pen.DashStyle = GetPenStyle( borderDashStyle );
  1350. this.DrawRectangle(
  1351. pen,
  1352. backPositionAbs.X,
  1353. backPositionAbs.Y,
  1354. backPositionAbs.Width,
  1355. backPositionAbs.Height);
  1356. }
  1357. }
  1358. finally
  1359. {
  1360. this.AntiAliasing = saveAntiAliasing;
  1361. }
  1362. }
  1363. }
  1364. else
  1365. {
  1366. // Draw invisible rectangle to handle tooltips
  1367. using(Brush brush = new SolidBrush(Color.Transparent))
  1368. {
  1369. this.FillRectangle(brush, backPositionAbs);
  1370. }
  1371. }
  1372. // Restore old state
  1373. this.Restore(graphicsState);
  1374. // Add point label hot region
  1375. if( common != null &&
  1376. common.ProcessModeRegions)
  1377. {
  1378. // Insert area
  1379. if(angle == 0)
  1380. {
  1381. common.HotRegionsList.AddHotRegion(
  1382. backPosition,
  1383. point,
  1384. series.Name,
  1385. pointIndex );
  1386. }
  1387. else
  1388. {
  1389. // Convert rectangle to the graphics path and apply rotation transformation
  1390. using (GraphicsPath path = new GraphicsPath())
  1391. {
  1392. path.AddRectangle(backPositionAbs);
  1393. path.Transform(_myMatrix);
  1394. // Add hot region
  1395. common.HotRegionsList.AddHotRegion(
  1396. path,
  1397. false,
  1398. this,
  1399. point,
  1400. series.Name,
  1401. pointIndex);
  1402. }
  1403. }
  1404. // Set new hot region element type
  1405. if (common.HotRegionsList.List != null && common.HotRegionsList.List.Count > 0)
  1406. {
  1407. ((HotRegion)common.HotRegionsList.List[common.HotRegionsList.List.Count - 1]).Type =
  1408. ChartElementType.DataPointLabel;
  1409. }
  1410. }
  1411. }
  1412. }
  1413. /// <summary>
  1414. /// Draw a string.
  1415. /// </summary>
  1416. /// <param name="text">Text.</param>
  1417. /// <param name="font">Text Font.</param>
  1418. /// <param name="brush">Text Brush.</param>
  1419. /// <param name="position">Text Position.</param>
  1420. /// <param name="format">Format and text alignment.</param>
  1421. /// <param name="angle">Text angle.</param>
  1422. internal void DrawStringRel(
  1423. string text,
  1424. System.Drawing.Font font,
  1425. System.Drawing.Brush brush,
  1426. PointF position,
  1427. System.Drawing.StringFormat format,
  1428. int angle
  1429. )
  1430. {
  1431. DrawStringAbs(
  1432. text,
  1433. font,
  1434. brush,
  1435. GetAbsolutePoint(position),
  1436. format,
  1437. angle);
  1438. }
  1439. /// <summary>
  1440. /// Draw a string.
  1441. /// </summary>
  1442. /// <param name="text">Text.</param>
  1443. /// <param name="font">Text Font.</param>
  1444. /// <param name="brush">Text Brush.</param>
  1445. /// <param name="absPosition">Text Position.</param>
  1446. /// <param name="format">Format and text alignment.</param>
  1447. /// <param name="angle">Text angle.</param>
  1448. internal void DrawStringAbs(
  1449. string text,
  1450. System.Drawing.Font font,
  1451. System.Drawing.Brush brush,
  1452. PointF absPosition,
  1453. System.Drawing.StringFormat format,
  1454. int angle
  1455. )
  1456. {
  1457. // Create a matrix and rotate it.
  1458. _myMatrix = this.Transform.Clone();
  1459. _myMatrix.RotateAt(angle, absPosition);
  1460. // Save aold state
  1461. IGraphicsState graphicsState = this.Save();
  1462. // Set Angle
  1463. this.Transform = _myMatrix;
  1464. // Draw text with anti-aliasing
  1465. /*
  1466. if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
  1467. this.TextRenderingHint = TextRenderingHint.AntiAlias;
  1468. else
  1469. this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  1470. */
  1471. // Draw a string
  1472. this.DrawString( text, font, brush, absPosition , format );
  1473. // Restore old state
  1474. this.Restore(graphicsState);
  1475. }
  1476. /// <summary>
  1477. /// This method is used by the axis title hot region generation code.
  1478. /// It transforms the centered rectangle the same way as the Axis title text.
  1479. /// </summary>
  1480. /// <param name="center">Title center</param>
  1481. /// <param name="size">Title text size</param>
  1482. /// <param name="angle">Title rotation angle</param>
  1483. /// <returns></returns>
  1484. internal GraphicsPath GetTranformedTextRectPath(PointF center, SizeF size, int angle)
  1485. {
  1486. // Text hot area is 10px greater than the size of text
  1487. size.Width += 10;
  1488. size.Height += 10;
  1489. // Get the absolute center and create the centered rectangle points
  1490. PointF absCenter = GetAbsolutePoint(center);
  1491. PointF[] points = new PointF[] {
  1492. new PointF(absCenter.X - size.Width / 2f, absCenter.Y - size.Height / 2f),
  1493. new PointF(absCenter.X + size.Width / 2f, absCenter.Y - size.Height / 2f),
  1494. new PointF(absCenter.X + size.Width / 2f, absCenter.Y + size.Height / 2f),
  1495. new PointF(absCenter.X - size.Width / 2f, absCenter.Y + size.Height / 2f)};
  1496. //Prepare the same tranformation matrix as used for the axis title
  1497. Matrix matrix = this.Transform.Clone();
  1498. matrix.RotateAt(angle, absCenter);
  1499. //Tranform the rectangle points
  1500. matrix.TransformPoints(points);
  1501. //Return the path consisting of the rect points
  1502. GraphicsPath path = new GraphicsPath();
  1503. path.AddLines(points);
  1504. path.CloseAllFigures();
  1505. return path;
  1506. }
  1507. /// <summary>
  1508. /// Draw label string.
  1509. /// </summary>
  1510. /// <param name="axis">Label axis.</param>
  1511. /// <param name="labelRowIndex">Label text row index (0-10).</param>
  1512. /// <param name="labelMark">Second row labels mark style.</param>
  1513. /// <param name="markColor">Label mark line color.</param>
  1514. /// <param name="text">Label text.</param>
  1515. /// <param name="image">Label image name.</param>
  1516. /// <param name="imageTransparentColor">Label image transparent color.</param>
  1517. /// <param name="font">Text bont.</param>
  1518. /// <param name="brush">Text brush.</param>
  1519. /// <param name="position">Text position rectangle.</param>
  1520. /// <param name="format">Label text format.</param>
  1521. /// <param name="angle">Label text angle.</param>
  1522. /// <param name="boundaryRect">Specifies the rectangle where the label text MUST be fitted.</param>
  1523. /// <param name="label">Custom Label Item</param>
  1524. /// <param name="truncatedLeft">Label is truncated on the left.</param>
  1525. /// <param name="truncatedRight">Label is truncated on the right.</param>
  1526. internal void DrawLabelStringRel(
  1527. Axis axis,
  1528. int labelRowIndex,
  1529. LabelMarkStyle labelMark,
  1530. Color markColor,
  1531. string text,
  1532. string image,
  1533. Color imageTransparentColor,
  1534. System.Drawing.Font font,
  1535. System.Drawing.Brush brush,
  1536. RectangleF position,
  1537. System.Drawing.StringFormat format,
  1538. int angle,
  1539. RectangleF boundaryRect,
  1540. CustomLabel label,
  1541. bool truncatedLeft,
  1542. bool truncatedRight)
  1543. {
  1544. Matrix oldTransform;
  1545. using (StringFormat drawingFormat = (StringFormat)format.Clone())
  1546. {
  1547. SizeF labelSize = SizeF.Empty;
  1548. // Check that rectangle is not empty
  1549. if (position.Width == 0 || position.Height == 0)
  1550. {
  1551. return;
  1552. }
  1553. // Find absolute position
  1554. RectangleF absPosition = this.GetAbsoluteRectangle(position);
  1555. // Make sure the rectangle is not empty
  1556. if (absPosition.Width < 1f)
  1557. {
  1558. absPosition.Width = 1f;
  1559. }
  1560. if (absPosition.Height < 1f)
  1561. {
  1562. absPosition.Height = 1f;
  1563. }
  1564. #if DEBUG
  1565. // TESTING CODE: Shows labels rectangle position.
  1566. // Rectangle rr = Rectangle.Round(absPosition);
  1567. // rr.Width = (int)Math.Round(absPosition.Right) - rr.X;
  1568. // rr.Height = (int)Math.Round(absPosition.Bottom) - rr.Y;
  1569. // this.DrawRectangle(Pens.Red,rr.X, rr.Y, rr.Width, rr.Height);
  1570. #endif // DEBUG
  1571. CommonElements common = axis.Common;
  1572. if (common.ProcessModeRegions)
  1573. {
  1574. common.HotRegionsList.AddHotRegion(Rectangle.Round(absPosition), label, ChartElementType.AxisLabels, false, true);
  1575. }
  1576. //********************************************************************
  1577. //** Draw labels in the second row
  1578. //********************************************************************
  1579. if (labelRowIndex > 0)
  1580. {
  1581. drawingFormat.LineAlignment = StringAlignment.Center;
  1582. drawingFormat.Alignment = StringAlignment.Center;
  1583. angle = 0;
  1584. if (axis.AxisPosition == AxisPosition.Left)
  1585. {
  1586. angle = -90;
  1587. }
  1588. else if (axis.AxisPosition == AxisPosition.Right)
  1589. {
  1590. angle = 90;
  1591. }
  1592. else if (axis.AxisPosition == AxisPosition.Top)
  1593. {
  1594. }
  1595. else if (axis.AxisPosition == AxisPosition.Bottom)
  1596. {
  1597. }
  1598. }
  1599. //********************************************************************
  1600. //** Calculate rotation point
  1601. //********************************************************************
  1602. PointF rotationPoint = PointF.Empty;
  1603. if (axis.AxisPosition == AxisPosition.Left)
  1604. {
  1605. rotationPoint.X = absPosition.Right;
  1606. rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
  1607. }
  1608. else if (axis.AxisPosition == AxisPosition.Right)
  1609. {
  1610. rotationPoint.X = absPosition.Left;
  1611. rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
  1612. }
  1613. else if (axis.AxisPosition == AxisPosition.Top)
  1614. {
  1615. rotationPoint.X = absPosition.X + absPosition.Width / 2F;
  1616. rotationPoint.Y = absPosition.Bottom;
  1617. }
  1618. else if (axis.AxisPosition == AxisPosition.Bottom)
  1619. {
  1620. rotationPoint.X = absPosition.X + absPosition.Width / 2F;
  1621. rotationPoint.Y = absPosition.Top;
  1622. }
  1623. //********************************************************************
  1624. //** Adjust rectangle for horisontal axis
  1625. //********************************************************************
  1626. if ((axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) &&
  1627. angle != 0)
  1628. {
  1629. // Get rectangle center
  1630. rotationPoint.X = absPosition.X + absPosition.Width / 2F;
  1631. rotationPoint.Y = (axis.AxisPosition == AxisPosition.Top) ? absPosition.Bottom : absPosition.Y;
  1632. // Rotate rectangle 90 degrees
  1633. RectangleF newRect = RectangleF.Empty;
  1634. newRect.X = absPosition.X + absPosition.Width / 2F;
  1635. newRect.Y = absPosition.Y - absPosition.Width / 2F;
  1636. newRect.Height = absPosition.Width;
  1637. newRect.Width = absPosition.Height;
  1638. // Adjust values for bottom axis
  1639. if (axis.AxisPosition == AxisPosition.Bottom)
  1640. {
  1641. if (angle < 0)
  1642. {
  1643. newRect.X -= newRect.Width;
  1644. }
  1645. // Replace string alignment
  1646. drawingFormat.Alignment = StringAlignment.Near;
  1647. if (angle < 0)
  1648. {
  1649. drawingFormat.Alignment = StringAlignment.Far;
  1650. }
  1651. drawingFormat.LineAlignment = StringAlignment.Center;
  1652. }
  1653. // Adjust values for bottom axis
  1654. if (axis.AxisPosition == AxisPosition.Top)
  1655. {
  1656. newRect.Y += absPosition.Height;
  1657. if (angle > 0)
  1658. {
  1659. newRect.X -= newRect.Width;
  1660. }
  1661. // Replace string alignment
  1662. drawingFormat.Alignment = StringAlignment.Far;
  1663. if (angle < 0)
  1664. {
  1665. drawingFormat.Alignment = StringAlignment.Near;
  1666. }
  1667. drawingFormat.LineAlignment = StringAlignment.Center;
  1668. }
  1669. // Set new label rect
  1670. absPosition = newRect;
  1671. }
  1672. //********************************************************************
  1673. //** 90 degrees is a special case for vertical axes
  1674. //********************************************************************
  1675. if ((axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) &&
  1676. (angle == 90 || angle == -90))
  1677. {
  1678. // Get rectangle center
  1679. rotationPoint.X = absPosition.X + absPosition.Width / 2F;
  1680. rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
  1681. // Rotate rectangle 90 degrees
  1682. RectangleF newRect = RectangleF.Empty;
  1683. newRect.X = rotationPoint.X - absPosition.Height / 2F;
  1684. newRect.Y = rotationPoint.Y - absPosition.Width / 2F;
  1685. newRect.Height = absPosition.Width;
  1686. newRect.Width = absPosition.Height;
  1687. absPosition = newRect;
  1688. // Replace string alignment
  1689. StringAlignment align = drawingFormat.Alignment;
  1690. drawingFormat.Alignment = drawingFormat.LineAlignment;
  1691. drawingFormat.LineAlignment = align;
  1692. if (angle == 90)
  1693. {
  1694. if (drawingFormat.LineAlignment == StringAlignment.Far)
  1695. drawingFormat.LineAlignment = StringAlignment.Near;
  1696. else if (drawingFormat.LineAlignment == StringAlignment.Near)
  1697. drawingFormat.LineAlignment = StringAlignment.Far;
  1698. }
  1699. if (angle == -90)
  1700. {
  1701. if (drawingFormat.Alignment == StringAlignment.Far)
  1702. drawingFormat.Alignment = StringAlignment.Near;
  1703. else if (drawingFormat.Alignment == StringAlignment.Near)
  1704. drawingFormat.Alignment = StringAlignment.Far;
  1705. }
  1706. }
  1707. //********************************************************************
  1708. //** Create a matrix and rotate it.
  1709. //********************************************************************
  1710. oldTransform = null;
  1711. if (angle != 0)
  1712. {
  1713. _myMatrix = this.Transform.Clone();
  1714. _myMatrix.RotateAt(angle, rotationPoint);
  1715. // Old angle
  1716. oldTransform = this.Transform;
  1717. // Set Angle
  1718. this.Transform = _myMatrix;
  1719. }
  1720. //********************************************************************
  1721. //** Measure string exact rectangle and adjust label bounding rectangle
  1722. //********************************************************************
  1723. RectangleF labelRect = Rectangle.Empty;
  1724. float offsetY = 0f;
  1725. float offsetX = 0f;
  1726. // Measure text size
  1727. labelSize = this.MeasureString(text.Replace("\\n", "\n"), font, absPosition.Size, drawingFormat);
  1728. // Calculate text rectangle
  1729. labelRect.Width = labelSize.Width;
  1730. labelRect.Height = labelSize.Height;
  1731. if (drawingFormat.Alignment == StringAlignment.Far)
  1732. {
  1733. labelRect.X = absPosition.Right - labelSize.Width;
  1734. }
  1735. else if (drawingFormat.Alignment == StringAlignment.Near)
  1736. {
  1737. labelRect.X = absPosition.X;
  1738. }
  1739. else if (drawingFormat.Alignment == StringAlignment.Center)
  1740. {
  1741. labelRect.X = absPosition.X + absPosition.Width / 2F - labelSize.Width / 2F;
  1742. }
  1743. if (drawingFormat.LineAlignment == StringAlignment.Far)
  1744. {
  1745. labelRect.Y = absPosition.Bottom - labelSize.Height;
  1746. }
  1747. else if (drawingFormat.LineAlignment == StringAlignment.Near)
  1748. {
  1749. labelRect.Y = absPosition.Y;
  1750. }
  1751. else if (drawingFormat.LineAlignment == StringAlignment.Center)
  1752. {
  1753. labelRect.Y = absPosition.Y + absPosition.Height / 2F - labelSize.Height / 2F;
  1754. }
  1755. //If the angle is not vertical or horizontal
  1756. if (angle != 0 && angle != 90 && angle != -90)
  1757. {
  1758. // Adjust label rectangle so it will not overlap the plotting area
  1759. offsetY = (float)Math.Sin((90 - angle) / 180F * Math.PI) * labelRect.Height / 2F;
  1760. offsetX = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * labelRect.Height / 2F;
  1761. if (axis.AxisPosition == AxisPosition.Left)
  1762. {
  1763. _myMatrix.Translate(-offsetX, 0);
  1764. }
  1765. else if (axis.AxisPosition == AxisPosition.Right)
  1766. {
  1767. _myMatrix.Translate(offsetX, 0);
  1768. }
  1769. else if (axis.AxisPosition == AxisPosition.Top)
  1770. {
  1771. _myMatrix.Translate(0, -offsetY);
  1772. }
  1773. else if (axis.AxisPosition == AxisPosition.Bottom)
  1774. {
  1775. _myMatrix.Translate(0, offsetY);
  1776. }
  1777. // Adjust label rectangle so it will be inside boundary
  1778. if (boundaryRect != RectangleF.Empty)
  1779. {
  1780. Region region = new Region(labelRect);
  1781. region.Transform(_myMatrix);
  1782. // Extend boundary rectangle to the chart picture border
  1783. if (axis.AxisPosition == AxisPosition.Left)
  1784. {
  1785. boundaryRect.Width += boundaryRect.X;
  1786. boundaryRect.X = 0;
  1787. }
  1788. else if (axis.AxisPosition == AxisPosition.Right)
  1789. {
  1790. boundaryRect.Width = this._common.Width - boundaryRect.X;
  1791. }
  1792. else if (axis.AxisPosition == AxisPosition.Top)
  1793. {
  1794. boundaryRect.Height += boundaryRect.Y;
  1795. boundaryRect.Y = 0;
  1796. }
  1797. else if (axis.AxisPosition == AxisPosition.Bottom)
  1798. {
  1799. boundaryRect.Height = this._common.Height - boundaryRect.Y;
  1800. }
  1801. // Exclude boundary rectangle from the label rectangle
  1802. region.Exclude(this.GetAbsoluteRectangle(boundaryRect));
  1803. // If any part of the label was outside bounding rectangle
  1804. if (!region.IsEmpty(Graphics.Graphics))
  1805. {
  1806. this.Transform = oldTransform;
  1807. RectangleF truncateRect = region.GetBounds(Graphics.Graphics);
  1808. float sizeChange = truncateRect.Width / (float)Math.Cos(Math.Abs(angle) / 180F * Math.PI);
  1809. if (axis.AxisPosition == AxisPosition.Left)
  1810. {
  1811. sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
  1812. absPosition.Y = labelRect.Y;
  1813. absPosition.X = labelRect.X + sizeChange;
  1814. absPosition.Width = labelRect.Width - sizeChange;
  1815. absPosition.Height = labelRect.Height;
  1816. }
  1817. else if (axis.AxisPosition == AxisPosition.Right)
  1818. {
  1819. sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
  1820. absPosition.Y = labelRect.Y;
  1821. absPosition.X = labelRect.X;
  1822. absPosition.Width = labelRect.Width - sizeChange;
  1823. absPosition.Height = labelRect.Height;
  1824. }
  1825. else if (axis.AxisPosition == AxisPosition.Top)
  1826. {
  1827. absPosition.Y = labelRect.Y;
  1828. absPosition.X = labelRect.X;
  1829. absPosition.Width = labelRect.Width - sizeChange;
  1830. absPosition.Height = labelRect.Height;
  1831. if (angle > 0)
  1832. {
  1833. absPosition.X += sizeChange;
  1834. }
  1835. }
  1836. else if (axis.AxisPosition == AxisPosition.Bottom)
  1837. {
  1838. absPosition.Y = labelRect.Y;
  1839. absPosition.X = labelRect.X;
  1840. absPosition.Width = labelRect.Width - sizeChange;
  1841. absPosition.Height = labelRect.Height;
  1842. if (angle < 0)
  1843. {
  1844. absPosition.X += sizeChange;
  1845. }
  1846. }
  1847. }
  1848. }
  1849. // Update transformation matrix
  1850. this.Transform = _myMatrix;
  1851. }
  1852. //********************************************************************
  1853. //** Reserve space on the left for the label iamge
  1854. //********************************************************************
  1855. RectangleF absPositionWithoutImage = new RectangleF(absPosition.Location, absPosition.Size);
  1856. System.Drawing.Image labelImage = null;
  1857. SizeF imageAbsSize = new SizeF();
  1858. if (image.Length > 0)
  1859. {
  1860. labelImage = axis.Common.ImageLoader.LoadImage(label.Image);
  1861. if (labelImage != null)
  1862. {
  1863. ImageLoader.GetAdjustedImageSize(labelImage, this.Graphics, ref imageAbsSize);
  1864. // Adjust label position using image size
  1865. absPositionWithoutImage.Width -= imageAbsSize.Width;
  1866. absPositionWithoutImage.X += imageAbsSize.Width;
  1867. }
  1868. if (absPositionWithoutImage.Width < 1f)
  1869. {
  1870. absPositionWithoutImage.Width = 1f;
  1871. }
  1872. }
  1873. //********************************************************************
  1874. //** Draw tick marks for labels in second row
  1875. //********************************************************************
  1876. if (labelRowIndex > 0 && labelMark != LabelMarkStyle.None)
  1877. {
  1878. // Make sure that me know the exact size of the text
  1879. labelSize = this.MeasureString(
  1880. text.Replace("\\n", "\n"),
  1881. font,
  1882. absPositionWithoutImage.Size,
  1883. drawingFormat);
  1884. // Adjust for label image
  1885. SizeF labelSizeWithImage = new SizeF(labelSize.Width, labelSize.Height);
  1886. if (labelImage != null)
  1887. {
  1888. labelSizeWithImage.Width += imageAbsSize.Width;
  1889. }
  1890. // Draw mark
  1891. DrawSecondRowLabelMark(
  1892. axis,
  1893. markColor,
  1894. absPosition,
  1895. labelSizeWithImage,
  1896. labelMark,
  1897. truncatedLeft,
  1898. truncatedRight,
  1899. oldTransform);
  1900. }
  1901. //********************************************************************
  1902. //** Make sure that one line label will not disapear with LineLimit
  1903. //** flag on.
  1904. //********************************************************************
  1905. if ((drawingFormat.FormatFlags & StringFormatFlags.LineLimit) != 0)
  1906. {
  1907. // Measure string height out of one character
  1908. drawingFormat.FormatFlags ^= StringFormatFlags.LineLimit;
  1909. SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
  1910. // If height of one characte is more than rectangle heigjt - remove LineLimit flag
  1911. if (size.Height < absPosition.Height)
  1912. {
  1913. drawingFormat.FormatFlags |= StringFormatFlags.LineLimit;
  1914. }
  1915. }
  1916. else
  1917. {
  1918. // Set NoClip flag
  1919. if ((drawingFormat.FormatFlags & StringFormatFlags.NoClip) != 0)
  1920. {
  1921. drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
  1922. }
  1923. // Measure string height out of one character without clipping
  1924. SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
  1925. // Clear NoClip flag
  1926. drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
  1927. // If height of one characte is more than rectangle heigt - set NoClip flag
  1928. if (size.Height > absPosition.Height)
  1929. {
  1930. float delta = size.Height - absPosition.Height;
  1931. absPosition.Y -= delta / 2f;
  1932. absPosition.Height += delta;
  1933. }
  1934. }
  1935. //********************************************************************
  1936. //** Draw a string
  1937. //********************************************************************
  1938. if (IsRightToLeft)
  1939. {
  1940. // label alignment on the axis should appear as not RTL.
  1941. using (StringFormat fmt = (StringFormat)drawingFormat.Clone())
  1942. {
  1943. if (fmt.Alignment == StringAlignment.Far)
  1944. {
  1945. fmt.Alignment = StringAlignment.Near;
  1946. }
  1947. else if (fmt.Alignment == StringAlignment.Near)
  1948. {
  1949. fmt.Alignment = StringAlignment.Far;
  1950. }
  1951. this.DrawString(text.Replace("\\n", "\n"), font, brush,
  1952. absPositionWithoutImage,
  1953. fmt);
  1954. }
  1955. }
  1956. else
  1957. this.DrawString(text.Replace("\\n", "\n"), font, brush,
  1958. absPositionWithoutImage,
  1959. drawingFormat);
  1960. // Add separate hot region for the label
  1961. if (common.ProcessModeRegions)
  1962. {
  1963. using (GraphicsPath path = new GraphicsPath())
  1964. {
  1965. path.AddRectangle(labelRect);
  1966. path.Transform(this.Transform);
  1967. string url = string.Empty;
  1968. string mapAreaAttributes = string.Empty;
  1969. string postbackValue = string.Empty;
  1970. common.HotRegionsList.AddHotRegion(
  1971. this,
  1972. path,
  1973. false,
  1974. label.ToolTip,
  1975. url,
  1976. mapAreaAttributes,
  1977. postbackValue,
  1978. label,
  1979. ChartElementType.AxisLabels);
  1980. }
  1981. }
  1982. //********************************************************************
  1983. //** Draw an image
  1984. //********************************************************************
  1985. if (labelImage != null)
  1986. {
  1987. // Make sure we no the text size
  1988. if (labelSize.IsEmpty)
  1989. {
  1990. labelSize = this.MeasureString(
  1991. text.Replace("\\n", "\n"),
  1992. font,
  1993. absPositionWithoutImage.Size,
  1994. drawingFormat);
  1995. }
  1996. // Calculate image rectangle
  1997. RectangleF imageRect = new RectangleF(
  1998. absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2,
  1999. absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2,
  2000. imageAbsSize.Width,
  2001. imageAbsSize.Height);
  2002. if (drawingFormat.LineAlignment == StringAlignment.Center)
  2003. {
  2004. imageRect.Y = absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2;
  2005. }
  2006. else if (drawingFormat.LineAlignment == StringAlignment.Far)
  2007. {
  2008. imageRect.Y = absPosition.Bottom - (labelSize.Height + imageAbsSize.Height) / 2;
  2009. }
  2010. else if (drawingFormat.LineAlignment == StringAlignment.Near)
  2011. {
  2012. imageRect.Y = absPosition.Top + (labelSize.Height - imageAbsSize.Height) / 2;
  2013. }
  2014. if (drawingFormat.Alignment == StringAlignment.Center)
  2015. {
  2016. imageRect.X = absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2;
  2017. }
  2018. else if (drawingFormat.Alignment == StringAlignment.Far)
  2019. {
  2020. imageRect.X = absPosition.Right - imageAbsSize.Width - labelSize.Width;
  2021. }
  2022. else if (drawingFormat.Alignment == StringAlignment.Near)
  2023. {
  2024. imageRect.X = absPosition.X;
  2025. }
  2026. // Create image attribute
  2027. ImageAttributes attrib = new ImageAttributes();
  2028. if (imageTransparentColor != Color.Empty)
  2029. {
  2030. attrib.SetColorKey(imageTransparentColor, imageTransparentColor, ColorAdjustType.Default);
  2031. }
  2032. // Draw image
  2033. this.DrawImage(
  2034. labelImage,
  2035. Rectangle.Round(imageRect),
  2036. 0, 0, labelImage.Width, labelImage.Height,
  2037. GraphicsUnit.Pixel,
  2038. attrib);
  2039. // Add separate hot region for the label image
  2040. if (common.ProcessModeRegions)
  2041. {
  2042. using (GraphicsPath path = new GraphicsPath())
  2043. {
  2044. path.AddRectangle(imageRect);
  2045. path.Transform(this.Transform);
  2046. string imageUrl = string.Empty;
  2047. string imageMapAreaAttributes = string.Empty;
  2048. string postbackValue = string.Empty;
  2049. common.HotRegionsList.AddHotRegion(
  2050. this,
  2051. path,
  2052. false,
  2053. string.Empty,
  2054. imageUrl,
  2055. imageMapAreaAttributes,
  2056. postbackValue,
  2057. label,
  2058. ChartElementType.AxisLabelImage);
  2059. }
  2060. }
  2061. }
  2062. }
  2063. // Set Old Angle
  2064. if(oldTransform != null)
  2065. {
  2066. this.Transform = oldTransform;
  2067. }
  2068. }
  2069. /// <summary>
  2070. /// Draw box marks for the labels in second row
  2071. /// </summary>
  2072. /// <param name="axis">Axis object.</param>
  2073. /// <param name="markColor">Label mark color.</param>
  2074. /// <param name="absPosition">Absolute position of the text.</param>
  2075. /// <param name="truncatedLeft">Label is truncated on the left.</param>
  2076. /// <param name="truncatedRight">Label is truncated on the right.</param>
  2077. /// <param name="originalTransform">Original transformation matrix.</param>
  2078. private void DrawSecondRowLabelBoxMark(
  2079. Axis axis,
  2080. Color markColor,
  2081. RectangleF absPosition,
  2082. bool truncatedLeft,
  2083. bool truncatedRight,
  2084. Matrix originalTransform)
  2085. {
  2086. // Remeber current and then reset original matrix
  2087. Matrix curentMatrix = this.Transform;
  2088. if(originalTransform != null)
  2089. {
  2090. this.Transform = originalTransform;
  2091. }
  2092. // Calculate center of the text rectangle
  2093. PointF centerNotRound = new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F);
  2094. // Rotate rectangle 90 degrees
  2095. if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
  2096. {
  2097. RectangleF newRect = RectangleF.Empty;
  2098. newRect.X = centerNotRound.X - absPosition.Height / 2F;
  2099. newRect.Y = centerNotRound.Y - absPosition.Width / 2F;
  2100. newRect.Height = absPosition.Width;
  2101. newRect.Width = absPosition.Height;
  2102. absPosition = newRect;
  2103. }
  2104. // Get axis position
  2105. float axisPosRelative = (float)axis.GetAxisPosition(true);
  2106. PointF axisPositionAbs = new PointF(axisPosRelative, axisPosRelative);
  2107. axisPositionAbs = this.GetAbsolutePoint(axisPositionAbs);
  2108. // Round position to achieve crisp lines with antialiasing
  2109. Rectangle absPositionRounded = Rectangle.Round(absPosition);
  2110. // Make sure the right and bottom position is not shifted during rounding
  2111. absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
  2112. absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
  2113. // Create pen
  2114. Pen markPen = new Pen(
  2115. (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor,
  2116. axis.MajorTickMark.LineWidth);
  2117. // Set pen style
  2118. markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
  2119. // Draw top/bottom lines
  2120. if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
  2121. {
  2122. this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Left, absPositionRounded.Bottom);
  2123. this.DrawLine(markPen, absPositionRounded.Right, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Bottom);
  2124. }
  2125. else
  2126. {
  2127. this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Top);
  2128. this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Bottom, absPositionRounded.Right, absPositionRounded.Bottom);
  2129. }
  2130. // Draw left line
  2131. if(!truncatedLeft)
  2132. {
  2133. if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
  2134. {
  2135. this.DrawLine(
  2136. markPen,
  2137. (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right,
  2138. absPositionRounded.Bottom,
  2139. axisPositionAbs.X,
  2140. absPositionRounded.Bottom);
  2141. }
  2142. else
  2143. {
  2144. this.DrawLine(
  2145. markPen,
  2146. absPositionRounded.Left,
  2147. (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom,
  2148. absPositionRounded.Left,
  2149. axisPositionAbs.Y);
  2150. }
  2151. }
  2152. // Draw right line
  2153. if(!truncatedRight)
  2154. {
  2155. if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
  2156. {
  2157. this.DrawLine(
  2158. markPen,
  2159. (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right,
  2160. absPositionRounded.Top,
  2161. axisPositionAbs.X,
  2162. absPositionRounded.Top);
  2163. }
  2164. else
  2165. {
  2166. this.DrawLine(
  2167. markPen,
  2168. absPositionRounded.Right,
  2169. (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom,
  2170. absPositionRounded.Right,
  2171. axisPositionAbs.Y);
  2172. }
  2173. }
  2174. // Dispose Pen
  2175. if( markPen != null )
  2176. {
  2177. markPen.Dispose();
  2178. }
  2179. // Restore currentmatrix
  2180. if(originalTransform != null)
  2181. {
  2182. this.Transform = curentMatrix;
  2183. }
  2184. }
  2185. /// <summary>
  2186. /// Draw marks for the labels in second row
  2187. /// </summary>
  2188. /// <param name="axis">Axis object.</param>
  2189. /// <param name="markColor">Label mark color.</param>
  2190. /// <param name="absPosition">Absolute position of the text.</param>
  2191. /// <param name="labelSize">Exact mesured size of the text.</param>
  2192. /// <param name="labelMark">Label mark style to draw.</param>
  2193. /// <param name="truncatedLeft">Label is truncated on the left.</param>
  2194. /// <param name="truncatedRight">Label is truncated on the right.</param>
  2195. /// <param name="oldTransform">Original transformation matrix.</param>
  2196. private void DrawSecondRowLabelMark(
  2197. Axis axis,
  2198. Color markColor,
  2199. RectangleF absPosition,
  2200. SizeF labelSize,
  2201. LabelMarkStyle labelMark,
  2202. bool truncatedLeft,
  2203. bool truncatedRight,
  2204. Matrix oldTransform)
  2205. {
  2206. // Do not draw marking line if width is 0 and style or color are not set
  2207. if( axis.MajorTickMark.LineWidth == 0 ||
  2208. axis.MajorTickMark.LineDashStyle == ChartDashStyle.NotSet ||
  2209. axis.MajorTickMark.LineColor == Color.Empty)
  2210. {
  2211. return;
  2212. }
  2213. // Remember SmoothingMode and turn off anti aliasing for
  2214. // vertical or horizontal lines of the label markers.
  2215. SmoothingMode oldSmoothingMode = this.SmoothingMode;
  2216. this.SmoothingMode = SmoothingMode.None;
  2217. // Draw box marker
  2218. if(labelMark == LabelMarkStyle.Box)
  2219. {
  2220. DrawSecondRowLabelBoxMark(
  2221. axis,
  2222. markColor,
  2223. absPosition,
  2224. truncatedLeft,
  2225. truncatedRight,
  2226. oldTransform);
  2227. }
  2228. else
  2229. {
  2230. // Calculate center of the text rectangle
  2231. System.Drawing.Point center = System.Drawing.Point.Round(new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F));
  2232. // Round position to achieve crisp lines with antialiasing
  2233. Rectangle absPositionRounded = Rectangle.Round(absPosition);
  2234. // Make sure the right and bottom position is not shifted during rounding
  2235. absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
  2236. absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
  2237. // Arrays of points for the left and right marking lines
  2238. PointF[] leftLine = new PointF[3];
  2239. PointF[] rightLine = new PointF[3];
  2240. // Calculate marking lines coordinates
  2241. leftLine[0].X = absPositionRounded.Left;
  2242. leftLine[0].Y = absPositionRounded.Bottom;
  2243. leftLine[1].X = absPositionRounded.Left;
  2244. leftLine[1].Y = center.Y;
  2245. leftLine[2].X = (float)Math.Round((double)center.X - labelSize.Width/2F - 1F);
  2246. leftLine[2].Y = center.Y;
  2247. rightLine[0].X = absPositionRounded.Right;
  2248. rightLine[0].Y = absPositionRounded.Bottom;
  2249. rightLine[1].X = absPositionRounded.Right;
  2250. rightLine[1].Y = center.Y;
  2251. rightLine[2].X = (float)Math.Round((double)center.X + labelSize.Width/2F - 1F);
  2252. rightLine[2].Y = center.Y;
  2253. if(axis.AxisPosition == AxisPosition.Bottom)
  2254. {
  2255. leftLine[0].Y = absPositionRounded.Top;
  2256. rightLine[0].Y = absPositionRounded.Top;
  2257. }
  2258. // Remove third point to draw only side marks
  2259. if(labelMark == LabelMarkStyle.SideMark)
  2260. {
  2261. leftLine[2] = leftLine[1];
  2262. rightLine[2] = rightLine[1];
  2263. }
  2264. if(truncatedLeft)
  2265. {
  2266. leftLine[0] = leftLine[1];
  2267. }
  2268. if(truncatedRight)
  2269. {
  2270. rightLine[0] = rightLine[1];
  2271. }
  2272. // Create pen
  2273. Pen markPen = new Pen(
  2274. (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor,
  2275. axis.MajorTickMark.LineWidth);
  2276. // Set pen style
  2277. markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
  2278. // Draw marking lines
  2279. this.DrawLines(markPen, leftLine);
  2280. this.DrawLines(markPen, rightLine);
  2281. // Dispose Pen
  2282. if( markPen != null )
  2283. {
  2284. markPen.Dispose();
  2285. }
  2286. }
  2287. // Restore previous SmoothingMode
  2288. this.SmoothingMode = oldSmoothingMode;
  2289. }
  2290. /// <summary>
  2291. /// Measures the specified text string when drawn with
  2292. /// the specified Font object and formatted with the
  2293. /// specified StringFormat object.
  2294. /// </summary>
  2295. /// <param name="text">The string to measure</param>
  2296. /// <param name="font">The Font object used to determine the size of the text string. </param>
  2297. /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
  2298. internal SizeF MeasureStringRel( string text, Font font )
  2299. {
  2300. SizeF newSize;
  2301. // Measure string
  2302. newSize = this.MeasureString( text, font );
  2303. // Convert to relative Coordinates
  2304. return GetRelativeSize( newSize );
  2305. }
  2306. /// <summary>
  2307. /// Measures the specified text string when drawn with
  2308. /// the specified Font object and formatted with the
  2309. /// specified StringFormat object.
  2310. /// </summary>
  2311. /// <param name="text">The string to measure</param>
  2312. /// <param name="font">The Font object used to determine the size of the text string. </param>
  2313. /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
  2314. /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
  2315. /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
  2316. internal SizeF MeasureStringRel( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
  2317. {
  2318. SizeF size, newSize;
  2319. // Get absolute coordinates
  2320. size = GetAbsoluteSize( layoutArea );
  2321. newSize = this.MeasureString( text, font, size, stringFormat );
  2322. // Convert to relative Coordinates
  2323. return GetRelativeSize( newSize );
  2324. }
  2325. /// <summary>
  2326. /// Measures the specified text string when drawn with
  2327. /// the specified Font object and formatted with the
  2328. /// specified StringFormat object.
  2329. /// </summary>
  2330. /// <param name="text">The string to measure</param>
  2331. /// <param name="font">The Font object used to determine the size of the text string. </param>
  2332. /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
  2333. internal Size MeasureStringAbs( string text, Font font )
  2334. {
  2335. // Measure string
  2336. SizeF size = this.MeasureString( text, font );
  2337. return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
  2338. }
  2339. /// <summary>
  2340. /// Measures the specified text string when drawn with
  2341. /// the specified Font object and formatted with the
  2342. /// specified StringFormat object.
  2343. /// </summary>
  2344. /// <param name="text">The string to measure</param>
  2345. /// <param name="font">The Font object used to determine the size of the text string. </param>
  2346. /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
  2347. /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
  2348. /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
  2349. internal Size MeasureStringAbs( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
  2350. {
  2351. SizeF size = this.MeasureString( text, font, layoutArea, stringFormat );
  2352. return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
  2353. }
  2354. /// <summary>
  2355. /// Draws the specified text string at the specified location
  2356. /// with the specified Brush object and font. The formatting
  2357. /// properties in the specified StringFormat object are applied
  2358. /// to the text.
  2359. /// </summary>
  2360. /// <param name="text">A string object that specifies the text to draw.</param>
  2361. /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
  2362. /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
  2363. /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
  2364. /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
  2365. internal void DrawStringRel( string text, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format )
  2366. {
  2367. RectangleF rect;
  2368. // Check that rectangle is not empty
  2369. if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
  2370. {
  2371. return;
  2372. }
  2373. // Get absolute coordinates
  2374. rect = GetAbsoluteRectangle( layoutRectangle );
  2375. // Draw text with anti-aliasing
  2376. /*
  2377. if( (this.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
  2378. {
  2379. this.TextRenderingHint = TextRenderingHint.AntiAlias;
  2380. }
  2381. else
  2382. {
  2383. this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  2384. }
  2385. */
  2386. this.DrawString( text, font, brush, rect, format );
  2387. }
  2388. /// <summary>
  2389. /// Draws the specified text string at the specified location
  2390. /// with the specified angle and with the specified Brush object and font. The
  2391. /// formatting properties in the specified StringFormat object are applied
  2392. /// to the text.
  2393. /// </summary>
  2394. /// <param name="text">A string object that specifies the text to draw.</param>
  2395. /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
  2396. /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
  2397. /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
  2398. /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
  2399. /// <param name="angle">A angle of the text</param>
  2400. internal void DrawStringRel(
  2401. string text,
  2402. Font font,
  2403. Brush brush,
  2404. RectangleF layoutRectangle,
  2405. StringFormat format,
  2406. int angle
  2407. )
  2408. {
  2409. RectangleF rect;
  2410. SizeF size;
  2411. Matrix oldTransform;
  2412. PointF rotationCenter = PointF.Empty;
  2413. // Check that rectangle is not empty
  2414. if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
  2415. {
  2416. return;
  2417. }
  2418. // Get absolute coordinates
  2419. rect = GetAbsoluteRectangle( layoutRectangle );
  2420. size = this.MeasureString( text, font, rect.Size, format );
  2421. // Find the center of rotation
  2422. if( format.Alignment == StringAlignment.Near )
  2423. { // Near
  2424. rotationCenter.X = rect.X + size.Width / 2;
  2425. rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
  2426. }
  2427. else if( format.Alignment == StringAlignment.Far )
  2428. { // Far
  2429. rotationCenter.X = rect.Right - size.Width / 2;
  2430. rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
  2431. }
  2432. else
  2433. { // Center
  2434. rotationCenter.X = ( rect.Left + rect.Right ) / 2;
  2435. rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
  2436. }
  2437. // Create a matrix and rotate it.
  2438. _myMatrix = this.Transform.Clone();
  2439. _myMatrix.RotateAt( angle, rotationCenter);
  2440. // Old angle
  2441. oldTransform = this.Transform;
  2442. // Set Angle
  2443. this.Transform = _myMatrix;
  2444. // Draw text with anti-aliasing
  2445. /*
  2446. if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
  2447. {
  2448. this.TextRenderingHint = TextRenderingHint.AntiAlias;
  2449. }
  2450. else
  2451. {
  2452. this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  2453. }
  2454. */
  2455. this.DrawString( text, font, brush, rect, format );
  2456. // Set Old Angle
  2457. this.Transform = oldTransform;
  2458. }
  2459. #endregion
  2460. #region Rectangle Methods
  2461. /// <summary>
  2462. /// Draws different shadows to create bar styles.
  2463. /// </summary>
  2464. /// <param name="barDrawingStyle">Bar drawing style.</param>
  2465. /// <param name="isVertical">True if a vertical bar.</param>
  2466. /// <param name="rect">Rectangle position.</param>
  2467. internal void DrawRectangleBarStyle(BarDrawingStyle barDrawingStyle, bool isVertical, RectangleF rect)
  2468. {
  2469. // Check if non-default bar drawing style is specified
  2470. if(barDrawingStyle != BarDrawingStyle.Default)
  2471. {
  2472. // Check column/bar size
  2473. if(rect.Width > 0 && rect.Height > 0)
  2474. {
  2475. // Draw gradient(s)
  2476. if(barDrawingStyle == BarDrawingStyle.Cylinder)
  2477. {
  2478. // Calculate gradient position
  2479. RectangleF gradientRect = rect;
  2480. if(isVertical)
  2481. {
  2482. gradientRect.Width *= 0.3f;
  2483. }
  2484. else
  2485. {
  2486. gradientRect.Height *= 0.3f;
  2487. }
  2488. if(gradientRect.Width > 0 && gradientRect.Height > 0)
  2489. {
  2490. this.FillRectangleAbs(
  2491. gradientRect,
  2492. Color.Transparent,
  2493. ChartHatchStyle.None,
  2494. string.Empty,
  2495. ChartImageWrapMode.Scaled,
  2496. Color.Empty,
  2497. ChartImageAlignmentStyle.Center,
  2498. (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom,
  2499. Color.FromArgb(120, Color.White),
  2500. Color.Empty,
  2501. 0,
  2502. ChartDashStyle.NotSet,
  2503. PenAlignment.Inset );
  2504. if(isVertical)
  2505. {
  2506. gradientRect.X += gradientRect.Width + 1f;
  2507. gradientRect.Width = rect.Right - gradientRect.X;
  2508. }
  2509. else
  2510. {
  2511. gradientRect.Y += gradientRect.Height + 1f;
  2512. gradientRect.Height = rect.Bottom - gradientRect.Y;
  2513. }
  2514. this.FillRectangleAbs(
  2515. gradientRect,
  2516. Color.FromArgb(120, Color.White),
  2517. ChartHatchStyle.None,
  2518. string.Empty,
  2519. ChartImageWrapMode.Scaled,
  2520. Color.Empty,
  2521. ChartImageAlignmentStyle.Center,
  2522. (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom,
  2523. Color.FromArgb(150, Color.Black),
  2524. Color.Empty,
  2525. 0,
  2526. ChartDashStyle.NotSet,
  2527. PenAlignment.Inset );
  2528. }
  2529. }
  2530. else if(barDrawingStyle == BarDrawingStyle.Emboss)
  2531. {
  2532. // Calculate width of shadows used to create the effect
  2533. float shadowSize = 3f;
  2534. if(rect.Width < 6f || rect.Height < 6f)
  2535. {
  2536. shadowSize = 1f;
  2537. }
  2538. else if(rect.Width < 15f || rect.Height < 15f)
  2539. {
  2540. shadowSize = 2f;
  2541. }
  2542. // Create and draw left/top path
  2543. using(GraphicsPath path = new GraphicsPath())
  2544. {
  2545. // Add shadow polygon to the path
  2546. PointF[] points = new PointF[] {
  2547. new PointF(rect.Left, rect.Bottom),
  2548. new PointF(rect.Left, rect.Top),
  2549. new PointF(rect.Right, rect.Top),
  2550. new PointF(rect.Right - shadowSize, rect.Top + shadowSize),
  2551. new PointF(rect.Left + shadowSize, rect.Top + shadowSize),
  2552. new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize) };
  2553. path.AddPolygon(points);
  2554. // Create brush
  2555. using(SolidBrush leftTopBrush = new SolidBrush(Color.FromArgb(100, Color.White)))
  2556. {
  2557. // Fill shadow path on the left-bottom side of the bar
  2558. this.FillPath(leftTopBrush, path);
  2559. }
  2560. }
  2561. // Create and draw top/right path
  2562. using(GraphicsPath path = new GraphicsPath())
  2563. {
  2564. // Add shadow polygon to the path
  2565. PointF[] points = new PointF[] {
  2566. new PointF(rect.Right, rect.Top),
  2567. new PointF(rect.Right, rect.Bottom),
  2568. new PointF(rect.Left, rect.Bottom),
  2569. new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize),
  2570. new PointF(rect.Right - shadowSize, rect.Bottom - shadowSize),
  2571. new PointF(rect.Right - shadowSize, rect.Top + shadowSize) };
  2572. path.AddPolygon(points);
  2573. // Create brush
  2574. using(SolidBrush bottomRightBrush = new SolidBrush(Color.FromArgb(80, Color.Black)))
  2575. {
  2576. // Fill shadow path on the left-bottom side of the bar
  2577. this.FillPath(bottomRightBrush, path);
  2578. }
  2579. }
  2580. }
  2581. else if(barDrawingStyle == BarDrawingStyle.LightToDark)
  2582. {
  2583. // Calculate width of shadows used to create the effect
  2584. float shadowSize = 4f;
  2585. if(rect.Width < 6f || rect.Height < 6f)
  2586. {
  2587. shadowSize = 2f;
  2588. }
  2589. else if(rect.Width < 15f || rect.Height < 15f)
  2590. {
  2591. shadowSize = 3f;
  2592. }
  2593. // Calculate gradient position
  2594. RectangleF gradientRect = rect;
  2595. gradientRect.Inflate(-shadowSize, -shadowSize);
  2596. if(isVertical)
  2597. {
  2598. gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
  2599. }
  2600. else
  2601. {
  2602. gradientRect.X = gradientRect.Right - (float)Math.Floor(gradientRect.Width / 3f);
  2603. gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
  2604. }
  2605. if(gradientRect.Width > 0 && gradientRect.Height > 0)
  2606. {
  2607. this.FillRectangleAbs(
  2608. gradientRect,
  2609. (isVertical) ? Color.FromArgb(120, Color.White) : Color.Transparent,
  2610. ChartHatchStyle.None,
  2611. string.Empty,
  2612. ChartImageWrapMode.Scaled,
  2613. Color.Empty,
  2614. ChartImageAlignmentStyle.Center,
  2615. (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight,
  2616. (isVertical) ? Color.Transparent : Color.FromArgb(120, Color.White),
  2617. Color.Empty,
  2618. 0,
  2619. ChartDashStyle.NotSet,
  2620. PenAlignment.Inset );
  2621. gradientRect = rect;
  2622. gradientRect.Inflate(-shadowSize, -shadowSize);
  2623. if(isVertical)
  2624. {
  2625. gradientRect.Y = gradientRect.Bottom - (float)Math.Floor(gradientRect.Height / 3f);
  2626. gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
  2627. }
  2628. else
  2629. {
  2630. gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
  2631. }
  2632. this.FillRectangleAbs(
  2633. gradientRect,
  2634. (!isVertical) ? Color.FromArgb(80, Color.Black) : Color.Transparent,
  2635. ChartHatchStyle.None,
  2636. string.Empty,
  2637. ChartImageWrapMode.Scaled,
  2638. Color.Empty,
  2639. ChartImageAlignmentStyle.Center,
  2640. (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight,
  2641. (!isVertical) ? Color.Transparent : Color.FromArgb(80, Color.Black),
  2642. Color.Empty,
  2643. 0,
  2644. ChartDashStyle.NotSet,
  2645. PenAlignment.Inset );
  2646. }
  2647. }
  2648. else if(barDrawingStyle == BarDrawingStyle.Wedge)
  2649. {
  2650. // Calculate wedge size to fit the rectangle
  2651. float size = (isVertical) ? rect.Width / 2f : rect.Height / 2f;
  2652. if(isVertical && 2f * size > rect.Height)
  2653. {
  2654. size = rect.Height/2f;
  2655. }
  2656. if(!isVertical && 2f * size > rect.Width)
  2657. {
  2658. size = rect.Width/2f;
  2659. }
  2660. // Draw left/bottom shadow
  2661. RectangleF gradientRect = rect;
  2662. using(GraphicsPath path = new GraphicsPath())
  2663. {
  2664. if(isVertical)
  2665. {
  2666. path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
  2667. path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
  2668. path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Right, gradientRect.Y);
  2669. }
  2670. else
  2671. {
  2672. path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f);
  2673. path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right, gradientRect.Bottom);
  2674. path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Left, gradientRect.Bottom);
  2675. }
  2676. path.CloseAllFigures();
  2677. // Create brush and fill path
  2678. using(SolidBrush brush = new SolidBrush(Color.FromArgb(90, Color.Black)))
  2679. {
  2680. this.FillPath(brush, path);
  2681. }
  2682. }
  2683. // Draw top/right triangle
  2684. using(GraphicsPath path = new GraphicsPath())
  2685. {
  2686. if(isVertical)
  2687. {
  2688. path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size);
  2689. path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.Right, gradientRect.Y);
  2690. }
  2691. else
  2692. {
  2693. path.AddLine(gradientRect.Right, gradientRect.Y, gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f);
  2694. path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.Right, gradientRect.Bottom);
  2695. }
  2696. // Create brush and fill path
  2697. using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
  2698. {
  2699. // Fill shadow path on the left-bottom side of the bar
  2700. this.FillPath(brush, path);
  2701. // Draw Lines
  2702. using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
  2703. {
  2704. this.DrawPath(penDark, path);
  2705. if(isVertical)
  2706. {
  2707. this.DrawLine(
  2708. penDark,
  2709. rect.X + rect.Width/2f,
  2710. rect.Y + size,
  2711. rect.X + rect.Width/2f,
  2712. rect.Bottom - size);
  2713. }
  2714. else
  2715. {
  2716. this.DrawLine(
  2717. penDark,
  2718. rect.X + size,
  2719. rect.Y + rect.Height/2f,
  2720. rect.X + size,
  2721. rect.Bottom - rect.Height/2f);
  2722. }
  2723. }
  2724. // Draw Lines
  2725. using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
  2726. {
  2727. this.DrawPath(pen, path);
  2728. if(isVertical)
  2729. {
  2730. this.DrawLine(
  2731. pen,
  2732. rect.X + rect.Width/2f,
  2733. rect.Y + size,
  2734. rect.X + rect.Width/2f,
  2735. rect.Bottom - size);
  2736. }
  2737. else
  2738. {
  2739. this.DrawLine(
  2740. pen,
  2741. rect.X + size,
  2742. rect.Y + rect.Height/2f,
  2743. rect.X + size,
  2744. rect.Bottom - rect.Height/2f);
  2745. }
  2746. }
  2747. }
  2748. }
  2749. // Draw bottom/left triangle
  2750. using(GraphicsPath path = new GraphicsPath())
  2751. {
  2752. if(isVertical)
  2753. {
  2754. path.AddLine(gradientRect.X, gradientRect.Bottom, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
  2755. path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
  2756. }
  2757. else
  2758. {
  2759. path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f);
  2760. path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.X, gradientRect.Bottom);
  2761. }
  2762. // Create brush
  2763. using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
  2764. {
  2765. // Fill shadow path on the left-bottom side of the bar
  2766. this.FillPath(brush, path);
  2767. // Draw edges
  2768. using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
  2769. {
  2770. this.DrawPath(penDark, path);
  2771. }
  2772. using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
  2773. {
  2774. this.DrawPath(pen, path);
  2775. }
  2776. }
  2777. }
  2778. }
  2779. }
  2780. }
  2781. }
  2782. /// <summary>
  2783. /// Draw a bar with shadow.
  2784. /// </summary>
  2785. /// <param name="rectF">Size of rectangle</param>
  2786. /// <param name="backColor">Color of rectangle</param>
  2787. /// <param name="backHatchStyle">Hatch style</param>
  2788. /// <param name="backImage">Back Image</param>
  2789. /// <param name="backImageWrapMode">Image mode</param>
  2790. /// <param name="backImageTransparentColor">Image transparent color.</param>
  2791. /// <param name="backImageAlign">Image alignment</param>
  2792. /// <param name="backGradientStyle">Gradient type </param>
  2793. /// <param name="backSecondaryColor">Gradient End Color</param>
  2794. /// <param name="borderColor">Border Color</param>
  2795. /// <param name="borderWidth">Border Width</param>
  2796. /// <param name="borderDashStyle">Border Style</param>
  2797. /// <param name="shadowColor">Shadow Color</param>
  2798. /// <param name="shadowOffset">Shadow Offset</param>
  2799. /// <param name="penAlignment">Pen Alignment</param>
  2800. /// <param name="barDrawingStyle">Bar drawing style.</param>
  2801. /// <param name="isVertical">True if a vertical bar.</param>
  2802. internal void FillRectangleRel( RectangleF rectF,
  2803. Color backColor,
  2804. ChartHatchStyle backHatchStyle,
  2805. string backImage,
  2806. ChartImageWrapMode backImageWrapMode,
  2807. Color backImageTransparentColor,
  2808. ChartImageAlignmentStyle backImageAlign,
  2809. GradientStyle backGradientStyle,
  2810. Color backSecondaryColor,
  2811. Color borderColor,
  2812. int borderWidth,
  2813. ChartDashStyle borderDashStyle,
  2814. Color shadowColor,
  2815. int shadowOffset,
  2816. PenAlignment penAlignment,
  2817. BarDrawingStyle barDrawingStyle,
  2818. bool isVertical)
  2819. {
  2820. this.FillRectangleRel(
  2821. rectF,
  2822. backColor,
  2823. backHatchStyle,
  2824. backImage,
  2825. backImageWrapMode,
  2826. backImageTransparentColor,
  2827. backImageAlign,
  2828. backGradientStyle,
  2829. backSecondaryColor,
  2830. borderColor,
  2831. borderWidth,
  2832. borderDashStyle,
  2833. shadowColor,
  2834. shadowOffset,
  2835. penAlignment,
  2836. false,
  2837. 0,
  2838. false,
  2839. barDrawingStyle,
  2840. isVertical);
  2841. }
  2842. /// <summary>
  2843. /// Draw a bar with shadow.
  2844. /// </summary>
  2845. /// <param name="rectF">Size of rectangle</param>
  2846. /// <param name="backColor">Color of rectangle</param>
  2847. /// <param name="backHatchStyle">Hatch style</param>
  2848. /// <param name="backImage">Back Image</param>
  2849. /// <param name="backImageWrapMode">Image mode</param>
  2850. /// <param name="backImageTransparentColor">Image transparent color.</param>
  2851. /// <param name="backImageAlign">Image alignment</param>
  2852. /// <param name="backGradientStyle">Gradient type </param>
  2853. /// <param name="backSecondaryColor">Gradient End Color</param>
  2854. /// <param name="borderColor">Border Color</param>
  2855. /// <param name="borderWidth">Border Width</param>
  2856. /// <param name="borderDashStyle">Border Style</param>
  2857. /// <param name="shadowColor">Shadow Color</param>
  2858. /// <param name="shadowOffset">Shadow Offset</param>
  2859. /// <param name="penAlignment">Pen Alignment</param>
  2860. internal void FillRectangleRel( RectangleF rectF,
  2861. Color backColor,
  2862. ChartHatchStyle backHatchStyle,
  2863. string backImage,
  2864. ChartImageWrapMode backImageWrapMode,
  2865. Color backImageTransparentColor,
  2866. ChartImageAlignmentStyle backImageAlign,
  2867. GradientStyle backGradientStyle,
  2868. Color backSecondaryColor,
  2869. Color borderColor,
  2870. int borderWidth,
  2871. ChartDashStyle borderDashStyle,
  2872. Color shadowColor,
  2873. int shadowOffset,
  2874. PenAlignment penAlignment )
  2875. {
  2876. this.FillRectangleRel(
  2877. rectF,
  2878. backColor,
  2879. backHatchStyle,
  2880. backImage,
  2881. backImageWrapMode,
  2882. backImageTransparentColor,
  2883. backImageAlign,
  2884. backGradientStyle,
  2885. backSecondaryColor,
  2886. borderColor,
  2887. borderWidth,
  2888. borderDashStyle,
  2889. shadowColor,
  2890. shadowOffset,
  2891. penAlignment,
  2892. false,
  2893. 0,
  2894. false,
  2895. BarDrawingStyle.Default,
  2896. true);
  2897. }
  2898. /// <summary>
  2899. /// Draws rectangle or circle (inside rectangle) with shadow.
  2900. /// </summary>
  2901. /// <param name="rectF">Size of rectangle</param>
  2902. /// <param name="backColor">Color of rectangle</param>
  2903. /// <param name="backHatchStyle">Hatch style</param>
  2904. /// <param name="backImage">Back Image</param>
  2905. /// <param name="backImageWrapMode">Image mode</param>
  2906. /// <param name="backImageTransparentColor">Image transparent color.</param>
  2907. /// <param name="backImageAlign">Image alignment</param>
  2908. /// <param name="backGradientStyle">Gradient type </param>
  2909. /// <param name="backSecondaryColor">Gradient End Color</param>
  2910. /// <param name="borderColor">Border Color</param>
  2911. /// <param name="borderWidth">Border Width</param>
  2912. /// <param name="borderDashStyle">Border Style</param>
  2913. /// <param name="shadowColor">Shadow Color</param>
  2914. /// <param name="shadowOffset">Shadow Offset</param>
  2915. /// <param name="penAlignment">Pen Alignment</param>
  2916. /// <param name="circular">Draw circular shape inside the rectangle.</param>
  2917. /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
  2918. /// <param name="circle3D">3D Circle must be drawn.</param>
  2919. internal void FillRectangleRel( RectangleF rectF,
  2920. Color backColor,
  2921. ChartHatchStyle backHatchStyle,
  2922. string backImage,
  2923. ChartImageWrapMode backImageWrapMode,
  2924. Color backImageTransparentColor,
  2925. ChartImageAlignmentStyle backImageAlign,
  2926. GradientStyle backGradientStyle,
  2927. Color backSecondaryColor,
  2928. Color borderColor,
  2929. int borderWidth,
  2930. ChartDashStyle borderDashStyle,
  2931. Color shadowColor,
  2932. int shadowOffset,
  2933. PenAlignment penAlignment,
  2934. bool circular,
  2935. int circularSectorsCount,
  2936. bool circle3D)
  2937. {
  2938. this.FillRectangleRel(
  2939. rectF,
  2940. backColor,
  2941. backHatchStyle,
  2942. backImage,
  2943. backImageWrapMode,
  2944. backImageTransparentColor,
  2945. backImageAlign,
  2946. backGradientStyle,
  2947. backSecondaryColor,
  2948. borderColor,
  2949. borderWidth,
  2950. borderDashStyle,
  2951. shadowColor,
  2952. shadowOffset,
  2953. penAlignment,
  2954. circular,
  2955. circularSectorsCount,
  2956. circle3D,
  2957. BarDrawingStyle.Default,
  2958. true);
  2959. }
  2960. /// <summary>
  2961. /// Draws rectangle or circle (inside rectangle) with shadow.
  2962. /// </summary>
  2963. /// <param name="rectF">Size of rectangle</param>
  2964. /// <param name="backColor">Color of rectangle</param>
  2965. /// <param name="backHatchStyle">Hatch style</param>
  2966. /// <param name="backImage">Back Image</param>
  2967. /// <param name="backImageWrapMode">Image mode</param>
  2968. /// <param name="backImageTransparentColor">Image transparent color.</param>
  2969. /// <param name="backImageAlign">Image alignment</param>
  2970. /// <param name="backGradientStyle">Gradient type </param>
  2971. /// <param name="backSecondaryColor">Gradient End Color</param>
  2972. /// <param name="borderColor">Border Color</param>
  2973. /// <param name="borderWidth">Border Width</param>
  2974. /// <param name="borderDashStyle">Border Style</param>
  2975. /// <param name="shadowColor">Shadow Color</param>
  2976. /// <param name="shadowOffset">Shadow Offset</param>
  2977. /// <param name="penAlignment">Pen Alignment</param>
  2978. /// <param name="circular">Draw circular shape inside the rectangle.</param>
  2979. /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
  2980. /// <param name="circle3D">3D Circle must be drawn.</param>
  2981. /// <param name="barDrawingStyle">Bar drawing style.</param>
  2982. /// <param name="isVertical">True if a vertical bar.</param>
  2983. internal void FillRectangleRel( RectangleF rectF,
  2984. Color backColor,
  2985. ChartHatchStyle backHatchStyle,
  2986. string backImage,
  2987. ChartImageWrapMode backImageWrapMode,
  2988. Color backImageTransparentColor,
  2989. ChartImageAlignmentStyle backImageAlign,
  2990. GradientStyle backGradientStyle,
  2991. Color backSecondaryColor,
  2992. Color borderColor,
  2993. int borderWidth,
  2994. ChartDashStyle borderDashStyle,
  2995. Color shadowColor,
  2996. int shadowOffset,
  2997. PenAlignment penAlignment,
  2998. bool circular,
  2999. int circularSectorsCount,
  3000. bool circle3D,
  3001. BarDrawingStyle barDrawingStyle,
  3002. bool isVertical)
  3003. {
  3004. Brush brush = null;
  3005. Brush backBrush = null;
  3006. // Remember SmoothingMode and turn off anti aliasing
  3007. SmoothingMode oldSmoothingMode = this.SmoothingMode;
  3008. if(!circular)
  3009. {
  3010. this.SmoothingMode = SmoothingMode.Default;
  3011. }
  3012. // Color is empty
  3013. if( backColor.IsEmpty )
  3014. {
  3015. backColor = Color.White;
  3016. }
  3017. if( backSecondaryColor.IsEmpty )
  3018. {
  3019. backSecondaryColor = Color.White;
  3020. }
  3021. if( borderColor.IsEmpty || borderDashStyle == ChartDashStyle.NotSet)
  3022. {
  3023. borderWidth = 0;
  3024. }
  3025. // Get absolute coordinates
  3026. RectangleF rect = GetAbsoluteRectangle( rectF );
  3027. // Rectangle width and height can not be very small value
  3028. if( rect.Width < 1.0F && rect.Width > 0.0F )
  3029. {
  3030. rect.Width = 1.0F;
  3031. }
  3032. if( rect.Height < 1.0F && rect.Height > 0.0F )
  3033. {
  3034. rect.Height = 1.0F;
  3035. }
  3036. // Round the values
  3037. rect = Round( rect );
  3038. // For inset alignment resize fill rectangle
  3039. RectangleF fillRect;
  3040. if( penAlignment == PenAlignment.Inset &&
  3041. borderWidth > 0)
  3042. {
  3043. // SVG and Metafiles do not support inset pen styles - use same rectangle
  3044. if( this.ActiveRenderingType == RenderingType.Svg ||
  3045. this.IsMetafile)
  3046. {
  3047. fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
  3048. }
  3049. else if (this.Graphics.Transform.Elements[0] != 1f ||
  3050. this.Graphics.Transform.Elements[3] != 1f)
  3051. {
  3052. // Do not reduce filling rectangle if scaling is used in the graphics
  3053. // transformations. Rounding may cause a 1 pixel gap between the border
  3054. // and the filling.
  3055. fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
  3056. }
  3057. else
  3058. {
  3059. // The fill rectangle is resized because of border size.
  3060. fillRect = new RectangleF(
  3061. rect.X + borderWidth,
  3062. rect.Y + borderWidth,
  3063. rect.Width - borderWidth * 2f + 1,
  3064. rect.Height - borderWidth * 2f + 1);
  3065. }
  3066. }
  3067. else
  3068. {
  3069. // The fill rectangle is same
  3070. fillRect = rect;
  3071. }
  3072. // Fix for issue #6714:
  3073. // Make sure the rectangle coordinates fit the control. In same cases rectangle width or
  3074. // hight ca be extremly large. Drawing such a rectangle may cause an overflow exception.
  3075. // The code below restricts the maximum size to double the chart size. See issue
  3076. // description for more information. -AG.
  3077. if(fillRect.Width > 2f * this._width)
  3078. {
  3079. fillRect.Width = 2f * this._width;
  3080. }
  3081. if(fillRect.Height > 2f * this._height)
  3082. {
  3083. fillRect.Height = 2f * this._height;
  3084. }
  3085. if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
  3086. {
  3087. backBrush = brush;
  3088. brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor);
  3089. }
  3090. else if( backHatchStyle != ChartHatchStyle.None )
  3091. {
  3092. brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
  3093. }
  3094. else if( backGradientStyle != GradientStyle.None )
  3095. {
  3096. // If a gradient type is set create a brush with gradient
  3097. brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
  3098. }
  3099. else
  3100. {
  3101. // Set a bar color.
  3102. if(backColor == Color.Empty || backColor == Color.Transparent)
  3103. {
  3104. brush = null;
  3105. }
  3106. else
  3107. {
  3108. brush = new SolidBrush(backColor);
  3109. }
  3110. }
  3111. // Draw shadow
  3112. FillRectangleShadowAbs( rect, shadowColor, shadowOffset, backColor, circular, circularSectorsCount );
  3113. // Draw rectangle image
  3114. if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
  3115. {
  3116. // Load image
  3117. System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
  3118. // Prepare image properties (transparent color)
  3119. ImageAttributes attrib = new ImageAttributes();
  3120. if(backImageTransparentColor != Color.Empty)
  3121. {
  3122. attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
  3123. }
  3124. // Draw scaled image
  3125. RectangleF imageRect = new RectangleF();
  3126. imageRect.X = fillRect.X;
  3127. imageRect.Y = fillRect.Y;
  3128. imageRect.Width = fillRect.Width;
  3129. imageRect.Height = fillRect.Height;
  3130. SizeF imageAbsSize = new SizeF();
  3131. // Calculate unscaled image position
  3132. if(backImageWrapMode == ChartImageWrapMode.Unscaled)
  3133. {
  3134. ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
  3135. // Calculate image position
  3136. imageRect.Width = Math.Min(fillRect.Width, imageAbsSize.Width);
  3137. imageRect.Height = Math.Min(fillRect.Height, imageAbsSize.Height);
  3138. // Adjust position with alignment property
  3139. if(imageRect.Width < fillRect.Width)
  3140. {
  3141. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  3142. backImageAlign == ChartImageAlignmentStyle.Right ||
  3143. backImageAlign == ChartImageAlignmentStyle.TopRight)
  3144. {
  3145. imageRect.X = fillRect.Right - imageRect.Width;
  3146. }
  3147. else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
  3148. backImageAlign == ChartImageAlignmentStyle.Center ||
  3149. backImageAlign == ChartImageAlignmentStyle.Top)
  3150. {
  3151. imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
  3152. }
  3153. }
  3154. if(imageRect.Height < fillRect.Height)
  3155. {
  3156. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  3157. backImageAlign == ChartImageAlignmentStyle.Bottom ||
  3158. backImageAlign == ChartImageAlignmentStyle.BottomLeft)
  3159. {
  3160. imageRect.Y = fillRect.Bottom - imageRect.Height;
  3161. }
  3162. else if(backImageAlign == ChartImageAlignmentStyle.Left ||
  3163. backImageAlign == ChartImageAlignmentStyle.Center ||
  3164. backImageAlign == ChartImageAlignmentStyle.Right)
  3165. {
  3166. imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
  3167. }
  3168. }
  3169. }
  3170. // Fill background with brush
  3171. if(brush != null)
  3172. {
  3173. if(circular)
  3174. this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
  3175. else
  3176. this.FillRectangle( brush, fillRect );
  3177. }
  3178. // Draw image
  3179. this.DrawImage(image,
  3180. new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
  3181. 0, 0,
  3182. (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Width * image.Width / imageAbsSize.Width : image.Width,
  3183. (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Height * image.Height / imageAbsSize.Height : image.Height,
  3184. GraphicsUnit.Pixel,
  3185. attrib);
  3186. }
  3187. // Draw rectangle
  3188. else
  3189. {
  3190. if(backBrush != null && backImageTransparentColor != Color.Empty)
  3191. {
  3192. // Fill background with brush
  3193. if(circular)
  3194. this.DrawCircleAbs( null, backBrush, fillRect, circularSectorsCount, circle3D );
  3195. else
  3196. this.FillRectangle( backBrush, fillRect );
  3197. }
  3198. if(brush != null)
  3199. {
  3200. if(circular)
  3201. this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
  3202. else
  3203. this.FillRectangle( brush, fillRect );
  3204. }
  3205. }
  3206. // Draw different bar style
  3207. this.DrawRectangleBarStyle(barDrawingStyle, isVertical, fillRect);
  3208. // Draw border
  3209. if( borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
  3210. {
  3211. // Set a border line color
  3212. if(_pen.Color != borderColor)
  3213. {
  3214. _pen.Color = borderColor;
  3215. }
  3216. // Set a border line width
  3217. if(_pen.Width != borderWidth)
  3218. {
  3219. _pen.Width = borderWidth;
  3220. }
  3221. // Set pen alignment
  3222. if(_pen.Alignment != penAlignment)
  3223. {
  3224. _pen.Alignment = penAlignment;
  3225. }
  3226. // Set a border line style
  3227. if(_pen.DashStyle != GetPenStyle( borderDashStyle ))
  3228. {
  3229. _pen.DashStyle = GetPenStyle( borderDashStyle );
  3230. }
  3231. // Draw border
  3232. if(circular)
  3233. {
  3234. this.DrawCircleAbs( _pen, null, rect, circularSectorsCount, false );
  3235. }
  3236. else
  3237. {
  3238. // NOTE: Rectangle with single pixel inset border is drawn 1 pixel larger
  3239. // in the .Net Framework. Increase size by 1 pixel to solve the issue.
  3240. if(_pen.Alignment == PenAlignment.Inset && _pen.Width > 1f)
  3241. {
  3242. rect.Width += 1;
  3243. rect.Height += 1;
  3244. }
  3245. // Draw rectangle
  3246. this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
  3247. }
  3248. }
  3249. // Dispose Image and Gradient
  3250. if(brush != null)
  3251. {
  3252. brush.Dispose();
  3253. }
  3254. // Return old smoothing mode
  3255. this.SmoothingMode = oldSmoothingMode;
  3256. }
  3257. /// <summary>
  3258. /// Draw Shadow for a bar
  3259. /// </summary>
  3260. /// <param name="rect">Bar rectangle</param>
  3261. /// <param name="shadowColor">Shadow Color</param>
  3262. /// <param name="shadowOffset">Shadow Offset</param>
  3263. /// <param name="backColor">Back Color</param>
  3264. internal void FillRectangleShadowAbs(
  3265. RectangleF rect,
  3266. Color shadowColor,
  3267. float shadowOffset,
  3268. Color backColor)
  3269. {
  3270. FillRectangleShadowAbs(
  3271. rect,
  3272. shadowColor,
  3273. shadowOffset,
  3274. backColor,
  3275. false,
  3276. 0);
  3277. }
  3278. /// <summary>
  3279. /// Draw Shadow for a bar
  3280. /// </summary>
  3281. /// <param name="rect">Bar rectangle</param>
  3282. /// <param name="shadowColor">Shadow Color</param>
  3283. /// <param name="shadowOffset">Shadow Offset</param>
  3284. /// <param name="backColor">Back Color</param>
  3285. /// <param name="circular">Draw circular shape inside the rectangle.</param>
  3286. /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
  3287. internal void FillRectangleShadowAbs(
  3288. RectangleF rect,
  3289. Color shadowColor,
  3290. float shadowOffset,
  3291. Color backColor,
  3292. bool circular,
  3293. int circularSectorsCount)
  3294. {
  3295. // Do not draw shadoe for empty rectangle
  3296. if(rect.Height == 0 || rect.Width == 0 || shadowOffset == 0)
  3297. {
  3298. return;
  3299. }
  3300. // Do not draw shadow if color is IsEmpty or offset is 0
  3301. if (shadowOffset == 0 || shadowColor == Color.Empty)
  3302. {
  3303. return;
  3304. }
  3305. // For non-circualr shadow with transparent background - use clipping
  3306. bool clippingUsed = false;
  3307. Region oldClipRegion = null;
  3308. if (!circular && backColor == Color.Transparent)
  3309. {
  3310. clippingUsed = true;
  3311. oldClipRegion = this.Clip;
  3312. Region region = new Region();
  3313. region.MakeInfinite();
  3314. region.Xor(rect);
  3315. this.Clip = region;
  3316. }
  3317. // Draw usual or "soft" shadows
  3318. if(!softShadows || circularSectorsCount > 2)
  3319. {
  3320. RectangleF absolute;
  3321. RectangleF offset = RectangleF.Empty;
  3322. absolute = Round( rect );
  3323. // Change shadow color
  3324. using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(backColor.A / 2, shadowColor)))
  3325. {
  3326. // Shadow Position
  3327. offset.X = absolute.X + shadowOffset;
  3328. offset.Y = absolute.Y + shadowOffset;
  3329. offset.Width = absolute.Width;
  3330. offset.Height = absolute.Height;
  3331. // Draw rectangle
  3332. if (circular)
  3333. this.DrawCircleAbs(null, shadowBrush, offset, circularSectorsCount, false);
  3334. else
  3335. this.FillRectangle(shadowBrush, offset);
  3336. }
  3337. }
  3338. else
  3339. {
  3340. RectangleF absolute;
  3341. RectangleF offset = RectangleF.Empty;
  3342. absolute = Round( rect );
  3343. // Shadow Position
  3344. offset.X = absolute.X + shadowOffset - 1;
  3345. offset.Y = absolute.Y + shadowOffset - 1;
  3346. offset.Width = absolute.Width + 2;
  3347. offset.Height = absolute.Height + 2;
  3348. // Calculate rounded rect radius
  3349. float radius = shadowOffset * 0.7f;
  3350. radius = (float)Math.Max(radius, 2f);
  3351. radius = (float)Math.Min(radius, offset.Width/4f);
  3352. radius = (float)Math.Min(radius, offset.Height/4f);
  3353. radius = (float)Math.Ceiling(radius);
  3354. if(circular)
  3355. {
  3356. radius = offset.Width/2f;
  3357. }
  3358. // Create rounded rectangle path
  3359. GraphicsPath path = new GraphicsPath();
  3360. if(circular && offset.Width != offset.Height)
  3361. {
  3362. float radiusX = offset.Width/2f;
  3363. float radiusY = offset.Height/2f;
  3364. path.AddLine(offset.X+radiusX, offset.Y, offset.Right-radiusX, offset.Y);
  3365. path.AddArc(offset.Right-2f*radiusX, offset.Y, 2f*radiusX, 2f*radiusY, 270, 90);
  3366. path.AddLine(offset.Right, offset.Y + radiusY, offset.Right, offset.Bottom - radiusY);
  3367. path.AddArc(offset.Right-2f*radiusX, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 0, 90);
  3368. path.AddLine(offset.Right-radiusX, offset.Bottom, offset.X + radiusX, offset.Bottom);
  3369. path.AddArc(offset.X, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 90, 90);
  3370. path.AddLine(offset.X, offset.Bottom-radiusY, offset.X, offset.Y+radiusY);
  3371. path.AddArc(offset.X, offset.Y, 2f*radiusX, 2f*radiusY, 180, 90);
  3372. }
  3373. else
  3374. {
  3375. path.AddLine(offset.X+radius, offset.Y, offset.Right-radius, offset.Y);
  3376. path.AddArc(offset.Right-2f*radius, offset.Y, 2f*radius, 2f*radius, 270, 90);
  3377. path.AddLine(offset.Right, offset.Y + radius, offset.Right, offset.Bottom - radius);
  3378. path.AddArc(offset.Right-2f*radius, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 0, 90);
  3379. path.AddLine(offset.Right-radius, offset.Bottom, offset.X + radius, offset.Bottom);
  3380. path.AddArc(offset.X, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 90, 90);
  3381. path.AddLine(offset.X, offset.Bottom-radius, offset.X, offset.Y+radius);
  3382. path.AddArc(offset.X, offset.Y, 2f*radius, 2f*radius, 180, 90);
  3383. }
  3384. PathGradientBrush shadowBrush = new PathGradientBrush(path);
  3385. shadowBrush.CenterColor = shadowColor;
  3386. // Set the color along the entire boundary of the path
  3387. Color[] colors = {Color.Transparent};
  3388. shadowBrush.SurroundColors = colors;
  3389. shadowBrush.CenterPoint = new PointF(offset.X + offset.Width/2f, offset.Y + offset.Height/2f);
  3390. // Define brush focus scale
  3391. PointF focusScale = new PointF(1-2f*shadowOffset/offset.Width, 1-2f*shadowOffset/offset.Height);
  3392. if(focusScale.X < 0)
  3393. focusScale.X = 0;
  3394. if(focusScale.Y < 0)
  3395. focusScale.Y = 0;
  3396. shadowBrush.FocusScales = focusScale;
  3397. // Draw rectangle
  3398. this.FillPath(shadowBrush, path);
  3399. }
  3400. // Reset clip region
  3401. if (clippingUsed)
  3402. {
  3403. Region region = this.Clip;
  3404. this.Clip = oldClipRegion;
  3405. region.Dispose();
  3406. }
  3407. }
  3408. /// <summary>
  3409. /// Gets the path of the polygon which represent the circular area.
  3410. /// </summary>
  3411. /// <param name="position">Circle position.</param>
  3412. /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
  3413. /// <returns>Graphics path of the polygon circle.</returns>
  3414. internal GraphicsPath GetPolygonCirclePath(RectangleF position, int polygonSectorsNumber)
  3415. {
  3416. PointF firstPoint = new PointF(position.X + position.Width/2f, position.Y);
  3417. PointF centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
  3418. float sectorSize = 0f;
  3419. GraphicsPath path = new GraphicsPath();
  3420. PointF prevPoint = PointF.Empty;
  3421. float curentSector = 0f;
  3422. // Get sector size
  3423. if(polygonSectorsNumber <= 2)
  3424. {
  3425. // Circle sector size
  3426. sectorSize = 1f;
  3427. }
  3428. else
  3429. {
  3430. // Polygon sector size
  3431. sectorSize = 360f / ((float)polygonSectorsNumber);
  3432. }
  3433. // Loop throug all sectors
  3434. for(curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
  3435. {
  3436. // Create matrix
  3437. Matrix matrix = new Matrix();
  3438. matrix.RotateAt(curentSector, centerPoint);
  3439. // Get point and rotate it
  3440. PointF[] points = new PointF[] { firstPoint };
  3441. matrix.TransformPoints(points);
  3442. // Add point into the path
  3443. if(!prevPoint.IsEmpty)
  3444. {
  3445. path.AddLine(prevPoint, points[0]);
  3446. }
  3447. // Remember last point
  3448. prevPoint = points[0];
  3449. }
  3450. path.CloseAllFigures();
  3451. return path;
  3452. }
  3453. /// <summary>
  3454. /// Fills and/or draws border as circle or polygon.
  3455. /// </summary>
  3456. /// <param name="pen">Border pen.</param>
  3457. /// <param name="brush">Border brush.</param>
  3458. /// <param name="position">Circle position.</param>
  3459. /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
  3460. /// <param name="circle3D">Indicates that circle should be 3D..</param>
  3461. internal void DrawCircleAbs(Pen pen, Brush brush, RectangleF position, int polygonSectorsNumber, bool circle3D)
  3462. {
  3463. bool fill3DCircle = (circle3D && brush != null);
  3464. // Draw 2D circle
  3465. if(polygonSectorsNumber <= 2 && !fill3DCircle)
  3466. {
  3467. if(brush != null)
  3468. {
  3469. this.FillEllipse(brush, position);
  3470. }
  3471. if(pen != null)
  3472. {
  3473. this.DrawEllipse(pen, position);
  3474. }
  3475. }
  3476. // Draw circle as polygon with specified number of sectors
  3477. else
  3478. {
  3479. PointF firstPoint = new PointF(position.X + position.Width/2f, position.Y);
  3480. PointF centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
  3481. float sectorSize = 0f;
  3482. PointF prevPoint = PointF.Empty;
  3483. float curentSector = 0f;
  3484. using (GraphicsPath path = new GraphicsPath())
  3485. {
  3486. // Remember current smoothing mode
  3487. SmoothingMode oldMode = this.SmoothingMode;
  3488. if (fill3DCircle)
  3489. {
  3490. this.SmoothingMode = SmoothingMode.None;
  3491. }
  3492. // Get sector size
  3493. if (polygonSectorsNumber <= 2)
  3494. {
  3495. // Circle sector size
  3496. sectorSize = 1f;
  3497. }
  3498. else
  3499. {
  3500. // Polygon sector size
  3501. sectorSize = 360f / ((float)polygonSectorsNumber);
  3502. }
  3503. // Loop throug all sectors
  3504. for (curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
  3505. {
  3506. // Create matrix
  3507. Matrix matrix = new Matrix();
  3508. matrix.RotateAt(curentSector, centerPoint);
  3509. // Get point and rotate it
  3510. PointF[] points = new PointF[] { firstPoint };
  3511. matrix.TransformPoints(points);
  3512. // Add point into the path
  3513. if (!prevPoint.IsEmpty)
  3514. {
  3515. path.AddLine(prevPoint, points[0]);
  3516. // Fill each segment separatly for the 3D look
  3517. if (fill3DCircle)
  3518. {
  3519. path.AddLine(points[0], centerPoint);
  3520. path.AddLine(centerPoint, prevPoint);
  3521. using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
  3522. {
  3523. this.FillPath(sectorBrush, path);
  3524. }
  3525. path.Reset();
  3526. }
  3527. }
  3528. // Remember last point
  3529. prevPoint = points[0];
  3530. }
  3531. path.CloseAllFigures();
  3532. // Fill last segment for the 3D look
  3533. if (!prevPoint.IsEmpty && fill3DCircle)
  3534. {
  3535. path.AddLine(prevPoint, firstPoint);
  3536. path.AddLine(firstPoint, centerPoint);
  3537. path.AddLine(centerPoint, prevPoint);
  3538. using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
  3539. {
  3540. this.FillPath(sectorBrush, path);
  3541. }
  3542. path.Reset();
  3543. }
  3544. // Restore old mode
  3545. if (fill3DCircle)
  3546. {
  3547. this.SmoothingMode = oldMode;
  3548. }
  3549. if (brush != null && !circle3D)
  3550. {
  3551. this.FillPath(brush, path);
  3552. }
  3553. if (pen != null)
  3554. {
  3555. this.DrawPath(pen, path);
  3556. }
  3557. }
  3558. }
  3559. }
  3560. /// <summary>
  3561. /// Creates 3D sector brush.
  3562. /// </summary>
  3563. /// <param name="brush">Original brush.</param>
  3564. /// <param name="curentSector">Sector position.</param>
  3565. /// <param name="sectorSize">Sector size.</param>
  3566. /// <returns>3D brush.</returns>
  3567. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
  3568. Justification = "Too large of a code change to justify making this change")]
  3569. internal Brush GetSector3DBrush(Brush brush, float curentSector, float sectorSize)
  3570. {
  3571. // Get color from the brush
  3572. Color brushColor = Color.Gray;
  3573. if(brush is HatchBrush)
  3574. {
  3575. brushColor = ((HatchBrush)brush).BackgroundColor;
  3576. }
  3577. else if(brush is LinearGradientBrush)
  3578. {
  3579. brushColor = ((LinearGradientBrush)brush).LinearColors[0];
  3580. }
  3581. else if(brush is PathGradientBrush)
  3582. {
  3583. brushColor = ((PathGradientBrush)brush).CenterColor;
  3584. }
  3585. else if(brush is SolidBrush)
  3586. {
  3587. brushColor = ((SolidBrush)brush).Color;
  3588. }
  3589. // Adjust sector angle
  3590. curentSector -= sectorSize / 2f;
  3591. // Make adjustment for polygon circle with 5 segments
  3592. // to avoid the issue that bottom segment is too dark
  3593. if(sectorSize == 72f && curentSector == 180f)
  3594. {
  3595. curentSector *= 0.8f;
  3596. }
  3597. // No angles more than 180
  3598. if(curentSector > 180)
  3599. {
  3600. curentSector = 360f - curentSector;
  3601. }
  3602. curentSector = curentSector / 180F;
  3603. // Get brush
  3604. brushColor = GetBrightGradientColor( brushColor, curentSector);
  3605. // Get brush
  3606. return new SolidBrush(brushColor);
  3607. }
  3608. /// <summary>
  3609. /// This method creates gradient color with brightness
  3610. /// </summary>
  3611. /// <param name="beginColor">Start color for gradient.</param>
  3612. /// <param name="position">Position used between Start and end color.</param>
  3613. /// <returns>Calculated Gradient color from gradient position</returns>
  3614. internal Color GetBrightGradientColor( Color beginColor, double position )
  3615. {
  3616. double brightness = 0.5;
  3617. if( position < brightness )
  3618. {
  3619. return GetGradientColor( Color.FromArgb(beginColor.A,255,255,255), beginColor, 1 - brightness + position );
  3620. }
  3621. else if( -brightness + position < 1 )
  3622. {
  3623. return GetGradientColor( beginColor, Color.Black, -brightness + position);
  3624. }
  3625. else
  3626. {
  3627. return Color.FromArgb( beginColor.A, 0, 0, 0 );
  3628. }
  3629. }
  3630. /// <summary>
  3631. /// Draw Rectangle using absolute coordinates.
  3632. /// </summary>
  3633. /// <param name="rect">Size of rectangle</param>
  3634. /// <param name="backColor">Color of rectangle</param>
  3635. /// <param name="backHatchStyle">Hatch Style</param>
  3636. /// <param name="backImage">Image URL</param>
  3637. /// <param name="backImageWrapMode">Image Mode</param>
  3638. /// <param name="backImageTransparentColor">Image transparent color.</param>
  3639. /// <param name="backImageAlign">Image alignment.</param>
  3640. /// <param name="backGradientStyle">Gradient AxisName</param>
  3641. /// <param name="backSecondaryColor">End Gradient color</param>
  3642. /// <param name="borderColor">Border Color</param>
  3643. /// <param name="borderWidth">Border Width</param>
  3644. /// <param name="borderDashStyle">Border Style</param>
  3645. /// <param name="penAlignment">Border is outside or inside rectangle</param>
  3646. internal void FillRectangleAbs( RectangleF rect,
  3647. Color backColor,
  3648. ChartHatchStyle backHatchStyle,
  3649. string backImage,
  3650. ChartImageWrapMode backImageWrapMode,
  3651. Color backImageTransparentColor,
  3652. ChartImageAlignmentStyle backImageAlign,
  3653. GradientStyle backGradientStyle,
  3654. Color backSecondaryColor,
  3655. Color borderColor,
  3656. int borderWidth,
  3657. ChartDashStyle borderDashStyle,
  3658. PenAlignment penAlignment )
  3659. {
  3660. Brush brush = null;
  3661. Brush backBrush = null;
  3662. // Turn off Antialias
  3663. SmoothingMode oldMode = this.SmoothingMode;
  3664. this.SmoothingMode = SmoothingMode.None;
  3665. // Color is empty
  3666. if( backColor.IsEmpty )
  3667. backColor = Color.White;
  3668. if( backSecondaryColor.IsEmpty )
  3669. backSecondaryColor = Color.White;
  3670. if( borderColor.IsEmpty )
  3671. {
  3672. borderColor = Color.White;
  3673. borderWidth = 0;
  3674. }
  3675. // Set a border line color
  3676. _pen.Color = borderColor;
  3677. // Set a border line width
  3678. _pen.Width = borderWidth;
  3679. // Set pen alignment
  3680. _pen.Alignment = penAlignment;
  3681. // Set a border line style
  3682. _pen.DashStyle = GetPenStyle( borderDashStyle );
  3683. if( backGradientStyle == GradientStyle.None )
  3684. {
  3685. // Set a bar color.
  3686. _solidBrush.Color = backColor;
  3687. brush = _solidBrush;
  3688. }
  3689. else
  3690. {
  3691. // If a gradient type is set create a brush with gradient
  3692. brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
  3693. }
  3694. if( backHatchStyle != ChartHatchStyle.None )
  3695. {
  3696. brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
  3697. }
  3698. if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
  3699. {
  3700. backBrush = brush;
  3701. brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
  3702. }
  3703. // For inset alignment resize fill rectangle
  3704. RectangleF fillRect;
  3705. // The fill rectangle is same
  3706. fillRect = new RectangleF( rect.X + borderWidth, rect.Y + borderWidth, rect.Width - borderWidth * 2, rect.Height - borderWidth * 2 );
  3707. // FillRectangle and DrawRectangle works differently with RectangleF.
  3708. fillRect.Width += 1;
  3709. fillRect.Height += 1;
  3710. // Draw rectangle image
  3711. if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
  3712. {
  3713. // Load image
  3714. System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
  3715. // Prepare image properties (transparent color)
  3716. ImageAttributes attrib = new ImageAttributes();
  3717. if(backImageTransparentColor != Color.Empty)
  3718. {
  3719. attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
  3720. }
  3721. // Draw scaled image
  3722. RectangleF imageRect = new RectangleF();
  3723. imageRect.X = fillRect.X;
  3724. imageRect.Y = fillRect.Y;
  3725. imageRect.Width = fillRect.Width;
  3726. imageRect.Height = fillRect.Height;
  3727. // Draw unscaled image using align property
  3728. if(backImageWrapMode == ChartImageWrapMode.Unscaled)
  3729. {
  3730. SizeF imageAbsSize = new SizeF();
  3731. ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
  3732. // Calculate image position
  3733. imageRect.Width = imageAbsSize.Width;
  3734. imageRect.Height = imageAbsSize.Height;
  3735. // Adjust position with alignment property
  3736. if(imageRect.Width < fillRect.Width)
  3737. {
  3738. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  3739. backImageAlign == ChartImageAlignmentStyle.Right ||
  3740. backImageAlign == ChartImageAlignmentStyle.TopRight)
  3741. {
  3742. imageRect.X = fillRect.Right - imageRect.Width;
  3743. }
  3744. else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
  3745. backImageAlign == ChartImageAlignmentStyle.Center ||
  3746. backImageAlign == ChartImageAlignmentStyle.Top)
  3747. {
  3748. imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
  3749. }
  3750. }
  3751. if(imageRect.Height < fillRect.Height)
  3752. {
  3753. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  3754. backImageAlign == ChartImageAlignmentStyle.Bottom ||
  3755. backImageAlign == ChartImageAlignmentStyle.BottomLeft)
  3756. {
  3757. imageRect.Y = fillRect.Bottom - imageRect.Height;
  3758. }
  3759. else if(backImageAlign == ChartImageAlignmentStyle.Left ||
  3760. backImageAlign == ChartImageAlignmentStyle.Center ||
  3761. backImageAlign == ChartImageAlignmentStyle.Right)
  3762. {
  3763. imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
  3764. }
  3765. }
  3766. }
  3767. // Fill background with brush
  3768. this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
  3769. // Draw image
  3770. this.DrawImage(image,
  3771. new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
  3772. 0, 0, image.Width, image.Height,
  3773. GraphicsUnit.Pixel,
  3774. attrib);
  3775. }
  3776. // Draw rectangle
  3777. else
  3778. {
  3779. if(backBrush != null && backImageTransparentColor != Color.Empty)
  3780. {
  3781. // Fill background with brush
  3782. this.FillRectangle( backBrush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
  3783. }
  3784. this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
  3785. }
  3786. // Set pen alignment
  3787. if(borderDashStyle != ChartDashStyle.NotSet)
  3788. {
  3789. if( borderWidth > 1 )
  3790. this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
  3791. else if( borderWidth == 1 )
  3792. this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
  3793. }
  3794. // Dispose Image and Gradient
  3795. if( backGradientStyle != GradientStyle.None )
  3796. {
  3797. brush.Dispose();
  3798. }
  3799. if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
  3800. {
  3801. brush.Dispose();
  3802. }
  3803. if( backHatchStyle != ChartHatchStyle.None )
  3804. {
  3805. brush.Dispose();
  3806. }
  3807. // Set Old Smoothing Mode
  3808. this.SmoothingMode = oldMode;
  3809. }
  3810. /// <summary>
  3811. /// Fills graphics path with shadow using absolute coordinates.
  3812. /// </summary>
  3813. /// <param name="path">Graphics path to fill.</param>
  3814. /// <param name="backColor">Color of rectangle</param>
  3815. /// <param name="backHatchStyle">Hatch Style</param>
  3816. /// <param name="backImage">Image URL</param>
  3817. /// <param name="backImageWrapMode">Image Mode</param>
  3818. /// <param name="backImageTransparentColor">Image transparent color.</param>
  3819. /// <param name="backImageAlign">Image alignment.</param>
  3820. /// <param name="backGradientStyle">Gradient AxisName</param>
  3821. /// <param name="backSecondaryColor">End Gradient color</param>
  3822. /// <param name="borderColor">Border Color</param>
  3823. /// <param name="borderWidth">Border Width</param>
  3824. /// <param name="borderDashStyle">Border Style</param>
  3825. /// <param name="penAlignment">Border is outside or inside rectangle</param>
  3826. /// <param name="shadowOffset">Shadow offset.</param>
  3827. /// <param name="shadowColor">Shadow color.</param>
  3828. internal void DrawPathAbs(
  3829. GraphicsPath path,
  3830. Color backColor,
  3831. ChartHatchStyle backHatchStyle,
  3832. string backImage,
  3833. ChartImageWrapMode backImageWrapMode,
  3834. Color backImageTransparentColor,
  3835. ChartImageAlignmentStyle backImageAlign,
  3836. GradientStyle backGradientStyle,
  3837. Color backSecondaryColor,
  3838. Color borderColor,
  3839. int borderWidth,
  3840. ChartDashStyle borderDashStyle,
  3841. PenAlignment penAlignment,
  3842. int shadowOffset,
  3843. Color shadowColor)
  3844. {
  3845. // Draw patj shadow
  3846. if(shadowOffset != 0 && shadowColor != Color.Transparent)
  3847. {
  3848. // Save graphics state and apply translate transformation
  3849. IGraphicsState graphicsState = this.Save();
  3850. this.TranslateTransform(shadowOffset, shadowOffset);
  3851. if(backColor == Color.Transparent &&
  3852. backSecondaryColor.IsEmpty )
  3853. {
  3854. this.DrawPathAbs(
  3855. path,
  3856. Color.Transparent,
  3857. ChartHatchStyle.None,
  3858. String.Empty,
  3859. ChartImageWrapMode.Scaled,
  3860. Color.Empty,
  3861. ChartImageAlignmentStyle.Center,
  3862. GradientStyle.None,
  3863. Color.Empty,
  3864. shadowColor,
  3865. borderWidth,
  3866. borderDashStyle,
  3867. PenAlignment.Center);
  3868. }
  3869. else
  3870. {
  3871. this.DrawPathAbs(
  3872. path,
  3873. shadowColor,
  3874. ChartHatchStyle.None,
  3875. String.Empty,
  3876. ChartImageWrapMode.Scaled,
  3877. Color.Empty,
  3878. ChartImageAlignmentStyle.Center,
  3879. GradientStyle.None,
  3880. Color.Empty,
  3881. Color.Transparent,
  3882. 0,
  3883. ChartDashStyle.NotSet,
  3884. PenAlignment.Center);
  3885. }
  3886. // Restore graphics state
  3887. this.Restore(graphicsState);
  3888. }
  3889. // Draw path
  3890. this.DrawPathAbs(
  3891. path,
  3892. backColor,
  3893. backHatchStyle,
  3894. backImage,
  3895. backImageWrapMode,
  3896. backImageTransparentColor,
  3897. backImageAlign,
  3898. backGradientStyle,
  3899. backSecondaryColor,
  3900. borderColor,
  3901. borderWidth,
  3902. borderDashStyle,
  3903. penAlignment);
  3904. }
  3905. /// <summary>
  3906. /// Fills graphics path using absolute coordinates.
  3907. /// </summary>
  3908. /// <param name="path">Graphics path to fill.</param>
  3909. /// <param name="backColor">Color of rectangle</param>
  3910. /// <param name="backHatchStyle">Hatch Style</param>
  3911. /// <param name="backImage">Image URL</param>
  3912. /// <param name="backImageWrapMode">Image Mode</param>
  3913. /// <param name="backImageTransparentColor">Image transparent color.</param>
  3914. /// <param name="backImageAlign">Image alignment.</param>
  3915. /// <param name="backGradientStyle">Gradient AxisName</param>
  3916. /// <param name="backSecondaryColor">End Gradient color</param>
  3917. /// <param name="borderColor">Border Color</param>
  3918. /// <param name="borderWidth">Border Width</param>
  3919. /// <param name="borderDashStyle">Border Style</param>
  3920. /// <param name="penAlignment">Border is outside or inside rectangle</param>
  3921. internal void DrawPathAbs( GraphicsPath path,
  3922. Color backColor,
  3923. ChartHatchStyle backHatchStyle,
  3924. string backImage,
  3925. ChartImageWrapMode backImageWrapMode,
  3926. Color backImageTransparentColor,
  3927. ChartImageAlignmentStyle backImageAlign,
  3928. GradientStyle backGradientStyle,
  3929. Color backSecondaryColor,
  3930. Color borderColor,
  3931. int borderWidth,
  3932. ChartDashStyle borderDashStyle,
  3933. PenAlignment penAlignment )
  3934. {
  3935. Brush brush = null;
  3936. Brush backBrush = null;
  3937. // Color is empty
  3938. if( backColor.IsEmpty )
  3939. backColor = Color.White;
  3940. if( backSecondaryColor.IsEmpty )
  3941. backSecondaryColor = Color.White;
  3942. if( borderColor.IsEmpty )
  3943. {
  3944. borderColor = Color.White;
  3945. borderWidth = 0;
  3946. }
  3947. // Set pen properties
  3948. _pen.Color = borderColor;
  3949. _pen.Width = borderWidth;
  3950. _pen.Alignment = penAlignment;
  3951. _pen.DashStyle = GetPenStyle( borderDashStyle );
  3952. if( backGradientStyle == GradientStyle.None )
  3953. {
  3954. // Set solid brush color.
  3955. _solidBrush.Color = backColor;
  3956. brush = _solidBrush;
  3957. }
  3958. else
  3959. {
  3960. // If a gradient type is set create a brush with gradient
  3961. RectangleF pathRect = path.GetBounds();
  3962. pathRect.Inflate(new SizeF(2,2));
  3963. brush = GetGradientBrush(
  3964. pathRect,
  3965. backColor,
  3966. backSecondaryColor,
  3967. backGradientStyle );
  3968. }
  3969. if( backHatchStyle != ChartHatchStyle.None )
  3970. {
  3971. brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
  3972. }
  3973. if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
  3974. {
  3975. backBrush = brush;
  3976. brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
  3977. }
  3978. // For inset alignment resize fill rectangle
  3979. RectangleF fillRect = path.GetBounds();
  3980. // Draw rectangle image
  3981. if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
  3982. {
  3983. // Load image
  3984. System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
  3985. // Prepare image properties (transparent color)
  3986. ImageAttributes attrib = new ImageAttributes();
  3987. if(backImageTransparentColor != Color.Empty)
  3988. {
  3989. attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
  3990. }
  3991. // Draw scaled image
  3992. RectangleF imageRect = new RectangleF();
  3993. imageRect.X = fillRect.X;
  3994. imageRect.Y = fillRect.Y;
  3995. imageRect.Width = fillRect.Width;
  3996. imageRect.Height = fillRect.Height;
  3997. // Draw unscaled image using align property
  3998. if(backImageWrapMode == ChartImageWrapMode.Unscaled)
  3999. {
  4000. SizeF imageSize = new SizeF();
  4001. ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageSize);
  4002. // Calculate image position
  4003. imageRect.Width = imageSize.Width;
  4004. imageRect.Height = imageSize.Height;
  4005. // Adjust position with alignment property
  4006. if(imageRect.Width < fillRect.Width)
  4007. {
  4008. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  4009. backImageAlign == ChartImageAlignmentStyle.Right ||
  4010. backImageAlign == ChartImageAlignmentStyle.TopRight)
  4011. {
  4012. imageRect.X = fillRect.Right - imageRect.Width;
  4013. }
  4014. else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
  4015. backImageAlign == ChartImageAlignmentStyle.Center ||
  4016. backImageAlign == ChartImageAlignmentStyle.Top)
  4017. {
  4018. imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
  4019. }
  4020. }
  4021. if(imageRect.Height < fillRect.Height)
  4022. {
  4023. if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
  4024. backImageAlign == ChartImageAlignmentStyle.Bottom ||
  4025. backImageAlign == ChartImageAlignmentStyle.BottomLeft)
  4026. {
  4027. imageRect.Y = fillRect.Bottom - imageRect.Height;
  4028. }
  4029. else if(backImageAlign == ChartImageAlignmentStyle.Left ||
  4030. backImageAlign == ChartImageAlignmentStyle.Center ||
  4031. backImageAlign == ChartImageAlignmentStyle.Right)
  4032. {
  4033. imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
  4034. }
  4035. }
  4036. }
  4037. // Fill background with brush
  4038. this.FillPath( brush, path );
  4039. // Draw image
  4040. Region oldClipRegion = this.Clip;
  4041. this.Clip = new Region(path);
  4042. this.DrawImage(image,
  4043. new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
  4044. 0, 0, image.Width, image.Height,
  4045. GraphicsUnit.Pixel,
  4046. attrib);
  4047. this.Clip = oldClipRegion;
  4048. }
  4049. // Draw rectangle
  4050. else
  4051. {
  4052. if(backBrush != null && backImageTransparentColor != Color.Empty)
  4053. {
  4054. // Fill background with brush
  4055. this.FillPath( backBrush, path);
  4056. }
  4057. this.FillPath( brush, path);
  4058. }
  4059. // Draw border
  4060. if(borderColor != Color.Empty && borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
  4061. {
  4062. this.DrawPath( _pen, path );
  4063. }
  4064. }
  4065. /// <summary>
  4066. /// Creates brush with specified properties.
  4067. /// </summary>
  4068. /// <param name="rect">Gradient rectangle</param>
  4069. /// <param name="backColor">Color of rectangle</param>
  4070. /// <param name="backHatchStyle">Hatch style</param>
  4071. /// <param name="backImage">Back Image</param>
  4072. /// <param name="backImageWrapMode">Image mode</param>
  4073. /// <param name="backImageTransparentColor">Image transparent color.</param>
  4074. /// <param name="backGradientStyle">Gradient type </param>
  4075. /// <param name="backSecondaryColor">Gradient End Color</param>
  4076. /// <returns>New brush object.</returns>
  4077. internal Brush CreateBrush(
  4078. RectangleF rect,
  4079. Color backColor,
  4080. ChartHatchStyle backHatchStyle,
  4081. string backImage,
  4082. ChartImageWrapMode backImageWrapMode,
  4083. Color backImageTransparentColor,
  4084. GradientStyle backGradientStyle,
  4085. Color backSecondaryColor
  4086. )
  4087. {
  4088. Brush brush = new SolidBrush(backColor);
  4089. if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
  4090. {
  4091. brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
  4092. }
  4093. else if( backHatchStyle != ChartHatchStyle.None )
  4094. {
  4095. brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
  4096. }
  4097. else if( backGradientStyle != GradientStyle.None )
  4098. {
  4099. // If a gradient type is set create a brush with gradient
  4100. brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
  4101. }
  4102. return brush;
  4103. }
  4104. #endregion
  4105. #region Coordinates converter
  4106. /// <summary>
  4107. /// This method takes a RectangleF structure that is using absolute coordinates
  4108. /// and returns a RectangleF object that uses relative coordinates.
  4109. /// </summary>
  4110. /// <param name="rectangle">RectangleF structure in absolute coordinates.</param>
  4111. /// <returns>RectangleF structure in relative coordinates.</returns>
  4112. public RectangleF GetRelativeRectangle( RectangleF rectangle )
  4113. {
  4114. // Check arguments
  4115. if (rectangle == null)
  4116. throw new ArgumentNullException("rectangle");
  4117. RectangleF relative = RectangleF.Empty;
  4118. // Convert absolute coordinates to relative coordinates
  4119. relative.X = rectangle.X * 100F / ((float)(_width - 1));
  4120. relative.Y = rectangle.Y * 100F / ((float)(_height - 1));
  4121. relative.Width = rectangle.Width * 100F / ((float)(_width - 1));
  4122. relative.Height = rectangle.Height * 100F / ((float)(_height - 1));
  4123. // Return Relative coordinates
  4124. return relative;
  4125. }
  4126. /// <summary>
  4127. /// This method takes a PointF object that is using absolute coordinates
  4128. /// and returns a PointF object that uses relative coordinates.
  4129. /// </summary>
  4130. /// <param name="point">PointF object in absolute coordinates.</param>
  4131. /// <returns>PointF object in relative coordinates.</returns>
  4132. public PointF GetRelativePoint( PointF point )
  4133. {
  4134. // Check arguments
  4135. if (point == null)
  4136. throw new ArgumentNullException("point");
  4137. PointF relative = PointF.Empty;
  4138. // Convert absolute coordinates to relative coordinates
  4139. relative.X = point.X * 100F / ((float)(_width - 1));
  4140. relative.Y = point.Y * 100F / ((float)(_height - 1));
  4141. // Return Relative coordinates
  4142. return relative;
  4143. }
  4144. /// <summary>
  4145. /// This method takes a SizeF object that uses absolute coordinates
  4146. /// and returns a SizeF object that uses relative coordinates.
  4147. /// </summary>
  4148. /// <param name="size">SizeF object in absolute coordinates.</param>
  4149. /// <returns>SizeF object in relative coordinates.</returns>
  4150. public SizeF GetRelativeSize( SizeF size )
  4151. {
  4152. // Check arguments
  4153. if (size == null)
  4154. throw new ArgumentNullException("size");
  4155. SizeF relative = SizeF.Empty;
  4156. // Convert absolute coordinates to relative coordinates
  4157. relative.Width = size.Width * 100F / ((float)(_width - 1));
  4158. relative.Height = size.Height * 100F / ((float)(_height - 1));
  4159. // Return relative coordinates
  4160. return relative;
  4161. }
  4162. /// <summary>
  4163. /// This method takes a PointF object and converts its relative coordinates
  4164. /// to absolute coordinates.
  4165. /// </summary>
  4166. /// <param name="point">PointF object in relative coordinates.</param>
  4167. /// <returns>PointF object in absolute coordinates.</returns>
  4168. public PointF GetAbsolutePoint( PointF point )
  4169. {
  4170. // Check arguments
  4171. if (point == null)
  4172. throw new ArgumentNullException("point");
  4173. PointF absolute = PointF.Empty;
  4174. // Convert relative coordinates to absolute coordinates
  4175. absolute.X = point.X * (_width - 1) / 100F;
  4176. absolute.Y = point.Y * (_height - 1) / 100F;
  4177. // Return Absolute coordinates
  4178. return absolute;
  4179. }
  4180. /// <summary>
  4181. /// This method takes a RectangleF structure and converts its relative coordinates
  4182. /// to absolute coordinates.
  4183. /// </summary>
  4184. /// <param name="rectangle">RectangleF object in relative coordinates.</param>
  4185. /// <returns>RectangleF object in absolute coordinates.</returns>
  4186. public RectangleF GetAbsoluteRectangle( RectangleF rectangle )
  4187. {
  4188. // Check arguments
  4189. if (rectangle == null)
  4190. throw new ArgumentNullException("rectangle");
  4191. RectangleF absolute = RectangleF.Empty;
  4192. // Convert relative coordinates to absolute coordinates
  4193. absolute.X = rectangle.X * (_width - 1) / 100F;
  4194. absolute.Y = rectangle.Y * (_height - 1) / 100F;
  4195. absolute.Width = rectangle.Width * (_width - 1) / 100F;
  4196. absolute.Height = rectangle.Height * (_height - 1) / 100F;
  4197. // Return Absolute coordinates
  4198. return absolute;
  4199. }
  4200. /// <summary>
  4201. /// This method takes a SizeF object that uses relative coordinates
  4202. /// and returns a SizeF object that uses absolute coordinates.
  4203. /// </summary>
  4204. /// <param name="size">SizeF object in relative coordinates.</param>
  4205. /// <returns>SizeF object in absolute coordinates.</returns>
  4206. public SizeF GetAbsoluteSize( SizeF size )
  4207. {
  4208. // Check arguments
  4209. if (size == null)
  4210. throw new ArgumentNullException("size");
  4211. SizeF absolute = SizeF.Empty;
  4212. // Convert relative coordinates to absolute coordinates
  4213. absolute.Width = size.Width * (_width - 1) / 100F;
  4214. absolute.Height = size.Height * (_height - 1) / 100F;
  4215. // Return Absolute coordinates
  4216. return absolute;
  4217. }
  4218. #endregion
  4219. #region Border drawing helper methods
  4220. /// <summary>
  4221. /// Helper function which creates a rounded rectangle path.
  4222. /// </summary>
  4223. /// <param name="rect">Rectangle coordinates.</param>
  4224. /// <param name="cornerRadius">Array of 4 corners radius.</param>
  4225. /// <returns>Graphics path object.</returns>
  4226. internal GraphicsPath CreateRoundedRectPath(RectangleF rect, float[] cornerRadius)
  4227. {
  4228. // Create rounded rectangle path
  4229. GraphicsPath path = new GraphicsPath();
  4230. path.AddLine(rect.X+cornerRadius[0], rect.Y, rect.Right-cornerRadius[1], rect.Y);
  4231. path.AddArc(rect.Right-2f*cornerRadius[1], rect.Y, 2f*cornerRadius[1], 2f*cornerRadius[2], 270, 90);
  4232. path.AddLine(rect.Right, rect.Y + cornerRadius[2], rect.Right, rect.Bottom - cornerRadius[3]);
  4233. path.AddArc(rect.Right-2f*cornerRadius[4], rect.Bottom-2f*cornerRadius[3], 2f*cornerRadius[4], 2f*cornerRadius[3], 0, 90);
  4234. path.AddLine(rect.Right-cornerRadius[4], rect.Bottom, rect.X + cornerRadius[5], rect.Bottom);
  4235. path.AddArc(rect.X, rect.Bottom-2f*cornerRadius[6], 2f*cornerRadius[5], 2f*cornerRadius[6], 90, 90);
  4236. path.AddLine(rect.X, rect.Bottom-cornerRadius[6], rect.X, rect.Y+cornerRadius[7]);
  4237. path.AddArc(rect.X, rect.Y, 2f*cornerRadius[0], 2f*cornerRadius[7], 180, 90);
  4238. return path;
  4239. }
  4240. /// <summary>
  4241. /// Helper function which draws a shadow of the rounded rect.
  4242. /// </summary>
  4243. /// <param name="rect">Rectangle coordinates.</param>
  4244. /// <param name="cornerRadius">Array of 4 corners radius.</param>
  4245. /// <param name="radius">Rounding radius.</param>
  4246. /// <param name="centerColor">Center color.</param>
  4247. /// <param name="surroundColor">Surrounding color.</param>
  4248. /// <param name="shadowScale">Shadow scale value.</param>
  4249. internal void DrawRoundedRectShadowAbs(RectangleF rect, float[] cornerRadius, float radius, Color centerColor, Color surroundColor, float shadowScale)
  4250. {
  4251. // Create rounded rectangle path
  4252. GraphicsPath path = CreateRoundedRectPath(rect, cornerRadius);
  4253. // Create gradient brush
  4254. PathGradientBrush shadowBrush = new PathGradientBrush(path);
  4255. shadowBrush.CenterColor = centerColor;
  4256. // Set the color along the entire boundary of the path
  4257. Color[] colors = {surroundColor};
  4258. shadowBrush.SurroundColors = colors;
  4259. shadowBrush.CenterPoint = new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f);
  4260. // Define brush focus scale
  4261. PointF focusScale = new PointF(1-shadowScale*radius/rect.Width, 1-shadowScale*radius/rect.Height);
  4262. shadowBrush.FocusScales = focusScale;
  4263. // Draw rounded rectangle
  4264. this.FillPath(shadowBrush, path);
  4265. if( path != null )
  4266. {
  4267. path.Dispose();
  4268. }
  4269. }
  4270. /// <summary>
  4271. /// Draws 3D border in absolute coordinates.
  4272. /// </summary>
  4273. /// <param name="borderSkin">Border skin object.</param>
  4274. /// <param name="rect">Rectangle of the border (pixel coordinates).</param>
  4275. /// <param name="backColor">Color of rectangle</param>
  4276. /// <param name="backHatchStyle">Hatch style</param>
  4277. /// <param name="backImage">Back Image</param>
  4278. /// <param name="backImageWrapMode">Image mode</param>
  4279. /// <param name="backImageTransparentColor">Image transparent color.</param>
  4280. /// <param name="backImageAlign">Image alignment</param>
  4281. /// <param name="backGradientStyle">Gradient type </param>
  4282. /// <param name="backSecondaryColor">Gradient End Color</param>
  4283. /// <param name="borderColor">Border Color</param>
  4284. /// <param name="borderWidth">Border Width</param>
  4285. /// <param name="borderDashStyle">Border Style</param>
  4286. internal void Draw3DBorderRel(
  4287. BorderSkin borderSkin,
  4288. RectangleF rect,
  4289. Color backColor,
  4290. ChartHatchStyle backHatchStyle,
  4291. string backImage,
  4292. ChartImageWrapMode backImageWrapMode,
  4293. Color backImageTransparentColor,
  4294. ChartImageAlignmentStyle backImageAlign,
  4295. GradientStyle backGradientStyle,
  4296. Color backSecondaryColor,
  4297. Color borderColor,
  4298. int borderWidth,
  4299. ChartDashStyle borderDashStyle)
  4300. {
  4301. Draw3DBorderAbs(borderSkin, GetAbsoluteRectangle(rect), backColor, backHatchStyle,
  4302. backImage, backImageWrapMode, backImageTransparentColor, backImageAlign, backGradientStyle,
  4303. backSecondaryColor, borderColor, borderWidth, borderDashStyle);
  4304. }
  4305. /// <summary>
  4306. /// Draws 3D border in absolute coordinates.
  4307. /// </summary>
  4308. /// <param name="borderSkin">Border skin object.</param>
  4309. /// <param name="absRect">Rectangle of the border (pixel coordinates).</param>
  4310. /// <param name="backColor">Color of rectangle</param>
  4311. /// <param name="backHatchStyle">Hatch style</param>
  4312. /// <param name="backImage">Back Image</param>
  4313. /// <param name="backImageWrapMode">Image mode</param>
  4314. /// <param name="backImageTransparentColor">Image transparent color.</param>
  4315. /// <param name="backImageAlign">Image alignment</param>
  4316. /// <param name="backGradientStyle">Gradient type </param>
  4317. /// <param name="backSecondaryColor">Gradient End Color</param>
  4318. /// <param name="borderColor">Border Color</param>
  4319. /// <param name="borderWidth">Border Width</param>
  4320. /// <param name="borderDashStyle">Border Style</param>
  4321. internal void Draw3DBorderAbs(
  4322. BorderSkin borderSkin,
  4323. RectangleF absRect,
  4324. Color backColor,
  4325. ChartHatchStyle backHatchStyle,
  4326. string backImage,
  4327. ChartImageWrapMode backImageWrapMode,
  4328. Color backImageTransparentColor,
  4329. ChartImageAlignmentStyle backImageAlign,
  4330. GradientStyle backGradientStyle,
  4331. Color backSecondaryColor,
  4332. Color borderColor,
  4333. int borderWidth,
  4334. ChartDashStyle borderDashStyle)
  4335. {
  4336. // Check input parameters
  4337. if(_common == null || borderSkin.SkinStyle == BorderSkinStyle.None || absRect.Width == 0 || absRect.Height == 0)
  4338. {
  4339. return;
  4340. }
  4341. // Find required border interface
  4342. IBorderType borderTypeInterface = _common.BorderTypeRegistry.GetBorderType(borderSkin.SkinStyle.ToString());
  4343. if(borderTypeInterface != null)
  4344. {
  4345. borderTypeInterface.Resolution = 96;//this.Graphics.DpiX;
  4346. // Draw border
  4347. borderTypeInterface.DrawBorder(this, borderSkin, absRect, backColor, backHatchStyle, backImage, backImageWrapMode,
  4348. backImageTransparentColor, backImageAlign, backGradientStyle, backSecondaryColor,
  4349. borderColor, borderWidth, borderDashStyle);
  4350. }
  4351. }
  4352. #endregion
  4353. #region Pie Method
  4354. /// <summary>
  4355. /// Helper function that retrieves pie drawing style.
  4356. /// </summary>
  4357. /// <param name="point">Data point to get the drawing style for.</param>
  4358. /// <returns>pie drawing style.</returns>
  4359. internal static PieDrawingStyle GetPieDrawingStyle(DataPoint point)
  4360. {
  4361. // Get column drawing style
  4362. PieDrawingStyle pieDrawingStyle = PieDrawingStyle.Default;
  4363. string styleName = point[CustomPropertyName.PieDrawingStyle];
  4364. if(styleName != null)
  4365. {
  4366. if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
  4367. {
  4368. pieDrawingStyle = PieDrawingStyle.Default;
  4369. }
  4370. else if (String.Compare(styleName, "SoftEdge", StringComparison.OrdinalIgnoreCase) == 0)
  4371. {
  4372. pieDrawingStyle = PieDrawingStyle.SoftEdge;
  4373. }
  4374. else if (String.Compare(styleName, "Concave", StringComparison.OrdinalIgnoreCase) == 0)
  4375. {
  4376. pieDrawingStyle = PieDrawingStyle.Concave;
  4377. }
  4378. else
  4379. {
  4380. throw( new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "PieDrawingStyle")));
  4381. }
  4382. }
  4383. return pieDrawingStyle;
  4384. }
  4385. /// <summary>
  4386. /// Draws a pie defined by an ellipse specified by a Rectangle structure and two radial lines.
  4387. /// </summary>
  4388. /// <param name="rect">Rectangle structure that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
  4389. /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
  4390. /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
  4391. /// <param name="backColor">Fill color</param>
  4392. /// <param name="backHatchStyle">Fill Hatch Style</param>
  4393. /// <param name="backImage">Fill texture</param>
  4394. /// <param name="backImageWrapMode">Texture image mode</param>
  4395. /// <param name="backImageTransparentColor">Texture transparent color</param>
  4396. /// <param name="backGradientStyle">Fill Gradient type </param>
  4397. /// <param name="backSecondaryColor">Fill Gradient Second Color</param>
  4398. /// <param name="borderColor">Border Color</param>
  4399. /// <param name="borderWidth">Border Width</param>
  4400. /// <param name="borderDashStyle">Border Style</param>
  4401. /// <param name="shadow">True if shadow is active</param>
  4402. /// <param name="doughnut">True if Doughnut is drawn instead of pie</param>
  4403. /// <param name="doughnutRadius">Internal radius of the doughnut</param>
  4404. /// <param name="pieDrawingStyle">Pie drawing style.</param>
  4405. internal void DrawPieRel(
  4406. RectangleF rect,
  4407. float startAngle,
  4408. float sweepAngle,
  4409. Color backColor,
  4410. ChartHatchStyle backHatchStyle,
  4411. string backImage,
  4412. ChartImageWrapMode backImageWrapMode,
  4413. Color backImageTransparentColor,
  4414. GradientStyle backGradientStyle,
  4415. Color backSecondaryColor,
  4416. Color borderColor,
  4417. int borderWidth,
  4418. ChartDashStyle borderDashStyle,
  4419. bool shadow,
  4420. bool doughnut,
  4421. float doughnutRadius,
  4422. PieDrawingStyle pieDrawingStyle
  4423. )
  4424. {
  4425. Pen borderPen = null; // Pen
  4426. Brush fillBrush; // Brush
  4427. // Get absolute rectangle
  4428. RectangleF absRect = GetAbsoluteRectangle( rect );
  4429. if( doughnutRadius == 100.0 )
  4430. {
  4431. doughnut = false;
  4432. }
  4433. if( doughnutRadius == 0.0 )
  4434. {
  4435. return;
  4436. }
  4437. // Create Brush
  4438. if( backHatchStyle != ChartHatchStyle.None )
  4439. {
  4440. // Create Hatch Brush
  4441. fillBrush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
  4442. }
  4443. else if( backGradientStyle != GradientStyle.None )
  4444. {
  4445. // Create gradient brush
  4446. if( backGradientStyle == GradientStyle.Center )
  4447. {
  4448. fillBrush = GetPieGradientBrush( absRect, backColor, backSecondaryColor );
  4449. }
  4450. else
  4451. {
  4452. using (GraphicsPath path = new GraphicsPath())
  4453. {
  4454. path.AddPie(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle);
  4455. fillBrush = GetGradientBrush(path.GetBounds(), backColor, backSecondaryColor, backGradientStyle);
  4456. }
  4457. }
  4458. }
  4459. else if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled )
  4460. {
  4461. // Create textured brush
  4462. fillBrush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
  4463. }
  4464. else
  4465. {
  4466. // Create solid brush
  4467. fillBrush = new SolidBrush( backColor );
  4468. }
  4469. // Create border Pen
  4470. borderPen = new Pen( borderColor, borderWidth );
  4471. // Set a border line style
  4472. borderPen.DashStyle = GetPenStyle( borderDashStyle );
  4473. // Use rounded line joins
  4474. borderPen.LineJoin = LineJoin.Round;
  4475. // Draw Doughnut
  4476. if( doughnut )
  4477. {
  4478. using (GraphicsPath path = new GraphicsPath())
  4479. {
  4480. path.AddArc(absRect.X + absRect.Width * doughnutRadius / 200 - 1, absRect.Y + absRect.Height * doughnutRadius / 200 - 1, absRect.Width - absRect.Width * doughnutRadius / 100 + 2, absRect.Height - absRect.Height * doughnutRadius / 100 + 2, startAngle, sweepAngle);
  4481. path.AddArc(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle + sweepAngle, -sweepAngle);
  4482. path.CloseFigure();
  4483. this.FillPath(fillBrush, path);
  4484. // Draw Pie gradien effects
  4485. this.DrawPieGradientEffects(pieDrawingStyle, absRect, startAngle, sweepAngle, doughnutRadius);
  4486. // Draw Doughnut Border
  4487. if (!shadow &&
  4488. borderWidth > 0 &&
  4489. borderDashStyle != ChartDashStyle.NotSet)
  4490. {
  4491. this.DrawPath(borderPen, path);
  4492. }
  4493. }
  4494. }
  4495. else // Draw Pie
  4496. {
  4497. // Draw Soft shadow for pie slice
  4498. if( shadow && softShadows )
  4499. {
  4500. DrawPieSoftShadow( startAngle, sweepAngle, absRect, backColor );
  4501. }
  4502. else
  4503. {
  4504. // Fill Pie for normal shadow or colored pie slice
  4505. this.FillPie( fillBrush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
  4506. // Draw Pie gradien effects
  4507. this.DrawPieGradientEffects( pieDrawingStyle, absRect, startAngle, sweepAngle, -1f);
  4508. }
  4509. // Draw Pie Border
  4510. if( !shadow &&
  4511. borderWidth > 0 &&
  4512. borderDashStyle != ChartDashStyle.NotSet)
  4513. {
  4514. this.DrawPie( borderPen, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
  4515. }
  4516. }
  4517. // Dispose graphics objects
  4518. if( borderPen != null )
  4519. {
  4520. borderPen.Dispose();
  4521. }
  4522. if( fillBrush != null )
  4523. {
  4524. fillBrush.Dispose();
  4525. }
  4526. }
  4527. private void DrawPieGradientEffects(
  4528. PieDrawingStyle pieDrawingStyle,
  4529. RectangleF position,
  4530. float startAngle,
  4531. float sweepAngle,
  4532. float doughnutRadius)
  4533. {
  4534. if(pieDrawingStyle == PieDrawingStyle.Concave)
  4535. {
  4536. // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn
  4537. // twice on the outside and inside radius.
  4538. float minSize = (float)Math.Min(position.Width, position.Height);
  4539. float shadowSize = minSize * 0.05f;
  4540. // Create brush path
  4541. RectangleF gradientPath = position;
  4542. gradientPath.Inflate(-shadowSize, -shadowSize);
  4543. using(GraphicsPath brushPath = new GraphicsPath())
  4544. {
  4545. brushPath.AddEllipse(gradientPath);
  4546. // Create shadow path
  4547. using(GraphicsPath path = new GraphicsPath())
  4548. {
  4549. if(doughnutRadius < 0f)
  4550. {
  4551. path.AddPie(Rectangle.Round(gradientPath), startAngle, sweepAngle);
  4552. }
  4553. else
  4554. {
  4555. path.AddArc(
  4556. gradientPath.X + position.Width * doughnutRadius /200 - 1 - shadowSize,
  4557. gradientPath.Y + position.Height * doughnutRadius /200 - 1 - shadowSize,
  4558. gradientPath.Width - position.Width * doughnutRadius / 100 + 2 + 2f * shadowSize,
  4559. gradientPath.Height - position.Height * doughnutRadius / 100 + 2 + 2f * shadowSize,
  4560. startAngle,
  4561. sweepAngle );
  4562. path.AddArc( gradientPath.X, gradientPath.Y, gradientPath.Width, gradientPath.Height, startAngle + sweepAngle, -sweepAngle );
  4563. }
  4564. // Create linear gradient brush
  4565. gradientPath.Inflate(1f, 1f);
  4566. using(LinearGradientBrush brush = new LinearGradientBrush(
  4567. gradientPath,
  4568. Color.Red,
  4569. Color.Green,
  4570. LinearGradientMode.Vertical) )
  4571. {
  4572. ColorBlend colorBlend = new ColorBlend(3);
  4573. colorBlend.Colors[0] = Color.FromArgb(100, Color.Black);
  4574. colorBlend.Colors[1] = Color.Transparent;
  4575. colorBlend.Colors[2] = Color.FromArgb(140, Color.White);
  4576. colorBlend.Positions[0] = 0f;
  4577. colorBlend.Positions[1] = 0.5f;
  4578. colorBlend.Positions[2] = 1f;
  4579. brush.InterpolationColors = colorBlend;
  4580. // Fill shadow
  4581. this.FillPath( brush, path );
  4582. }
  4583. }
  4584. }
  4585. }
  4586. else if(pieDrawingStyle == PieDrawingStyle.SoftEdge)
  4587. {
  4588. // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn
  4589. // twice on the outside and inside radius.
  4590. float minSize = (float)Math.Min(position.Width, position.Height);
  4591. float shadowSize = minSize/10f;
  4592. if(doughnutRadius > 0f)
  4593. {
  4594. shadowSize = (minSize * doughnutRadius / 100f) / 8f;
  4595. }
  4596. // Create brush path
  4597. using(GraphicsPath brushPath = new GraphicsPath())
  4598. {
  4599. brushPath.AddEllipse(position);
  4600. // Create shadow path
  4601. using(GraphicsPath path = new GraphicsPath())
  4602. {
  4603. path.AddArc( position.X + shadowSize, position.Y + shadowSize, position.Width - shadowSize * 2f, position.Height - shadowSize * 2f, startAngle, sweepAngle );
  4604. path.AddArc( position.X, position.Y, position.Width, position.Height, startAngle + sweepAngle, -sweepAngle );
  4605. path.CloseFigure();
  4606. // Create shadow brush
  4607. using( PathGradientBrush brush = new PathGradientBrush(brushPath) )
  4608. {
  4609. brush.CenterColor = Color.Transparent;
  4610. brush.SurroundColors = new Color[] { Color.FromArgb(100, Color.Black) };
  4611. Blend blend = new Blend(3);
  4612. blend.Positions[0] = 0f;
  4613. blend.Factors[0] = 0f;
  4614. blend.Positions[1] = shadowSize / (minSize / 2f);
  4615. blend.Factors[1] = 1f;
  4616. blend.Positions[2] = 1f;
  4617. blend.Factors[2] = 1f;
  4618. brush.Blend = blend;
  4619. // Fill shadow
  4620. this.FillPath( brush, path );
  4621. }
  4622. }
  4623. // Draw inner shadow for the doughnut chart
  4624. if(doughnutRadius > 0f)
  4625. {
  4626. // Create brush path
  4627. using(GraphicsPath brushInsidePath = new GraphicsPath())
  4628. {
  4629. RectangleF innerPosition = position;
  4630. innerPosition.Inflate(- position.Width * doughnutRadius / 200f + shadowSize, -position.Height * doughnutRadius / 200f + shadowSize);
  4631. brushInsidePath.AddEllipse(innerPosition);
  4632. // Create shadow path
  4633. using(GraphicsPath path = new GraphicsPath())
  4634. {
  4635. path.AddArc( innerPosition.X + shadowSize, innerPosition.Y + shadowSize, innerPosition.Width - 2f * shadowSize, innerPosition.Height - 2f * shadowSize, startAngle, sweepAngle );
  4636. path.AddArc( innerPosition.X, innerPosition.Y, innerPosition.Width, innerPosition.Height, startAngle + sweepAngle, -sweepAngle );
  4637. path.CloseFigure();
  4638. // Create shadow brush
  4639. using( PathGradientBrush brushInner = new PathGradientBrush(brushInsidePath) )
  4640. {
  4641. brushInner.CenterColor = Color.FromArgb(100, Color.Black);
  4642. brushInner.SurroundColors = new Color[] { Color.Transparent };
  4643. Blend blend = new Blend(3);
  4644. blend.Positions[0] = 0f;
  4645. blend.Factors[0] = 0f;
  4646. blend.Positions[1] = shadowSize / (innerPosition.Width / 2f);
  4647. blend.Factors[1] = 1f;
  4648. blend.Positions[2] = 1f;
  4649. blend.Factors[2] = 1f;
  4650. brushInner.Blend = blend;
  4651. // Fill shadow
  4652. this.FillPath( brushInner, path );
  4653. }
  4654. }
  4655. }
  4656. }
  4657. }
  4658. }
  4659. }
  4660. /// <summary>
  4661. /// The soft shadow of the pie
  4662. /// </summary>
  4663. /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
  4664. /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
  4665. /// <param name="absRect">Rectangle of the pie in absolute coordinates</param>
  4666. /// <param name="backColor">Fill color</param>
  4667. private void DrawPieSoftShadow( float startAngle, float sweepAngle, RectangleF absRect, Color backColor )
  4668. {
  4669. GraphicsPath path = new GraphicsPath();
  4670. path.AddEllipse( absRect.X, absRect.Y, absRect.Width, absRect.Height );
  4671. PathGradientBrush brush = new PathGradientBrush( path );
  4672. Color[] colors = {
  4673. Color.FromArgb( 0, backColor ),
  4674. Color.FromArgb( backColor.A, backColor ),
  4675. Color.FromArgb( backColor.A, backColor )};
  4676. float[] relativePositions = {
  4677. 0f,
  4678. 0.05f,
  4679. 1.0f}; // at the center point.
  4680. ColorBlend colorBlend = new ColorBlend();
  4681. colorBlend.Colors = colors;
  4682. colorBlend.Positions = relativePositions;
  4683. brush.InterpolationColors = colorBlend;
  4684. this.FillPie( brush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
  4685. }
  4686. #endregion
  4687. #region Arrow Methods
  4688. /// <summary>
  4689. /// Draw Arrow.
  4690. /// </summary>
  4691. /// <param name="position">Position of the arrow</param>
  4692. /// <param name="orientation">Orientation of the arrow - left, right, top, bottom </param>
  4693. /// <param name="type">Arrow style: Triangle, Sharp Triangle, Lines</param>
  4694. /// <param name="color">Color of the arrow</param>
  4695. /// <param name="lineWidth">Line width</param>
  4696. /// <param name="lineDashStyle">Line Dash style</param>
  4697. /// <param name="shift">Distance from the chart area</param>
  4698. /// <param name="size">Arrow size</param>
  4699. internal void DrawArrowRel( PointF position, ArrowOrientation orientation, AxisArrowStyle type, Color color, int lineWidth, ChartDashStyle lineDashStyle, double shift, double size )
  4700. {
  4701. // Check if arrow should be drawn
  4702. if(type == AxisArrowStyle.None)
  4703. {
  4704. return;
  4705. }
  4706. // Set a color
  4707. using (SolidBrush brush = new SolidBrush(color))
  4708. {
  4709. PointF endPoint = PointF.Empty; // End point of axis line
  4710. PointF[] points; // arrow points
  4711. PointF absolutePosition; // Absolute position of axis
  4712. absolutePosition = GetAbsolutePoint(position);
  4713. // Arrow type is triangle
  4714. if (type == AxisArrowStyle.Triangle)
  4715. {
  4716. points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
  4717. endPoint = GetRelativePoint(endPoint);
  4718. // Draw center line
  4719. DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
  4720. // Draw arrow
  4721. this.FillPolygon(brush, points);
  4722. }
  4723. // Arrow type is sharp triangle
  4724. else if (type == AxisArrowStyle.SharpTriangle)
  4725. {
  4726. points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
  4727. endPoint = GetRelativePoint(endPoint);
  4728. // Draw center line
  4729. DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
  4730. // Draw arrow
  4731. this.FillPolygon(brush, points);
  4732. }
  4733. // Arrow type is 'Lines'
  4734. else if (type == AxisArrowStyle.Lines)
  4735. {
  4736. points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
  4737. points[0] = GetRelativePoint(points[0]);
  4738. points[1] = GetRelativePoint(points[1]);
  4739. points[2] = GetRelativePoint(points[2]);
  4740. endPoint = GetRelativePoint(endPoint);
  4741. // Draw arrow
  4742. DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
  4743. DrawLineRel(color, lineWidth, lineDashStyle, points[0], points[2]);
  4744. DrawLineRel(color, lineWidth, lineDashStyle, points[1], points[2]);
  4745. }
  4746. }
  4747. }
  4748. /// <summary>
  4749. /// This function calculates points for polygon, which represents
  4750. /// shape of an arrow. There are four different orientations
  4751. /// of arrow and three arrow types.
  4752. /// </summary>
  4753. /// <param name="position">Arrow position</param>
  4754. /// <param name="orientation">Arrow orientation ( Left, Right, Top, Bottom )</param>
  4755. /// <param name="shift">Distance from chart area to the arrow</param>
  4756. /// <param name="size">Arrow size</param>
  4757. /// <param name="type">Arrow style.</param>
  4758. /// <param name="endPoint">End point of the axis and the beginning of arrow</param>
  4759. /// <returns>Polygon points</returns>
  4760. private PointF[] GetArrowShape( PointF position, ArrowOrientation orientation, double shift, double size, AxisArrowStyle type, ref PointF endPoint )
  4761. {
  4762. PointF[] points = new PointF[3]; // Polygon points
  4763. double sharp; // Size for sharp triangle
  4764. // Four different orientations for AxisArrowStyle
  4765. switch( orientation )
  4766. {
  4767. // Top orientation
  4768. case ArrowOrientation.Top:
  4769. // Get absolute size for arrow
  4770. // Arrow size has to have the same shape when width and height
  4771. // are changed. When the picture is resized, width of the chart
  4772. // picture is used only for arrow size.
  4773. size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
  4774. shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
  4775. // Size for sharp and regular triangle
  4776. if( type == AxisArrowStyle.SharpTriangle )
  4777. sharp = size * 4;
  4778. else
  4779. sharp = size * 2;
  4780. points[0].X = position.X - (float)size;
  4781. points[0].Y = position.Y - (float)shift;
  4782. points[1].X = position.X + (float)size;
  4783. points[1].Y = position.Y - (float)shift;
  4784. points[2].X = position.X;
  4785. points[2].Y = position.Y - (float)shift - (float)sharp;
  4786. // End of the axis line
  4787. endPoint.X = position.X;
  4788. if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
  4789. endPoint.Y = points[1].Y;
  4790. else
  4791. endPoint.Y = points[2].Y;
  4792. break;
  4793. // Bottom orientation
  4794. case ArrowOrientation.Bottom:
  4795. // Get absolute size for arrow
  4796. // Arrow size has to have the same shape when width and height
  4797. // are changed. When the picture is resized, width of the chart
  4798. // picture is used only for arrow size.
  4799. size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
  4800. shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
  4801. // Size for sharp and regular triangle
  4802. if( type == AxisArrowStyle.SharpTriangle )
  4803. sharp = size * 4;
  4804. else
  4805. sharp = size * 2;
  4806. points[0].X = position.X - (float)size;
  4807. points[0].Y = position.Y + (float)shift;
  4808. points[1].X = position.X + (float)size;
  4809. points[1].Y = position.Y + (float)shift;
  4810. points[2].X = position.X;
  4811. points[2].Y = position.Y + (float)shift + (float)sharp;
  4812. // End of the axis line
  4813. endPoint.X = position.X;
  4814. if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
  4815. endPoint.Y = points[1].Y;
  4816. else
  4817. endPoint.Y = points[2].Y;
  4818. break;
  4819. // Left orientation
  4820. case ArrowOrientation.Left:
  4821. // Get absolute size for arrow
  4822. size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
  4823. shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
  4824. // Size for sharp and regular triangle
  4825. if( type == AxisArrowStyle.SharpTriangle )
  4826. sharp = size * 4;
  4827. else
  4828. sharp = size * 2;
  4829. points[0].Y = position.Y - (float)size;
  4830. points[0].X = position.X - (float)shift;
  4831. points[1].Y = position.Y + (float)size;
  4832. points[1].X = position.X - (float)shift;
  4833. points[2].Y = position.Y;
  4834. points[2].X = position.X - (float)shift - (float)sharp;
  4835. // End of the axis line
  4836. endPoint.Y = position.Y;
  4837. if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
  4838. endPoint.X = points[1].X;
  4839. else
  4840. endPoint.X = points[2].X;
  4841. break;
  4842. // Right orientation
  4843. case ArrowOrientation.Right:
  4844. // Get absolute size for arrow
  4845. size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
  4846. shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
  4847. // Size for sharp and regular triangle
  4848. if( type == AxisArrowStyle.SharpTriangle )
  4849. sharp = size * 4;
  4850. else
  4851. sharp = size * 2;
  4852. points[0].Y = position.Y - (float)size;
  4853. points[0].X = position.X + (float)shift;
  4854. points[1].Y = position.Y + (float)size;
  4855. points[1].X = position.X + (float)shift;
  4856. points[2].Y = position.Y;
  4857. points[2].X = position.X + (float)shift + (float)sharp;
  4858. // End of the axis line
  4859. endPoint.Y = position.Y;
  4860. if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
  4861. endPoint.X = points[1].X;
  4862. else
  4863. endPoint.X = points[2].X;
  4864. break;
  4865. }
  4866. return points;
  4867. }
  4868. #endregion
  4869. #region Other methods and properties
  4870. /// <summary>
  4871. /// Helper function that retrieves bar drawing style.
  4872. /// </summary>
  4873. /// <param name="point">Data point to get the drawing style for.</param>
  4874. /// <returns>Bar drawing style.</returns>
  4875. internal static BarDrawingStyle GetBarDrawingStyle(DataPoint point)
  4876. {
  4877. // Get column drawing style
  4878. BarDrawingStyle barDrawingStyle = BarDrawingStyle.Default;
  4879. string styleName = point[CustomPropertyName.DrawingStyle];
  4880. if(styleName != null)
  4881. {
  4882. if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
  4883. {
  4884. barDrawingStyle = BarDrawingStyle.Default;
  4885. }
  4886. else if (String.Compare(styleName, "Cylinder", StringComparison.OrdinalIgnoreCase) == 0)
  4887. {
  4888. barDrawingStyle = BarDrawingStyle.Cylinder;
  4889. }
  4890. else if (String.Compare(styleName, "Emboss", StringComparison.OrdinalIgnoreCase) == 0)
  4891. {
  4892. barDrawingStyle = BarDrawingStyle.Emboss;
  4893. }
  4894. else if (String.Compare(styleName, "LightToDark", StringComparison.OrdinalIgnoreCase) == 0)
  4895. {
  4896. barDrawingStyle = BarDrawingStyle.LightToDark;
  4897. }
  4898. else if (String.Compare(styleName, "Wedge", StringComparison.OrdinalIgnoreCase) == 0)
  4899. {
  4900. barDrawingStyle = BarDrawingStyle.Wedge;
  4901. }
  4902. else
  4903. {
  4904. throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid(styleName, "DrawingStyle")));
  4905. }
  4906. }
  4907. return barDrawingStyle;
  4908. }
  4909. /// <summary>
  4910. /// Find rounding coordinates for a rectangle
  4911. /// </summary>
  4912. /// <param name="rect">Rectangle which has to be rounded</param>
  4913. /// <returns>Rounded rectangle</returns>
  4914. internal RectangleF Round(RectangleF rect)
  4915. {
  4916. float left = (float)Math.Round( (double)rect.Left );
  4917. float right = (float)Math.Round( (double)rect.Right );
  4918. float top = (float)Math.Round( (double)rect.Top );
  4919. float bottom = (float)Math.Round( (double)rect.Bottom );
  4920. return new RectangleF( left, top, right - left, bottom - top );
  4921. }
  4922. /// <summary>
  4923. /// This method takes a given axis value for a specified axis and returns the relative pixel value.
  4924. /// </summary>
  4925. /// <param name="chartAreaName">Chart area name.</param>
  4926. /// <param name="axis">An AxisName enum value that identifies the relevant axis.</param>
  4927. /// <param name="axisValue">The axis value that needs to be converted to a relative pixel value.</param>
  4928. /// <returns>The converted axis value, in relative pixel coordinates.</returns>
  4929. public double GetPositionFromAxis( string chartAreaName, AxisName axis, double axisValue )
  4930. {
  4931. if( axis == AxisName.X )
  4932. return _common.ChartPicture.ChartAreas[chartAreaName].AxisX.GetLinearPosition( axisValue );
  4933. if( axis == AxisName.X2 )
  4934. return _common.ChartPicture.ChartAreas[chartAreaName].AxisX2.GetLinearPosition( axisValue );
  4935. if( axis == AxisName.Y )
  4936. return _common.ChartPicture.ChartAreas[chartAreaName].AxisY.GetLinearPosition( axisValue );
  4937. if( axis == AxisName.Y2 )
  4938. return _common.ChartPicture.ChartAreas[chartAreaName].AxisY2.GetLinearPosition( axisValue );
  4939. return 0;
  4940. }
  4941. /// <summary>
  4942. /// Set picture size
  4943. /// </summary>
  4944. /// <param name="width">Width</param>
  4945. /// <param name="height">Height</param>
  4946. internal void SetPictureSize( int width, int height )
  4947. {
  4948. this._width = width;
  4949. this._height = height;
  4950. }
  4951. /// <summary>
  4952. /// Constructor
  4953. /// </summary>
  4954. /// <param name="common">Common elements class</param>
  4955. internal ChartGraphics(CommonElements common)
  4956. {
  4957. // Set Common elements
  4958. this._common = common;
  4959. base.Common = common;
  4960. // Create a pen object
  4961. _pen = new Pen(Color.Black);
  4962. // Create a brush object
  4963. _solidBrush = new SolidBrush(Color.Black);
  4964. }
  4965. /// <summary>
  4966. /// Chart Graphics Anti alias mode
  4967. /// </summary>
  4968. internal AntiAliasingStyles AntiAliasing
  4969. {
  4970. get
  4971. {
  4972. return _antiAliasing;
  4973. }
  4974. set
  4975. {
  4976. _antiAliasing = value;
  4977. // Graphics mode not set
  4978. if( Graphics == null )
  4979. return;
  4980. // Convert Chart's anti alias enumeration to GDI+ SmoothingMode
  4981. if( (_antiAliasing & AntiAliasingStyles.Graphics) == AntiAliasingStyles.Graphics )
  4982. {
  4983. this.SmoothingMode = SmoothingMode.AntiAlias;
  4984. }
  4985. else
  4986. {
  4987. this.SmoothingMode = SmoothingMode.None;
  4988. }
  4989. }
  4990. }
  4991. /// <summary>
  4992. /// Gets reusable pen.
  4993. /// </summary>
  4994. internal Pen Pen
  4995. {
  4996. get { return _pen; }
  4997. }
  4998. /// <summary>
  4999. /// Sets the clipping region of this Graphics object
  5000. /// to the rectangle specified by a RectangleF structure.
  5001. /// </summary>
  5002. /// <param name="region">Region rectangle</param>
  5003. internal void SetClip( RectangleF region )
  5004. {
  5005. this.SetClipAbs( GetAbsoluteRectangle( region ) );
  5006. }
  5007. #endregion
  5008. #region Color manipulation methods
  5009. /// <summary>
  5010. /// Returns the gradient color from a gradient position.
  5011. /// </summary>
  5012. /// <param name="beginColor">The color from the gradient beginning</param>
  5013. /// <param name="endColor">The color from the gradient end.</param>
  5014. /// <param name="relativePosition">The relative position.</param>
  5015. /// <returns>Result color.</returns>
  5016. static internal Color GetGradientColor(Color beginColor, Color endColor, double relativePosition)
  5017. {
  5018. // Check if position is valid
  5019. if(relativePosition < 0 || relativePosition > 1 || double.IsNaN(relativePosition))
  5020. {
  5021. return beginColor;
  5022. }
  5023. // Extracts Begin color
  5024. int nBRed = beginColor.R;
  5025. int nBGreen = beginColor.G;
  5026. int nBBlue = beginColor.B;
  5027. // Extracts End color
  5028. int nERed = endColor.R;
  5029. int nEGreen = endColor.G;
  5030. int nEBlue = endColor.B;
  5031. // Gradient positions for Red, Green and Blue colors
  5032. double dRRed = nBRed + (nERed - nBRed) * relativePosition;
  5033. double dRGreen = nBGreen + (nEGreen - nBGreen) * relativePosition;
  5034. double dRBlue = nBBlue + (nEBlue - nBBlue) * relativePosition;
  5035. // Make sure colors are in range from 0 to 255
  5036. if(dRRed > 255.0)
  5037. dRRed = 255.0;
  5038. if(dRRed < 0.0)
  5039. dRRed = 0.0;
  5040. if(dRGreen > 255.0)
  5041. dRGreen = 255.0;
  5042. if(dRGreen < 0.0)
  5043. dRGreen = 0.0;
  5044. if(dRBlue > 255.0)
  5045. dRBlue = 255.0;
  5046. if(dRBlue < 0.0)
  5047. dRBlue = 0.0;
  5048. // Return a gradient color position
  5049. return Color.FromArgb(beginColor.A, (int)dRRed, (int)dRGreen, (int)dRBlue);
  5050. }
  5051. #endregion
  5052. #region RightToLeft
  5053. /// <summary>
  5054. /// Returns chart right to left flag
  5055. /// </summary>
  5056. internal bool IsRightToLeft
  5057. {
  5058. get
  5059. {
  5060. if (Common == null)
  5061. {
  5062. return false;
  5063. }
  5064. return Common.ChartPicture.RightToLeft == RightToLeft.Yes;
  5065. }
  5066. }
  5067. #endregion //RightToLeft
  5068. #region IDisposable Members
  5069. /// <summary>
  5070. /// Releases unmanaged and - optionally - managed resources
  5071. /// </summary>
  5072. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  5073. protected override void Dispose(bool disposing)
  5074. {
  5075. if (disposing)
  5076. {
  5077. // Free up managed resources
  5078. if (_pen != null)
  5079. {
  5080. _pen.Dispose();
  5081. _pen = null;
  5082. }
  5083. if (_solidBrush != null)
  5084. {
  5085. _solidBrush.Dispose();
  5086. _solidBrush = null;
  5087. }
  5088. if (_myMatrix != null)
  5089. {
  5090. _myMatrix.Dispose();
  5091. _myMatrix = null;
  5092. }
  5093. }
  5094. base.Dispose(disposing);
  5095. }
  5096. #endregion
  5097. }
  5098. }