Legend.cs 173 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084
  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 Legend consist of default and custom legend
  6. // items. Default items are automatically added based
  7. // on the data series and custom items are added by
  8. // the user. Each item usually consist of 2 cells;
  9. // series color marker and series name. Legend item
  10. // cells form vertical columns in the legend.
  11. // Please refer to the Chart documentation which
  12. // contains images and samples describing legend features.
  13. // :
  14. // NOTE: In early versions of the Chart control only 1 legend was
  15. // exposed through the Legend property of the root chart object.
  16. // Due to the customer requests, support for unlimited number of
  17. // legends was added through the LegendCollection exposed as a
  18. // Legends property in the root chart object. Old propertys was
  19. // deprecated and marked as non-browsable.
  20. //
  21. using System;
  22. using System.Windows.Forms;
  23. using System.Collections.Generic;
  24. using System.ComponentModel;
  25. using System.Diagnostics.CodeAnalysis;
  26. using System.Drawing;
  27. using System.Drawing.Design;
  28. using System.Drawing.Drawing2D;
  29. using FastReport.DataVisualization.Charting.ChartTypes;
  30. using FastReport.DataVisualization.Charting.Utilities;
  31. namespace FastReport.DataVisualization.Charting
  32. {
  33. using Size = System.Drawing.Size;
  34. #region Legend enumerations
  35. /// <summary>
  36. /// An enumeration of legend item orderings.
  37. /// </summary>
  38. public enum LegendItemOrder
  39. {
  40. /// <summary>
  41. /// Items will be added into the legend in an order automatically determined by the chart.
  42. /// </summary>
  43. Auto,
  44. /// <summary>
  45. /// Items will be added into the legend in the same order as the chart series.
  46. /// </summary>
  47. SameAsSeriesOrder,
  48. /// <summary>
  49. /// Items will be added into the legend in the same order as the chart series.
  50. /// </summary>
  51. ReversedSeriesOrder
  52. };
  53. /// <summary>
  54. /// An enumeration of legend separator styles.
  55. /// </summary>
  56. public enum LegendSeparatorStyle
  57. {
  58. /// <summary>
  59. /// No separator will be shown.
  60. /// </summary>
  61. None,
  62. /// <summary>
  63. /// Single solid line separator.
  64. /// </summary>
  65. Line,
  66. /// <summary>
  67. /// Single solid thick line separator.
  68. /// </summary>
  69. ThickLine,
  70. /// <summary>
  71. /// Double solid line separator.
  72. /// </summary>
  73. DoubleLine,
  74. /// <summary>
  75. /// Single dash line separator.
  76. /// </summary>
  77. DashLine,
  78. /// <summary>
  79. /// Single dot line separator.
  80. /// </summary>
  81. DotLine,
  82. /// <summary>
  83. /// Gradient solid line separator.
  84. /// </summary>
  85. GradientLine,
  86. /// <summary>
  87. /// Thick gradient solid line separator.
  88. /// </summary>
  89. ThickGradientLine,
  90. }
  91. /// <summary>
  92. /// An enumeration that specifies a style for a legend item's symbol.
  93. /// </summary>
  94. public enum LegendImageStyle
  95. {
  96. /// <summary>
  97. /// The symbol will be a rectangle.
  98. /// </summary>
  99. Rectangle,
  100. /// <summary>
  101. /// The symbol will be a line.
  102. /// </summary>
  103. Line,
  104. /// <summary>
  105. /// The symbol will be a marker.
  106. /// </summary>
  107. Marker
  108. }
  109. /// <summary>
  110. /// An enumeration of legend styles.
  111. /// </summary>
  112. public enum LegendStyle
  113. {
  114. /// <summary>
  115. /// One column, many rows.
  116. /// </summary>
  117. Column,
  118. /// <summary>
  119. /// One row, many columns.
  120. /// </summary>
  121. Row,
  122. /// <summary>
  123. /// Many column, many rows.
  124. /// </summary>
  125. Table
  126. };
  127. /// <summary>
  128. /// An enumeration of legend table styles.
  129. /// </summary>
  130. public enum LegendTableStyle
  131. {
  132. /// <summary>
  133. /// The legend table style is automatically determined by the chart.
  134. /// </summary>
  135. Auto,
  136. /// <summary>
  137. /// The legend items will be fit horizontally within the legend.
  138. /// It is preferred to use this style when the docking is set to top or bottom.
  139. /// </summary>
  140. Wide,
  141. /// <summary>
  142. /// The legend items will be fit vertically within the legend.
  143. /// It is preferred to use this style when docking is set to left or right.
  144. /// </summary>
  145. Tall
  146. };
  147. #endregion
  148. /// <summary>
  149. /// The legend class represents a single chart legend. It contains visual
  150. /// appearance, position and content properties. This class is also
  151. /// responsible for drawing and positioning of the legend.
  152. /// </summary>
  153. [
  154. SRDescription("DescriptionAttributeLegend_Legend"),
  155. DefaultProperty("Enabled"),
  156. ]
  157. public class Legend : ChartNamedElement
  158. {
  159. #region Fields
  160. //***********************************************************
  161. //** Private data members, which store properties values
  162. //***********************************************************
  163. private ElementPosition _position = null;
  164. private bool _enabled = true;
  165. private LegendStyle _legendStyle = LegendStyle.Table;
  166. private LegendTableStyle _legendTableStyle = LegendTableStyle.Auto;
  167. private LegendItemsCollection _customLegends = null;
  168. private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
  169. private string _backImage = "";
  170. private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile;
  171. private Color _backImageTransparentColor = Color.Empty;
  172. private ChartImageAlignmentStyle _backImageAlignment = ChartImageAlignmentStyle.TopLeft;
  173. private GradientStyle _backGradientStyle = GradientStyle.None;
  174. private Color _backSecondaryColor = Color.Empty;
  175. private Color _borderColor = Color.Empty;
  176. private Color _backColor = Color.Empty;
  177. private int _borderWidth = 1;
  178. private ChartDashStyle _borderDashStyle = ChartDashStyle.Solid;
  179. private FontCache _fontCache = new FontCache();
  180. private Font _font = null;
  181. private Color _foreColor = Color.Black;
  182. private StringAlignment _legendAlignment = StringAlignment.Near;
  183. private Docking _legendDocking = Docking.Right;
  184. private int _shadowOffset = 0;
  185. private Color _shadowColor = Color.FromArgb(128, 0, 0, 0);
  186. private bool _isTextAutoFit = true;
  187. private string _dockedToChartArea = Constants.NotSetValue;
  188. private bool _isDockedInsideChartArea = true;
  189. //***********************************************************
  190. //** Private data members
  191. //***********************************************************
  192. // Collection of custom and series legend items
  193. internal LegendItemsCollection legendItems = null;
  194. // Number of rows and columns
  195. private int _itemColumns = 0;
  196. // Font calculated by auto fitting
  197. internal Font autofitFont = null;
  198. // Indicates that all items in the legend should be equally spaced
  199. private bool _isEquallySpacedItems = false;
  200. // Indicate that legend rows should be drawn with isInterlaced background color.
  201. private bool _interlacedRows = false;
  202. // Legend isInterlaced rows color
  203. private Color _interlacedRowsColor = Color.Empty;
  204. // Legend offsets
  205. private Size _offset = Size.Empty;
  206. // Adjustment point used for legend animation
  207. private float _maximumLegendAutoSize = 50f;
  208. // Text length after which the legend item text will be wrapped on the next whitespace.
  209. private int _textWrapThreshold = 25;
  210. // Value used to calculate auto-fit font size from the legend Font.
  211. private int _autoFitFontSizeAdjustment = 0;
  212. // Legend column collection
  213. private LegendCellColumnCollection _cellColumns = null;
  214. // Indicates that legend items automatically added based on the exsisting
  215. // series in reversed order.
  216. private LegendItemOrder _legendItemOrder = LegendItemOrder.Auto;
  217. // Legend title text
  218. private string _title = String.Empty;
  219. // Legend title color
  220. private Color _titleForeColor = Color.Black;
  221. // Legend title back color
  222. private Color _titleBackColor = Color.Empty;
  223. // Legend title font
  224. private Font _titleFont = null;
  225. // Legend title alignment
  226. private StringAlignment _titleAlignment = StringAlignment.Center;
  227. // Legend title visual separator
  228. private LegendSeparatorStyle _titleSeparator = LegendSeparatorStyle.None;
  229. // Legend title visual separator color
  230. private Color _titleSeparatorColor = Color.Black;
  231. // Legend header visual separator
  232. private LegendSeparatorStyle _headerSeparator = LegendSeparatorStyle.None;
  233. // Legend header visual separator color
  234. private Color _headerSeparatorColor = Color.Black;
  235. // Legend table columns visual separator
  236. private LegendSeparatorStyle _itemColumnSeparator = LegendSeparatorStyle.None;
  237. // Legend table columns visual separator color
  238. private Color _itemColumnSeparatorColor = Color.Black;
  239. // Legend table column spacing calculated as a percentage of the font
  240. private int _itemColumnSpacing = 50;
  241. // Legend table column spacing calculated in relative coordinates
  242. private int _itemColumnSpacingRel = 0;
  243. // Legend title position in pixelcoordinates.
  244. // Note that legend title always docked to the top of the legend.
  245. private Rectangle _titlePosition = Rectangle.Empty;
  246. // Legend header position in pixel coordinates.
  247. private Rectangle _headerPosition = Rectangle.Empty;
  248. // Minimum font size that can be used by the legend auto-fitting algorithm
  249. private int _autoFitMinFontSize = 7;
  250. // Horizontal space left after fitting legend items
  251. private int _horizontalSpaceLeft = 0;
  252. // Vertical space left after fitting legend items
  253. private int _verticalSpaceLeft = 0;
  254. // Sub-columns sizes calculated during the fitting process
  255. private int[,] _subColumnSizes = null;
  256. // Legend item heigts
  257. private int[,] _cellHeights = null;
  258. // Number of rows per each legend table column
  259. private int[] _numberOfRowsPerColumn = null;
  260. // Number of items from the collection that should be processed
  261. private int _numberOfLegendItemsToProcess = -1;
  262. // Legend items area position in pixels
  263. private Rectangle _legendItemsAreaPosition = Rectangle.Empty;
  264. // Indicates that not all legend items were able to fit the legend
  265. private bool _legendItemsTruncated = false;
  266. // Size of the dots (pixels) that will drawn on the bottom of the legend when it is truncated
  267. private int _truncatedDotsSize = 3;
  268. // Maximum number of cells in the legend item
  269. private int _numberOfCells = -1;
  270. // Pixel size of the 'W' character
  271. internal Size singleWCharacterSize = Size.Empty;
  272. #endregion
  273. #region Constructors
  274. /// <summary>
  275. /// Legend constructor
  276. /// </summary>
  277. public Legend()
  278. {
  279. _position = new ElementPosition(this);
  280. // Initialize custom items collection
  281. _customLegends = new LegendItemsCollection(this);
  282. legendItems = new LegendItemsCollection(this);
  283. _cellColumns = new LegendCellColumnCollection(this);
  284. _font = _fontCache.DefaultFont;
  285. _titleFont = _fontCache.DefaultBoldFont;
  286. }
  287. /// <summary>
  288. /// Legend constructor
  289. /// </summary>
  290. /// <param name="name">The legend name.</param>
  291. public Legend(string name) : base (name)
  292. {
  293. _position = new ElementPosition(this);
  294. // Initialize custom items collection
  295. _customLegends = new LegendItemsCollection(this);
  296. legendItems = new LegendItemsCollection(this);
  297. _cellColumns = new LegendCellColumnCollection(this);
  298. _font = _fontCache.DefaultFont;
  299. _titleFont = _fontCache.DefaultBoldFont;
  300. }
  301. #endregion
  302. #region Legend position & size methods
  303. /// <summary>
  304. /// Recalculates legend information:
  305. /// - legend items collection
  306. /// - maximum text rectangle
  307. /// </summary>
  308. /// <param name="chartGraph">Reference to the chart graphics.</param>
  309. private void RecalcLegendInfo(ChartGraphics chartGraph)
  310. {
  311. // Reset some values
  312. RectangleF legendPositionRel = _position.ToRectangleF();
  313. Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(legendPositionRel));
  314. //***********************************************************
  315. //** Use size of the "W" characters in current font to
  316. //** calculate legend spacing
  317. //***********************************************************
  318. this.singleWCharacterSize = chartGraph.MeasureStringAbs("W", this.Font);
  319. Size doubleCharacterSize = chartGraph.MeasureStringAbs("WW", this.Font);
  320. this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
  321. // Calculate left, top offset and column spacing
  322. this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
  323. this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
  324. // Calculate item column spacing and make sure it is dividable by 2
  325. this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
  326. if(this._itemColumnSpacingRel % 2 == 1)
  327. {
  328. this._itemColumnSpacingRel += 1;
  329. }
  330. //***********************************************************
  331. //** Calculate how much space required for the title.
  332. //***********************************************************
  333. this._titlePosition = Rectangle.Empty;
  334. if(this.Title.Length > 0)
  335. {
  336. // Measure title text size
  337. Size titleSize = this.GetTitleSize(chartGraph, legendPosition.Size);
  338. // Set legend title position
  339. this._titlePosition = new Rectangle(
  340. legendPosition.Location.X,
  341. legendPosition.Location.Y,
  342. legendPosition.Width,
  343. Math.Min(legendPosition.Height, titleSize.Height));
  344. // Adjust legend items position height
  345. legendPosition.Height -= this._titlePosition.Height;
  346. // Increase title top location by border height
  347. this._titlePosition.Y += this.GetBorderSize();
  348. }
  349. //***********************************************************
  350. //** Calculate how much space required for the header.
  351. //***********************************************************
  352. this._headerPosition = Rectangle.Empty;
  353. // Find the largest (height only) header
  354. Size highestHeader = Size.Empty;
  355. foreach(LegendCellColumn legendColumn in this.CellColumns)
  356. {
  357. if(legendColumn.HeaderText.Length > 0)
  358. {
  359. // Measure header text size
  360. Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
  361. // Get header with maximum height
  362. highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
  363. }
  364. }
  365. // Check if any headers where found
  366. if(!highestHeader.IsEmpty)
  367. {
  368. // Set legend header position
  369. this._headerPosition = new Rectangle(
  370. legendPosition.Location.X + this.GetBorderSize() + this._offset.Width,
  371. legendPosition.Location.Y + this._titlePosition.Height,
  372. legendPosition.Width - (this.GetBorderSize() + this._offset.Width) * 2,
  373. Math.Min(legendPosition.Height - this._titlePosition.Height, highestHeader.Height));
  374. this._headerPosition.Height = Math.Max(this._headerPosition.Height, 0);
  375. // Adjust legend items position height
  376. legendPosition.Height -= this._headerPosition.Height;
  377. // Increase header top location by border height
  378. this._headerPosition.Y += this.GetBorderSize();
  379. }
  380. //***********************************************************
  381. //** Calculate size available for all legend items
  382. //***********************************************************
  383. this._legendItemsAreaPosition = new Rectangle(
  384. legendPosition.X + this._offset.Width + this.GetBorderSize(),
  385. legendPosition.Y + this._offset.Height + this.GetBorderSize() + this._titlePosition.Height + this._headerPosition.Height,
  386. legendPosition.Width - 2 * (this._offset.Width + this.GetBorderSize()),
  387. legendPosition.Height - 2 * (this._offset.Height + this.GetBorderSize()) );
  388. //***********************************************************
  389. //** Calculate number of rows and columns depending on
  390. //** the legend style
  391. //***********************************************************
  392. this.GetNumberOfRowsAndColumns(
  393. chartGraph,
  394. this._legendItemsAreaPosition.Size,
  395. -1,
  396. out this._numberOfRowsPerColumn,
  397. out this._itemColumns,
  398. out this._horizontalSpaceLeft,
  399. out this._verticalSpaceLeft);
  400. //***********************************************************
  401. //** Try to fit all legend item cells reducing the font size
  402. //***********************************************************
  403. // Reset auto-fit font adjustment value and truncated legend flag
  404. this._autoFitFontSizeAdjustment = 0;
  405. this._legendItemsTruncated = false;
  406. // Check if legend items fit into the legend area
  407. bool autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
  408. // Calculate total number of items fit and make sure we fit all of them
  409. this._numberOfLegendItemsToProcess = this.legendItems.Count;
  410. int itemsFit = 0;
  411. for(int index = 0; index < this._itemColumns; index++)
  412. {
  413. itemsFit += this._numberOfRowsPerColumn[index];
  414. }
  415. if(itemsFit < this._numberOfLegendItemsToProcess)
  416. {
  417. autoFitDone = false;
  418. }
  419. // If items do not fit try reducing font or number of legend items
  420. this.autofitFont = this.Font;
  421. if(!autoFitDone)
  422. {
  423. do
  424. {
  425. // Check if legend item font size can be reduced
  426. if(this.IsTextAutoFit &&
  427. (this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
  428. {
  429. // Reduce font size by one
  430. ++this._autoFitFontSizeAdjustment;
  431. // Calculate new font size
  432. int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
  433. if(newFontSize < 1)
  434. {
  435. // Font can't be less than size 1
  436. newFontSize = 1;
  437. }
  438. // Create new font
  439. this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
  440. this.Font.FontFamily,
  441. newFontSize,
  442. this.Font.Style,
  443. this.Font.Unit);
  444. // Calculate number of rows and columns
  445. this.GetNumberOfRowsAndColumns(
  446. chartGraph,
  447. this._legendItemsAreaPosition.Size,
  448. -1,
  449. out this._numberOfRowsPerColumn,
  450. out this._itemColumns,
  451. out this._horizontalSpaceLeft,
  452. out this._verticalSpaceLeft);
  453. autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
  454. // Calculate total number of items fit and make sure we fit all of them
  455. itemsFit = 0;
  456. for(int index = 0; index < this._itemColumns; index++)
  457. {
  458. itemsFit += this._numberOfRowsPerColumn[index];
  459. }
  460. if(itemsFit < this._numberOfLegendItemsToProcess)
  461. {
  462. autoFitDone = false;
  463. }
  464. }
  465. else
  466. {
  467. // If font size cannot be reduced start removing legend items
  468. if(this._numberOfLegendItemsToProcess > 2)
  469. {
  470. // Handle case of 1 column that do not fit horizontally
  471. if(this._itemColumns == 1 && (this._horizontalSpaceLeft < 0 && this._verticalSpaceLeft >= 0))
  472. {
  473. autoFitDone = true;
  474. this._numberOfLegendItemsToProcess =
  475. Math.Min(this._numberOfLegendItemsToProcess, this._numberOfRowsPerColumn[0]);
  476. }
  477. // Handle case of 1 row that do not fit vertically
  478. else if(this.GetMaximumNumberOfRows() == 1 && (this._verticalSpaceLeft < 0 && this._horizontalSpaceLeft >= 0))
  479. {
  480. autoFitDone = true;
  481. this._numberOfLegendItemsToProcess =
  482. Math.Min(this._numberOfLegendItemsToProcess, this._itemColumns);
  483. }
  484. else
  485. {
  486. // Adjust legend items area height by size required to show
  487. // visually (dots) that legend is truncated
  488. if(!this._legendItemsTruncated)
  489. {
  490. this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
  491. }
  492. // Remove last legend item
  493. this._legendItemsTruncated = true;
  494. --this._numberOfLegendItemsToProcess;
  495. // RecalculateAxesScale number of rows and columns
  496. this.GetNumberOfRowsAndColumns(
  497. chartGraph,
  498. this._legendItemsAreaPosition.Size,
  499. this._numberOfLegendItemsToProcess,
  500. out this._numberOfRowsPerColumn,
  501. out this._itemColumns);
  502. }
  503. // Make sure we show truncated legend symbols when not all items shown
  504. if(autoFitDone &&
  505. !this._legendItemsTruncated &&
  506. this._numberOfLegendItemsToProcess < this.legendItems.Count)
  507. {
  508. // Adjust legend items area height by size required to show
  509. // visually (dots) that legend is truncated
  510. this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
  511. // Legend is truncated
  512. this._legendItemsTruncated = true;
  513. }
  514. }
  515. else
  516. {
  517. autoFitDone = true;
  518. }
  519. // Check if legend items fit into the legend area
  520. if(!autoFitDone)
  521. {
  522. autoFitDone = this.CheckLegendItemsFit(
  523. chartGraph,
  524. this._legendItemsAreaPosition.Size,
  525. this._numberOfLegendItemsToProcess,
  526. this._autoFitFontSizeAdjustment,
  527. this._itemColumns,
  528. this._numberOfRowsPerColumn,
  529. out this._subColumnSizes,
  530. out this._cellHeights,
  531. out this._horizontalSpaceLeft,
  532. out this._verticalSpaceLeft);
  533. }
  534. }
  535. } while(!autoFitDone);
  536. }
  537. //***********************************************************
  538. //** Calculate position of all cells
  539. //***********************************************************
  540. // Calculate item vertical spacing in relative coordinates but rounded on pixel boundary
  541. Size itemHalfSpacing = Size.Empty;
  542. if(this._verticalSpaceLeft > 0)
  543. {
  544. itemHalfSpacing.Height = (int)(this._verticalSpaceLeft / this.GetMaximumNumberOfRows() / 2);
  545. }
  546. if(this._horizontalSpaceLeft > 0)
  547. {
  548. itemHalfSpacing.Width = (int)(_horizontalSpaceLeft / 2);
  549. }
  550. // Iterate through all legend items
  551. int currentColumn = 0;
  552. int currentRow = 0;
  553. if(this._numberOfLegendItemsToProcess < 0)
  554. {
  555. this._numberOfLegendItemsToProcess = this.legendItems.Count;
  556. }
  557. for(int legendItemIndex = 0; legendItemIndex < this._numberOfLegendItemsToProcess; legendItemIndex++)
  558. {
  559. LegendItem legendItem = this.legendItems[legendItemIndex];
  560. // Iterate through legend item cells
  561. for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
  562. {
  563. // Get legend cell
  564. LegendCell legendCell = legendItem.Cells[cellIndex];
  565. // Calculate cell position
  566. Rectangle cellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex, itemHalfSpacing);
  567. // Check if current cell spans through more than 1 cell
  568. int overlappedCellsNumber = 0;
  569. if(legendCell.CellSpan > 1)
  570. {
  571. for(int spanIndex = 1; spanIndex < legendCell.CellSpan && (cellIndex + spanIndex) < legendItem.Cells.Count; spanIndex++)
  572. {
  573. // Calculate overlapped cell position
  574. Rectangle overlappedCellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex + spanIndex, itemHalfSpacing);
  575. // Adjust current cell right position
  576. if(cellPosition.Right < overlappedCellPosition.Right)
  577. {
  578. cellPosition.Width += overlappedCellPosition.Right - cellPosition.Right;
  579. }
  580. // Increase number of overlapped cells
  581. ++overlappedCellsNumber;
  582. // Set empty size for the overlapped cells
  583. LegendCell overlappedLegendCell = legendItem.Cells[cellIndex + spanIndex];
  584. overlappedLegendCell.SetCellPosition(
  585. currentRow,
  586. Rectangle.Empty,
  587. this.singleWCharacterSize);
  588. }
  589. }
  590. // Make sure cell is drawn inside the legend
  591. cellPosition.Intersect(this._legendItemsAreaPosition);
  592. // Set cell object position
  593. legendCell.SetCellPosition(
  594. currentRow,
  595. cellPosition,
  596. this.singleWCharacterSize);
  597. // Skip overlapped cells
  598. cellIndex += overlappedCellsNumber;
  599. }
  600. // Advance to the next row/column. Break if number of legend items exceed
  601. // number of availabale rows/columns.
  602. ++currentRow;
  603. if(currentRow >= this._numberOfRowsPerColumn[currentColumn])
  604. {
  605. ++currentColumn;
  606. currentRow = 0;
  607. if(currentColumn >= this._itemColumns)
  608. {
  609. break;
  610. }
  611. }
  612. }
  613. }
  614. /// <summary>
  615. /// Gets single cell position in relative coordinates.
  616. /// </summary>
  617. /// <param name="columnIndex">Cell column index.</param>
  618. /// <param name="rowIndex">Cell row index.</param>
  619. /// <param name="cellIndex">Index of the cell in the legend item.</param>
  620. /// <param name="itemHalfSpacing">Half legend item spacing in relative coordinates.</param>
  621. /// <returns></returns>
  622. private Rectangle GetCellPosition(
  623. int columnIndex,
  624. int rowIndex,
  625. int cellIndex,
  626. Size itemHalfSpacing)
  627. {
  628. Rectangle cellPosition = this._legendItemsAreaPosition;
  629. //*****************************************************************
  630. //** Get cell Top location
  631. //*****************************************************************
  632. for(int index = 0; index < rowIndex; index++)
  633. {
  634. cellPosition.Y += this._cellHeights[columnIndex, index];
  635. }
  636. if(itemHalfSpacing.Height > 0)
  637. {
  638. cellPosition.Y += itemHalfSpacing.Height * rowIndex * 2 + itemHalfSpacing.Height;
  639. }
  640. //*****************************************************************
  641. //** Get cell Left location
  642. //*****************************************************************
  643. // Add extar space left after auto fitting
  644. if(this._horizontalSpaceLeft > 0)
  645. {
  646. cellPosition.X += itemHalfSpacing.Width;
  647. }
  648. // Calculate how many sub-columns (cells) this legend has
  649. int numberOfSubColumns = this.GetNumberOfCells();
  650. // Iterate through all prev. columns
  651. for(int index = 0; index < columnIndex; index++)
  652. {
  653. // Add width of previous columns
  654. for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++)
  655. {
  656. cellPosition.X += this._subColumnSizes[index, subColumnIndex];
  657. }
  658. // Add width of separator for the previous columns
  659. cellPosition.X += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
  660. }
  661. // Add width of current column cells
  662. for(int subColumnIndex = 0; subColumnIndex < cellIndex; subColumnIndex++)
  663. {
  664. cellPosition.X += this._subColumnSizes[columnIndex, subColumnIndex];
  665. }
  666. //*****************************************************************
  667. //** Get cell Height
  668. //*****************************************************************
  669. cellPosition.Height = this._cellHeights[columnIndex, rowIndex];
  670. //*****************************************************************
  671. //** Get cell Width
  672. //*****************************************************************
  673. cellPosition.Width = this._subColumnSizes[columnIndex, cellIndex];
  674. return cellPosition;
  675. }
  676. /// <summary>
  677. /// Calculates the optimal size of the legend.
  678. /// </summary>
  679. /// <param name="chartGraph">Chart graphics object.</param>
  680. /// <param name="maxSizeRel">Max size for the legend.</param>
  681. /// <returns>Legend optimal size.</returns>
  682. private SizeF GetOptimalSize(ChartGraphics chartGraph, SizeF maxSizeRel)
  683. {
  684. // Reset some values
  685. this._offset = Size.Empty;
  686. this._itemColumns = 0;
  687. this._horizontalSpaceLeft = 0;
  688. this._verticalSpaceLeft = 0;
  689. this._subColumnSizes = null;
  690. this._numberOfRowsPerColumn = null;
  691. this._cellHeights = null;
  692. this.autofitFont = null;
  693. this._autoFitFontSizeAdjustment = 0;
  694. this._numberOfCells = -1;
  695. this._numberOfLegendItemsToProcess = -1;
  696. Size optimalSize = Size.Empty;
  697. // Convert to pixels
  698. SizeF maxSizeAbs = chartGraph.GetAbsoluteSize(maxSizeRel);
  699. Size maxSize = new Size((int)maxSizeAbs.Width, (int)maxSizeAbs.Height);
  700. // Clear all legend item cells cached information
  701. foreach(LegendItem legendItem in this.legendItems)
  702. {
  703. foreach(LegendCell cell in legendItem.Cells)
  704. {
  705. cell.ResetCache();
  706. }
  707. }
  708. // Check if legend is enabled
  709. if(this.IsEnabled())
  710. {
  711. // Add all series legend into items collection and then add custom legend items
  712. FillLegendItemsCollection();
  713. // Call a notification event, so that legend items collection can be modified by user
  714. this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
  715. // Check if there are any items in the legend
  716. if(this.legendItems.Count > 0)
  717. {
  718. //***********************************************************
  719. //** Use size of the "W" character in current font to
  720. //** calculate legend spacing
  721. //***********************************************************
  722. this.singleWCharacterSize = chartGraph.MeasureStringAbs("W", this.Font);
  723. Size doubleCharacterSize = chartGraph.MeasureStringAbs("WW", this.Font);
  724. this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
  725. // Calculate left, top offset and column spacing
  726. this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
  727. this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
  728. this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
  729. if(this._itemColumnSpacingRel % 2 == 1)
  730. {
  731. this._itemColumnSpacingRel += 1;
  732. }
  733. //***********************************************************
  734. //** Add size required for the legend tile
  735. //***********************************************************
  736. Size titleSize = Size.Empty;
  737. if(this.Title.Length > 0)
  738. {
  739. titleSize = this.GetTitleSize(chartGraph, maxSize);
  740. }
  741. //***********************************************************
  742. //** Add size required for the legend header
  743. //***********************************************************
  744. Size highestHeader = Size.Empty;
  745. foreach(LegendCellColumn legendColumn in this.CellColumns)
  746. {
  747. if(legendColumn.HeaderText.Length > 0)
  748. {
  749. // Measure header text size
  750. Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
  751. // Get header with maximum height
  752. highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
  753. }
  754. }
  755. //***********************************************************
  756. //** Calculate size available for legend items
  757. //***********************************************************
  758. Size legenItemsMaxSize = maxSize;
  759. legenItemsMaxSize.Width -= 2 * (this._offset.Width + this.GetBorderSize());
  760. legenItemsMaxSize.Height -= 2 * (this._offset.Height + this.GetBorderSize());
  761. legenItemsMaxSize.Height -= titleSize.Height;
  762. legenItemsMaxSize.Height -= highestHeader.Height;
  763. //***********************************************************
  764. //** Calculate number of rows and columns depending on
  765. //** the legend style
  766. //***********************************************************
  767. this._autoFitFontSizeAdjustment = 0;
  768. this.autofitFont = this.Font;
  769. int vertSpaceLeft = 0;
  770. int horizSpaceLeft = 0;
  771. bool reduceFont = this.IsTextAutoFit;
  772. bool autoFit = false;
  773. do
  774. {
  775. // Get number of columns and rows that we can fit in the legend
  776. this.GetNumberOfRowsAndColumns(
  777. chartGraph,
  778. legenItemsMaxSize,
  779. -1,
  780. out this._numberOfRowsPerColumn,
  781. out this._itemColumns,
  782. out horizSpaceLeft,
  783. out vertSpaceLeft);
  784. // Calculate total number of items fit and make sure we fit all of them
  785. int itemsFit = 0;
  786. for(int index = 0; index < this._itemColumns; index++)
  787. {
  788. itemsFit += this._numberOfRowsPerColumn[index];
  789. }
  790. autoFit = (horizSpaceLeft >= 0 && vertSpaceLeft >= 0 && itemsFit >= this.legendItems.Count);
  791. // Check if items fit
  792. if(reduceFont && !autoFit)
  793. {
  794. if((this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
  795. {
  796. // Reduce font size by one
  797. ++this._autoFitFontSizeAdjustment;
  798. // Calculate new font size
  799. int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
  800. if(newFontSize < 1)
  801. {
  802. // Font can't be less than size 1
  803. newFontSize = 1;
  804. }
  805. // Create new font
  806. this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
  807. this.Font.FontFamily,
  808. newFontSize,
  809. this.Font.Style,
  810. this.Font.Unit);
  811. }
  812. else
  813. {
  814. reduceFont = false;
  815. }
  816. }
  817. } while(reduceFont && !autoFit);
  818. // Slightly reduce used space
  819. horizSpaceLeft -= Math.Min(4, horizSpaceLeft);
  820. vertSpaceLeft -= Math.Min(2, vertSpaceLeft);
  821. //***********************************************************
  822. //** Calculate legend size
  823. //***********************************************************
  824. optimalSize.Width = (legenItemsMaxSize.Width - horizSpaceLeft);
  825. optimalSize.Width = Math.Max(optimalSize.Width, titleSize.Width);
  826. optimalSize.Width += 2 * (this._offset.Width + this.GetBorderSize());
  827. optimalSize.Height = (legenItemsMaxSize.Height - vertSpaceLeft) + titleSize.Height + highestHeader.Height;
  828. optimalSize.Height += 2 * (this._offset.Height + this.GetBorderSize());
  829. // Adjust legend items area height by size required to show
  830. // visually (dots) that legend is truncated
  831. if(horizSpaceLeft < 0 || vertSpaceLeft < 0)
  832. {
  833. optimalSize.Height += this._truncatedDotsSize;
  834. }
  835. //***********************************************************
  836. //** Make sure legend size do not exceed max. value
  837. //***********************************************************
  838. if(optimalSize.Width > maxSize.Width)
  839. {
  840. optimalSize.Width = maxSize.Width;
  841. }
  842. if(optimalSize.Height > maxSize.Height)
  843. {
  844. optimalSize.Height = maxSize.Height;
  845. }
  846. if(optimalSize.Width < 0)
  847. {
  848. optimalSize.Width = 0;
  849. }
  850. if(optimalSize.Height < 0)
  851. {
  852. optimalSize.Height = 0;
  853. }
  854. }
  855. }
  856. // Convert result size from pixel to relative coordinates
  857. return chartGraph.GetRelativeSize(optimalSize);
  858. }
  859. /// <summary>
  860. /// Recalculates legend position.
  861. /// </summary>
  862. /// <param name="chartGraph">Chart graphics used.</param>
  863. /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
  864. /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
  865. internal void CalcLegendPosition(
  866. ChartGraphics chartGraph,
  867. ref RectangleF chartAreasRectangle,
  868. float elementSpacing)
  869. {
  870. RectangleF legendPosition = new RectangleF();
  871. // Get optimal legend size
  872. SizeF maxSize = new SizeF(chartAreasRectangle.Width - 2*elementSpacing, chartAreasRectangle.Height - 2*elementSpacing);
  873. if (this.DockedToChartArea == Constants.NotSetValue)
  874. {
  875. // Note: 'maxLegendSize' parameter is ignored. New legend property
  876. // 'maximumLegendAutoSize' is used instead.
  877. if(this.Docking == Docking.Top || this.Docking == Docking.Bottom)
  878. {
  879. maxSize.Height = (maxSize.Height / 100F) * this._maximumLegendAutoSize;
  880. }
  881. else
  882. {
  883. maxSize.Width = (maxSize.Width / 100F) * this._maximumLegendAutoSize;
  884. }
  885. }
  886. if(maxSize.Width <= 0 || maxSize.Height <= 0)
  887. {
  888. return;
  889. }
  890. SizeF legendSize = this.GetOptimalSize(chartGraph, maxSize);
  891. legendPosition.Height = legendSize.Height;
  892. legendPosition.Width = legendSize.Width;
  893. if(float.IsNaN(legendSize.Height) || float.IsNaN(legendSize.Width))
  894. {
  895. return;
  896. }
  897. // Calculate legend position
  898. if(this.Docking == Docking.Top)
  899. {
  900. legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
  901. if(this.Alignment == StringAlignment.Near)
  902. {
  903. legendPosition.X = chartAreasRectangle.X + elementSpacing;
  904. }
  905. else if(this.Alignment == StringAlignment.Far)
  906. {
  907. legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
  908. }
  909. else if(this.Alignment == StringAlignment.Center)
  910. {
  911. legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
  912. }
  913. // Adjust position of the chart area(s)
  914. chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
  915. chartAreasRectangle.Y = legendPosition.Bottom;
  916. }
  917. else if(this.Docking == Docking.Bottom)
  918. {
  919. legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
  920. if(this.Alignment == StringAlignment.Near)
  921. {
  922. legendPosition.X = chartAreasRectangle.X + elementSpacing;
  923. }
  924. else if(this.Alignment == StringAlignment.Far)
  925. {
  926. legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
  927. }
  928. else if(this.Alignment == StringAlignment.Center)
  929. {
  930. legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
  931. }
  932. // Adjust position of the chart area(s)
  933. chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
  934. }
  935. if(this.Docking == Docking.Left)
  936. {
  937. legendPosition.X = chartAreasRectangle.X + elementSpacing;
  938. if(this.Alignment == StringAlignment.Near)
  939. {
  940. legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
  941. }
  942. else if(this.Alignment == StringAlignment.Far)
  943. {
  944. legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
  945. }
  946. else if(this.Alignment == StringAlignment.Center)
  947. {
  948. legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
  949. }
  950. // Adjust position of the chart area(s)
  951. chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
  952. chartAreasRectangle.X = legendPosition.Right;
  953. }
  954. if(this.Docking == Docking.Right)
  955. {
  956. legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
  957. if(this.Alignment == StringAlignment.Near)
  958. {
  959. legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
  960. }
  961. else if(this.Alignment == StringAlignment.Far)
  962. {
  963. legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
  964. }
  965. else if(this.Alignment == StringAlignment.Center)
  966. {
  967. legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
  968. }
  969. // Adjust position of the chart area(s)
  970. chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
  971. }
  972. this.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
  973. }
  974. /// <summary>
  975. /// Get number of columns and rows that can be fit in specified size.
  976. /// </summary>
  977. /// <param name="chartGraph">Chart graphics.</param>
  978. /// <param name="legendSize">Legend size.</param>
  979. /// <param name="numberOfItemsToCheck">Number of legend items to check.</param>
  980. /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
  981. /// <param name="columnNumber">Returns number of columns.</param>
  982. private void GetNumberOfRowsAndColumns(
  983. ChartGraphics chartGraph,
  984. Size legendSize,
  985. int numberOfItemsToCheck,
  986. out int[] numberOfRowsPerColumn,
  987. out int columnNumber)
  988. {
  989. int horSpaceLeft = 0;
  990. int vertSpaceLeft = 0;
  991. this.GetNumberOfRowsAndColumns(
  992. chartGraph,
  993. legendSize,
  994. numberOfItemsToCheck,
  995. out numberOfRowsPerColumn,
  996. out columnNumber,
  997. out horSpaceLeft,
  998. out vertSpaceLeft);
  999. }
  1000. /// <summary>
  1001. /// Get number of columns and rows that can be fit in specified size.
  1002. /// </summary>
  1003. /// <param name="chartGraph">Chart graphics.</param>
  1004. /// <param name="legendSize">Legend size.</param>
  1005. /// <param name="numberOfItemsToCheck">Legend items number to check.</param>
  1006. /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
  1007. /// <param name="columnNumber">Returns number of columns.</param>
  1008. /// <param name="horSpaceLeft">Returns horizontal spacing left.</param>
  1009. /// <param name="vertSpaceLeft">Returns vertical spacing left.</param>
  1010. private void GetNumberOfRowsAndColumns(
  1011. ChartGraphics chartGraph,
  1012. Size legendSize,
  1013. int numberOfItemsToCheck,
  1014. out int[] numberOfRowsPerColumn,
  1015. out int columnNumber,
  1016. out int horSpaceLeft,
  1017. out int vertSpaceLeft)
  1018. {
  1019. // Initialize output parameters
  1020. numberOfRowsPerColumn = null;
  1021. columnNumber = 1;
  1022. horSpaceLeft = 0;
  1023. vertSpaceLeft = 0;
  1024. // If number of items to check is nor set use total number of items in the collection
  1025. if(numberOfItemsToCheck < 0)
  1026. {
  1027. numberOfItemsToCheck = legendItems.Count;
  1028. }
  1029. // Check legend style
  1030. if(this.LegendStyle == LegendStyle.Column || numberOfItemsToCheck <= 1)
  1031. {
  1032. columnNumber = 1;
  1033. numberOfRowsPerColumn = new int[] { numberOfItemsToCheck };
  1034. }
  1035. else if(this.LegendStyle == LegendStyle.Row)
  1036. {
  1037. columnNumber = numberOfItemsToCheck;
  1038. numberOfRowsPerColumn = new int[columnNumber];
  1039. for(int index = 0; index < columnNumber; index++)
  1040. {
  1041. numberOfRowsPerColumn[index] = 1;
  1042. }
  1043. }
  1044. else if(this.LegendStyle == LegendStyle.Table)
  1045. {
  1046. // Start with 1 column and 1 row
  1047. columnNumber = 1;
  1048. numberOfRowsPerColumn = new int[] { 1 };
  1049. // Get legend table style and adjust number of columns and rows accordinly
  1050. LegendTableStyle tableStyle = this.GetLegendTableStyle(chartGraph);
  1051. //*********************************************************************************
  1052. //** Tall table layout
  1053. //*********************************************************************************
  1054. if(tableStyle == LegendTableStyle.Tall)
  1055. {
  1056. // Iterate from second item trying to add them and check if their fit
  1057. bool exitLoop = false;
  1058. int legendItemIndex = 1;
  1059. for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
  1060. {
  1061. // Try to increase number of rows in the current column
  1062. ++numberOfRowsPerColumn[columnNumber - 1];
  1063. // Check if legend items fit into the legend area
  1064. bool autoFitDone = this.CheckLegendItemsFit(
  1065. chartGraph,
  1066. legendSize,
  1067. legendItemIndex + 1,
  1068. this._autoFitFontSizeAdjustment,
  1069. columnNumber,
  1070. numberOfRowsPerColumn,
  1071. out this._subColumnSizes,
  1072. out this._cellHeights,
  1073. out horSpaceLeft,
  1074. out vertSpaceLeft);
  1075. // Check if we fit or if we have just one column that do not fit
  1076. // horizontally but still have vertical space.
  1077. if(autoFitDone ||
  1078. ( (columnNumber == 1 || horSpaceLeft < 0) && vertSpaceLeft > 0) )
  1079. {
  1080. // Continue adding rows to the current column
  1081. continue;
  1082. }
  1083. else
  1084. {
  1085. // Reduce number of rows in the current column
  1086. if(numberOfRowsPerColumn[columnNumber - 1] > 1)
  1087. {
  1088. --numberOfRowsPerColumn[columnNumber - 1];
  1089. }
  1090. // Get half of average column width
  1091. int averageColumnWidth = 0;
  1092. if(horSpaceLeft > 0)
  1093. {
  1094. averageColumnWidth = (int)Math.Round((double)(legendSize.Width - horSpaceLeft) / columnNumber) / 2;
  1095. }
  1096. // Check if number of columns can be increased
  1097. if(columnNumber < 50 && horSpaceLeft >= averageColumnWidth)
  1098. {
  1099. // Add new column
  1100. ++columnNumber;
  1101. // Resize array that stores number of rows per column
  1102. int[] tempArray = numberOfRowsPerColumn;
  1103. numberOfRowsPerColumn = new int[columnNumber];
  1104. for(int index = 0; index < tempArray.Length; index++)
  1105. {
  1106. numberOfRowsPerColumn[index] = tempArray[index];
  1107. }
  1108. numberOfRowsPerColumn[columnNumber - 1] = 1;
  1109. // If last legend item is moved into a new column
  1110. // call the auto fitting method before leaving the loop
  1111. if(legendItemIndex == numberOfItemsToCheck - 1)
  1112. {
  1113. this.CheckLegendItemsFit(
  1114. chartGraph,
  1115. legendSize,
  1116. legendItemIndex + 1,
  1117. this._autoFitFontSizeAdjustment,
  1118. columnNumber,
  1119. numberOfRowsPerColumn,
  1120. out this._subColumnSizes,
  1121. out this._cellHeights,
  1122. out horSpaceLeft,
  1123. out vertSpaceLeft);
  1124. }
  1125. }
  1126. else
  1127. {
  1128. exitLoop = true;
  1129. }
  1130. }
  1131. }
  1132. // Check if we end up with legend with multiple columns
  1133. // where last column has sinificantly lower height of all rows
  1134. if(columnNumber > 1)
  1135. {
  1136. // Try reducing number of rows in the "tall" calumns and move them
  1137. // into the last column.
  1138. bool done = false;
  1139. while(!done)
  1140. {
  1141. // By default no more iterations required
  1142. done = true;
  1143. // Find maximum column height not taking the last row in consideration
  1144. int maxColumnHeight = -1;
  1145. for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
  1146. {
  1147. // Calculate current column height not taking the last row in consideration
  1148. int columnHeight = 0;
  1149. for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex] - 1; rowIndex++)
  1150. {
  1151. columnHeight += this._cellHeights[columnIndex, rowIndex];
  1152. }
  1153. // Find maximum height
  1154. maxColumnHeight = Math.Max(maxColumnHeight, columnHeight);
  1155. }
  1156. // Calculate total height of items in the last row
  1157. int totalHieghtOfItemInLastRow = 0;
  1158. for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
  1159. {
  1160. if(this._numberOfRowsPerColumn[columnIndex] > 1)
  1161. {
  1162. totalHieghtOfItemInLastRow += this._cellHeights[columnIndex, this._numberOfRowsPerColumn[columnIndex] - 1];
  1163. }
  1164. }
  1165. // Check if rows are available for removal
  1166. if(totalHieghtOfItemInLastRow > 0)
  1167. {
  1168. // Get last column height
  1169. int lastColumnHeight = this.GetColumnHeight(columnNumber - 1);
  1170. // Check if all items in the last row can vertically fit in last column
  1171. if( (lastColumnHeight + totalHieghtOfItemInLastRow) <= maxColumnHeight )
  1172. {
  1173. // Reduce number of rows in all columns except last
  1174. int itemsToAdd = 0;
  1175. for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
  1176. {
  1177. if(this._numberOfRowsPerColumn[columnIndex] > 1)
  1178. {
  1179. --this._numberOfRowsPerColumn[columnIndex];
  1180. ++itemsToAdd;
  1181. }
  1182. }
  1183. // Add rows to last column
  1184. if(itemsToAdd > 0)
  1185. {
  1186. // Add roes into the last column
  1187. this._numberOfRowsPerColumn[columnNumber - 1] += itemsToAdd;
  1188. // Check if legend items fit into the legend area
  1189. bool autoFitDone = this.CheckLegendItemsFit(
  1190. chartGraph,
  1191. legendSize,
  1192. legendItemIndex + 1,
  1193. this._autoFitFontSizeAdjustment,
  1194. columnNumber,
  1195. numberOfRowsPerColumn,
  1196. out this._subColumnSizes,
  1197. out this._cellHeights,
  1198. out horSpaceLeft,
  1199. out vertSpaceLeft);
  1200. // Try doing one more time
  1201. done = false;
  1202. }
  1203. }
  1204. }
  1205. }
  1206. }
  1207. }
  1208. //*********************************************************************************
  1209. //** Wide table layout
  1210. //*********************************************************************************
  1211. else if(tableStyle == LegendTableStyle.Wide)
  1212. {
  1213. // Iterate from second item trying to add them and check if they fit
  1214. bool exitLoop = false;
  1215. int legendItemIndex = 1;
  1216. for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
  1217. {
  1218. // Try to increase number of columns
  1219. ++columnNumber;
  1220. // Resize array that stores number of rows per column
  1221. int[] tempArray = numberOfRowsPerColumn;
  1222. numberOfRowsPerColumn = new int[columnNumber];
  1223. for(int index = 0; index < tempArray.Length; index++)
  1224. {
  1225. numberOfRowsPerColumn[index] = tempArray[index];
  1226. }
  1227. numberOfRowsPerColumn[columnNumber - 1] = 1;
  1228. // Check if legend items fit into the legend area
  1229. bool autoFitDone = this.CheckLegendItemsFit(
  1230. chartGraph,
  1231. legendSize,
  1232. legendItemIndex + 1,
  1233. this._autoFitFontSizeAdjustment,
  1234. columnNumber,
  1235. numberOfRowsPerColumn,
  1236. out this._subColumnSizes,
  1237. out this._cellHeights,
  1238. out horSpaceLeft,
  1239. out vertSpaceLeft);
  1240. // Check if we fit or if we have just one row that do not fit
  1241. // vertically but still have horizontal space.
  1242. if(autoFitDone ||
  1243. ( (this.GetMaximumNumberOfRows(numberOfRowsPerColumn) == 1 || vertSpaceLeft < 0) && horSpaceLeft > 0) )
  1244. {
  1245. // Continue adding columns
  1246. continue;
  1247. }
  1248. else
  1249. {
  1250. // Remove columns and increase number of rows
  1251. bool columnFitting = true;
  1252. while(columnFitting)
  1253. {
  1254. columnFitting = false;
  1255. // If we can't fit current number of columns reduce current column number
  1256. int rowsToAdd = 0;
  1257. if(columnNumber > 1)
  1258. {
  1259. rowsToAdd = numberOfRowsPerColumn[columnNumber - 1];
  1260. --columnNumber;
  1261. // Resize array that stores number of rows per column
  1262. tempArray = numberOfRowsPerColumn;
  1263. numberOfRowsPerColumn = new int[columnNumber];
  1264. for(int index = 0; index < columnNumber; index++)
  1265. {
  1266. numberOfRowsPerColumn[index] = tempArray[index];
  1267. }
  1268. }
  1269. // We may need to add more than 1 row
  1270. for(int indexRowToAdd = 0; indexRowToAdd < rowsToAdd; indexRowToAdd++)
  1271. {
  1272. // Find first column with smallest height
  1273. int smallestColumnIndex = -1;
  1274. int columnMinHeight = int.MaxValue;
  1275. for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
  1276. {
  1277. int columnHeight = this.GetColumnHeight(columnIndex);
  1278. int nextColumnFirstItemHeight = 0;
  1279. if(columnIndex < columnNumber - 1)
  1280. {
  1281. nextColumnFirstItemHeight = this._cellHeights[columnIndex + 1, 0];
  1282. }
  1283. if(columnHeight < columnMinHeight &&
  1284. (columnHeight + nextColumnFirstItemHeight) < legendSize.Height)
  1285. {
  1286. // Remember column index and height
  1287. columnMinHeight = columnHeight;
  1288. smallestColumnIndex = columnIndex;
  1289. }
  1290. }
  1291. // No more items can fit
  1292. if(smallestColumnIndex < 0)
  1293. {
  1294. // Check if legend items fit into the legend area
  1295. autoFitDone = this.CheckLegendItemsFit(
  1296. chartGraph,
  1297. legendSize,
  1298. legendItemIndex + 1,
  1299. this._autoFitFontSizeAdjustment,
  1300. columnNumber,
  1301. numberOfRowsPerColumn,
  1302. out this._subColumnSizes,
  1303. out this._cellHeights,
  1304. out horSpaceLeft,
  1305. out vertSpaceLeft);
  1306. exitLoop = true;
  1307. break;
  1308. }
  1309. // Add new row to the smallest column
  1310. ++numberOfRowsPerColumn[smallestColumnIndex];
  1311. // Check if next column will be removed if it contains only 1 row
  1312. if(smallestColumnIndex < (columnNumber - 1))
  1313. {
  1314. if(numberOfRowsPerColumn[smallestColumnIndex + 1] == 1)
  1315. {
  1316. // Shift number of rows per column
  1317. tempArray = numberOfRowsPerColumn;
  1318. for(int index = smallestColumnIndex + 1; index < tempArray.Length - 1; index++)
  1319. {
  1320. numberOfRowsPerColumn[index] = tempArray[index + 1];
  1321. }
  1322. numberOfRowsPerColumn[columnNumber - 1] = 1;
  1323. }
  1324. }
  1325. // Check if legend items fit into the legend area
  1326. autoFitDone = this.CheckLegendItemsFit(
  1327. chartGraph,
  1328. legendSize,
  1329. legendItemIndex + 1,
  1330. this._autoFitFontSizeAdjustment,
  1331. columnNumber,
  1332. numberOfRowsPerColumn,
  1333. out this._subColumnSizes,
  1334. out this._cellHeights,
  1335. out horSpaceLeft,
  1336. out vertSpaceLeft);
  1337. }
  1338. // If there is more than 1 column and items do not fit
  1339. // horizontally - reduce number of columns.
  1340. if(!autoFitDone &&
  1341. horSpaceLeft < 0f &&
  1342. columnNumber > 1)
  1343. {
  1344. columnFitting = true;
  1345. }
  1346. }
  1347. }
  1348. }
  1349. }
  1350. }
  1351. // Check if items fit and how much empty space left
  1352. this.CheckLegendItemsFit(
  1353. chartGraph,
  1354. legendSize,
  1355. -1,
  1356. this._autoFitFontSizeAdjustment,
  1357. columnNumber,
  1358. numberOfRowsPerColumn,
  1359. out this._subColumnSizes,
  1360. out this._cellHeights,
  1361. out horSpaceLeft,
  1362. out vertSpaceLeft);
  1363. }
  1364. /// <summary>
  1365. /// Gets column height.
  1366. /// </summary>
  1367. /// <param name="columnIndex">Index of the column to get the height for.</param>
  1368. /// <returns>Column height in relative coordinates.</returns>
  1369. private int GetColumnHeight(int columnIndex)
  1370. {
  1371. // Calculate current column height
  1372. int columnHeight = 0;
  1373. for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex]; rowIndex++)
  1374. {
  1375. columnHeight += this._cellHeights[columnIndex, rowIndex];
  1376. }
  1377. return columnHeight;
  1378. }
  1379. /// <summary>
  1380. /// Checks if legend background is selected.
  1381. /// </summary>
  1382. internal void SelectLegendBackground()
  1383. {
  1384. Common.HotRegionsList.AddHotRegion(this.Position.ToRectangleF(), this, ChartElementType.LegendArea, true);
  1385. }
  1386. #endregion Legend position & size methods
  1387. #region Legend Items Fitting Methods
  1388. /// <summary>
  1389. /// Gets maximum number of rows in all columns.
  1390. /// </summary>
  1391. /// <returns>Maximum number of rows.</returns>
  1392. private int GetMaximumNumberOfRows()
  1393. {
  1394. return this.GetMaximumNumberOfRows(this._numberOfRowsPerColumn);
  1395. }
  1396. /// <summary>
  1397. /// Gets maximum number of rows in all columns.
  1398. /// </summary>
  1399. /// <param name="rowsPerColumn">Array that stores number of rows per column.</param>
  1400. /// <returns>Maximum number of rows.</returns>
  1401. private int GetMaximumNumberOfRows(int[] rowsPerColumn)
  1402. {
  1403. // Find column with maximum number of rows
  1404. int maxNumberOfColumns = 0;
  1405. if(rowsPerColumn != null)
  1406. {
  1407. for(int columnIndex = 0; columnIndex < rowsPerColumn.Length; columnIndex++)
  1408. {
  1409. maxNumberOfColumns = Math.Max(maxNumberOfColumns, rowsPerColumn[columnIndex]);
  1410. }
  1411. }
  1412. return maxNumberOfColumns;
  1413. }
  1414. /// <summary>
  1415. /// Checks if specified legend will fit the specified size.
  1416. /// </summary>
  1417. /// <param name="graph">Chart graphics.</param>
  1418. /// <param name="legendItemsAreaSize">Area that legend items must fit.</param>
  1419. /// <param name="numberOfItemsToCheck">Number of items that should be fitted.</param>
  1420. /// <param name="fontSizeReducedBy">Number of points the standard legend font is reduced by auto-fitting algorithm.</param>
  1421. /// <param name="numberOfColumns">Legend column number.</param>
  1422. /// <param name="numberOfRowsPerColumn">Array of number of rows per column.</param>
  1423. /// <param name="subColumnSizes">Returns array of sub-column size.</param>
  1424. /// <param name="cellHeights">Returns array of cell heights.</param>
  1425. /// <param name="horizontalSpaceLeft">Returns horizontal space left.</param>
  1426. /// <param name="verticalSpaceLeft">Returns vertical space left.</param>
  1427. /// <returns>True if items fit.</returns>
  1428. private bool CheckLegendItemsFit(
  1429. ChartGraphics graph,
  1430. Size legendItemsAreaSize,
  1431. int numberOfItemsToCheck,
  1432. int fontSizeReducedBy,
  1433. int numberOfColumns,
  1434. int[] numberOfRowsPerColumn,
  1435. out int[,] subColumnSizes,
  1436. out int[,] cellHeights,
  1437. out int horizontalSpaceLeft,
  1438. out int verticalSpaceLeft)
  1439. {
  1440. bool fitFlag = true;
  1441. // Initialize output values
  1442. horizontalSpaceLeft = 0;
  1443. verticalSpaceLeft = 0;
  1444. // Use current legend item count if number of items to check is not specified
  1445. if(numberOfItemsToCheck < 0)
  1446. {
  1447. numberOfItemsToCheck = this.legendItems.Count;
  1448. }
  1449. // Calculate how many sub-columns (cells) this legend has
  1450. int numberOfSubColumns = this.GetNumberOfCells();
  1451. // Each column may have its own number of rows. Calculate the maximum number of rows.
  1452. int maxNumberOfRows = this.GetMaximumNumberOfRows(numberOfRowsPerColumn);
  1453. // Create multidimensional arrays that will be holding the widths and heightsof all
  1454. // individual cells. First dimension will be the legend column index, second dimension
  1455. // is row index and the third is sub-column (cell) index.
  1456. int[,,] cellWidths = new int[numberOfColumns, maxNumberOfRows, numberOfSubColumns];
  1457. cellHeights = new int[numberOfColumns, maxNumberOfRows];
  1458. //*************************************************************************
  1459. //** Measure legend font single character
  1460. //*************************************************************************
  1461. this.singleWCharacterSize = graph.MeasureStringAbs("W", (this.autofitFont == null) ? this.Font : this.autofitFont);
  1462. Size doubleCharacterSize = graph.MeasureStringAbs("WW", (this.autofitFont == null) ? this.Font : this.autofitFont);
  1463. this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
  1464. //*************************************************************************
  1465. //** Iterate through all legend items and measure each individual cell
  1466. //*************************************************************************
  1467. int currentColumn = 0;
  1468. int currentRow = 0;
  1469. for(int legendItemIndex = 0; legendItemIndex < numberOfItemsToCheck; legendItemIndex++)
  1470. {
  1471. LegendItem legendItem = this.legendItems[legendItemIndex];
  1472. // Iterate through legend item cells
  1473. int numberOfCellsToSkip = 0;
  1474. for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
  1475. {
  1476. // Get legend cell
  1477. LegendCell legendCell = legendItem.Cells[cellIndex];
  1478. // Get assocated legend column object (may be NULL)
  1479. LegendCellColumn legendColumn = null;
  1480. if(cellIndex < this.CellColumns.Count)
  1481. {
  1482. legendColumn = this.CellColumns[cellIndex];
  1483. }
  1484. // Check if current cell should be skipped becuse it's overlapped
  1485. // by the previous sell that uses CellSpan.
  1486. if(numberOfCellsToSkip > 0)
  1487. {
  1488. // Put size (-1) for the cells that follow a cell using ColumnSpan
  1489. cellWidths[currentColumn, currentRow, cellIndex] = -1;
  1490. --numberOfCellsToSkip;
  1491. continue;
  1492. }
  1493. // Check if current cell uses CellSpan
  1494. if(legendCell.CellSpan > 1)
  1495. {
  1496. numberOfCellsToSkip = legendCell.CellSpan - 1;
  1497. }
  1498. // Measure cell and store the value in the array
  1499. Size cellSize = legendCell.MeasureCell(
  1500. graph,
  1501. fontSizeReducedBy,
  1502. (this.autofitFont == null) ? this.Font : this.autofitFont,
  1503. this.singleWCharacterSize);
  1504. // Check for column maximum/minimum cell width restrictions
  1505. if(legendColumn != null)
  1506. {
  1507. if(legendColumn.MinimumWidth >= 0)
  1508. {
  1509. cellSize.Width = (int)Math.Max(cellSize.Width, legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
  1510. }
  1511. if(legendColumn.MaximumWidth >= 0)
  1512. {
  1513. cellSize.Width = (int)Math.Min(cellSize.Width, legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
  1514. }
  1515. }
  1516. // Store cell size in arrays
  1517. cellWidths[currentColumn, currentRow, cellIndex] = cellSize.Width;
  1518. if(cellIndex == 0)
  1519. {
  1520. cellHeights[currentColumn, currentRow] = cellSize.Height;
  1521. }
  1522. else
  1523. {
  1524. cellHeights[currentColumn, currentRow] =
  1525. Math.Max(cellHeights[currentColumn, currentRow], cellSize.Height);
  1526. }
  1527. }
  1528. // Advance to the next row/column. Break if number of legend items exceed
  1529. // number of availabale rows/columns.
  1530. ++currentRow;
  1531. if(currentRow >= numberOfRowsPerColumn[currentColumn])
  1532. {
  1533. ++currentColumn;
  1534. currentRow = 0;
  1535. if(currentColumn >= numberOfColumns)
  1536. {
  1537. // Check if we were able to fit all the items
  1538. if(legendItemIndex < numberOfItemsToCheck - 1)
  1539. {
  1540. fitFlag = false;
  1541. }
  1542. break;
  1543. }
  1544. }
  1545. }
  1546. //*************************************************************************
  1547. //** For each sub-column get the maximum cell width
  1548. //*************************************************************************
  1549. subColumnSizes = new int[numberOfColumns, numberOfSubColumns];
  1550. bool secondIterationRequired = false;
  1551. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1552. {
  1553. for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
  1554. {
  1555. int width = 0;
  1556. for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
  1557. {
  1558. // Get current cell size
  1559. int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
  1560. // Skip overlapped cells and cells that use ColumnSpan during the
  1561. // first iteration. Their size will be determined during the
  1562. // second iteration.
  1563. if(cellWidth < 0)
  1564. {
  1565. secondIterationRequired = true;
  1566. continue;
  1567. }
  1568. if(currentSubColumn + 1 < numberOfSubColumns)
  1569. {
  1570. int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + 1];
  1571. if(nextCellWidth < 0)
  1572. {
  1573. continue;
  1574. }
  1575. }
  1576. // Get maximum width
  1577. width = Math.Max(width, cellWidth );
  1578. }
  1579. // Store maximum width in the array
  1580. subColumnSizes[currentColumn, currentSubColumn] = width;
  1581. }
  1582. }
  1583. //*************************************************************************
  1584. //** If leagend header text is used check if it fits into the currenly
  1585. //** calculated sub-column sizes.
  1586. //*************************************************************************
  1587. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1588. {
  1589. for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
  1590. {
  1591. if(currentSubColumn < this.CellColumns.Count)
  1592. {
  1593. LegendCellColumn legendColumn = this.CellColumns[currentSubColumn];
  1594. if(legendColumn.HeaderText.Length > 0)
  1595. {
  1596. // Note that extra "I" character added to add more horizontal spacing
  1597. Size headerTextSize = graph.MeasureStringAbs(legendColumn.HeaderText + "I", legendColumn.HeaderFont);
  1598. if(headerTextSize.Width > subColumnSizes[currentColumn, currentSubColumn])
  1599. {
  1600. // Set new width
  1601. subColumnSizes[currentColumn, currentSubColumn] = headerTextSize.Width;
  1602. // Check for column maximum/minimum cell width restrictions
  1603. if(legendColumn.MinimumWidth >= 0)
  1604. {
  1605. subColumnSizes[currentColumn, currentSubColumn] =
  1606. (int)Math.Max(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
  1607. }
  1608. if(legendColumn.MaximumWidth >= 0)
  1609. {
  1610. subColumnSizes[currentColumn, currentSubColumn] =
  1611. (int)Math.Min(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
  1612. }
  1613. }
  1614. }
  1615. }
  1616. }
  1617. }
  1618. //*************************************************************************
  1619. //** Adjust width of the cells to fit cell content displayed across
  1620. //** several cells (CellSpanning).
  1621. //*************************************************************************
  1622. if(secondIterationRequired)
  1623. {
  1624. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1625. {
  1626. for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
  1627. {
  1628. for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
  1629. {
  1630. // Get current cell size
  1631. int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
  1632. // Second iteration used to adjust width of the cells that are used to
  1633. // draw content across several horizontal cells (CellSpanning)
  1634. // Check if current cell will be spanned to the next ones
  1635. int cellSpan = 0;
  1636. while(currentSubColumn + cellSpan + 1 < numberOfSubColumns)
  1637. {
  1638. int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + cellSpan + 1];
  1639. if(nextCellWidth >= 0)
  1640. {
  1641. break;
  1642. }
  1643. ++cellSpan;
  1644. }
  1645. // Cell span was detected
  1646. if(cellSpan > 0)
  1647. {
  1648. // Calculate total width of current cell and all overlapped cells
  1649. int spanWidth = 0;
  1650. for(int index = 0; index <= cellSpan; index++)
  1651. {
  1652. spanWidth += subColumnSizes[currentColumn, currentSubColumn + index];
  1653. }
  1654. // Check if current cell fits into the cell span
  1655. if(cellWidth > spanWidth)
  1656. {
  1657. // Adjust last span cell width to fit all curent cell content
  1658. subColumnSizes[currentColumn, currentSubColumn + cellSpan] += cellWidth - spanWidth;
  1659. }
  1660. }
  1661. }
  1662. }
  1663. }
  1664. }
  1665. //*************************************************************************
  1666. //** Check if equally spaced legend columns are used
  1667. //*************************************************************************
  1668. if(this.IsEquallySpacedItems)
  1669. {
  1670. // Makre sure that same sub-colimn width are used in all columns
  1671. for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
  1672. {
  1673. int width = 0;
  1674. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1675. {
  1676. width = Math.Max(width, subColumnSizes[currentColumn, currentSubColumn]);
  1677. }
  1678. // Set new sub-column width for each column
  1679. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1680. {
  1681. subColumnSizes[currentColumn, currentSubColumn] = width;
  1682. }
  1683. }
  1684. }
  1685. //*************************************************************************
  1686. //** Calculate total width and height occupied by all cells
  1687. //*************************************************************************
  1688. int totalWidth = 0;
  1689. int totalTableColumnSpacingWidth = 0;
  1690. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1691. {
  1692. // Add up all sub-columns
  1693. for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
  1694. {
  1695. totalWidth += subColumnSizes[currentColumn, currentSubColumn];
  1696. }
  1697. // Add spacer between columns
  1698. if(currentColumn < numberOfColumns - 1)
  1699. {
  1700. totalTableColumnSpacingWidth += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
  1701. }
  1702. }
  1703. int totalHeight = 0;
  1704. for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
  1705. {
  1706. int columnHeight = 0;
  1707. for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
  1708. {
  1709. columnHeight += cellHeights[currentColumn, currentRow];
  1710. }
  1711. totalHeight = Math.Max(totalHeight, columnHeight);
  1712. }
  1713. //*************************************************************************
  1714. //** Check if everything fits
  1715. //*************************************************************************
  1716. horizontalSpaceLeft = legendItemsAreaSize.Width - totalWidth - totalTableColumnSpacingWidth;
  1717. if(horizontalSpaceLeft < 0)
  1718. {
  1719. fitFlag = false;
  1720. }
  1721. verticalSpaceLeft = legendItemsAreaSize.Height - totalHeight;
  1722. if(verticalSpaceLeft < 0)
  1723. {
  1724. fitFlag = false;
  1725. }
  1726. return fitFlag;
  1727. }
  1728. /// <summary>
  1729. /// Gets maximum number of legend cells defined as Column objects
  1730. /// or Cells in the custom legend items.
  1731. /// </summary>
  1732. /// <returns>Maximum number of cells.</returns>
  1733. private int GetNumberOfCells()
  1734. {
  1735. // Calculate cell number if it was not previously cached
  1736. if(this._numberOfCells < 0)
  1737. {
  1738. // Initialize with number of defined columns
  1739. this._numberOfCells = this.CellColumns.Count;
  1740. // Check if number of cells in legend items exceed number of defined columns
  1741. foreach(LegendItem legendItem in this.legendItems)
  1742. {
  1743. this._numberOfCells = Math.Max(this._numberOfCells, legendItem.Cells.Count);
  1744. }
  1745. }
  1746. return this._numberOfCells;
  1747. }
  1748. #endregion // Legend Items Fitting Methods
  1749. #region Legend items collection filling methods
  1750. /// <summary>
  1751. /// Add all series legend into items collection and then
  1752. /// add custom legend items.
  1753. /// </summary>
  1754. private void FillLegendItemsCollection()
  1755. {
  1756. // Clear all items
  1757. legendItems.Clear();
  1758. // Check that there is no invalid legend names in the series
  1759. foreach(Series series in this.Common.DataManager.Series)
  1760. {
  1761. if (this.Common.ChartPicture.Legends.IndexOf(series.Legend)<0)
  1762. {
  1763. throw (new InvalidOperationException(SR.ExceptionLegendReferencedInSeriesNotFound(series.Name, series.Legend)));
  1764. }
  1765. }
  1766. // Flag which indicates that series requires legend items to be reversed
  1767. bool seriesWithReversedLegendItemsPresent = false;
  1768. // Add legend items based on the exsisting chart series
  1769. foreach(Series series in this.Common.DataManager.Series)
  1770. {
  1771. // Check if series uses this legend
  1772. // VSTS issue #140694 fix: support of series.Legend = "Default";
  1773. if (this.Common.ChartPicture.Legends[series.Legend] != this)
  1774. {
  1775. continue;
  1776. }
  1777. // Make sure series is assigned to the chart area
  1778. if(series.ChartArea.Length > 0)
  1779. {
  1780. // Check if chart area name is valid
  1781. bool areaNameFound = false;
  1782. foreach(ChartArea area in this.Common.ChartPicture.ChartAreas)
  1783. {
  1784. if(area.Name == series.ChartArea)
  1785. {
  1786. areaNameFound = true;
  1787. break;
  1788. }
  1789. }
  1790. // Check if series is visible and valid chart area name was used
  1791. if(series.IsVisible() && areaNameFound)
  1792. {
  1793. // Check if we should add all data points into the legend
  1794. IChartType chartType = this.Common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
  1795. // Check if series legend items should be reversed
  1796. if (this.LegendItemOrder == LegendItemOrder.Auto)
  1797. {
  1798. if(series.ChartType == SeriesChartType.StackedArea ||
  1799. series.ChartType == SeriesChartType.StackedArea100 ||
  1800. series.ChartType == SeriesChartType.Pyramid ||
  1801. series.ChartType == SeriesChartType.StackedColumn ||
  1802. series.ChartType == SeriesChartType.StackedColumn100 )
  1803. {
  1804. seriesWithReversedLegendItemsPresent = true;
  1805. }
  1806. }
  1807. // Add item(s) based on series points label and fore color
  1808. if(chartType.DataPointsInLegend)
  1809. {
  1810. // Check if data points have X values set
  1811. bool xValuesSet = false;
  1812. foreach(DataPoint point in series.Points)
  1813. {
  1814. if(point.XValue != 0.0)
  1815. {
  1816. xValuesSet = true;
  1817. break;
  1818. }
  1819. }
  1820. // Add legend items for each point
  1821. int index = 0;
  1822. foreach(DataPoint point in series.Points)
  1823. {
  1824. // Do not show empty data points in the legend
  1825. if(point.IsEmpty)
  1826. {
  1827. ++index;
  1828. continue;
  1829. }
  1830. // Point should not be shown in the legend
  1831. if(!point.IsVisibleInLegend)
  1832. {
  1833. ++index;
  1834. continue;
  1835. }
  1836. // Create new legend item
  1837. LegendItem item = new LegendItem(point.Label, point.Color, "");
  1838. // Check if series is drawn in 3D chart area
  1839. bool area3D = this.Common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
  1840. // Set legend item appearance properties
  1841. item.SetAttributes(this.Common, series);
  1842. item.SetAttributes(point, area3D);
  1843. // Set chart image map properties
  1844. item.ToolTip = point.ReplaceKeywords(point.LegendToolTip);
  1845. item.Name = point.ReplaceKeywords(point.LegendText);
  1846. item.SeriesPointIndex = index++;
  1847. if(item.Name.Length == 0)
  1848. {
  1849. item.Name = point.ReplaceKeywords((point.Label.Length > 0) ? point.Label : point.AxisLabel);
  1850. }
  1851. // If legend item name is not defined - try using the X value
  1852. if(item.Name.Length == 0 && xValuesSet)
  1853. {
  1854. item.Name = ValueConverter.FormatValue(
  1855. series.Chart,
  1856. this,
  1857. this.Tag,
  1858. point.XValue,
  1859. "", // Do not use point label format! For Y values only! point.LabelFormat,
  1860. point.series.XValueType,
  1861. ChartElementType.LegendItem);
  1862. }
  1863. // If legend item name is not defined - use index
  1864. if(item.Name.Length == 0)
  1865. {
  1866. item.Name = "Point " + index;
  1867. }
  1868. // Add legend item cells based on predefined columns
  1869. item.AddAutomaticCells(this);
  1870. foreach(LegendCell cell in item.Cells)
  1871. {
  1872. if(cell.Text.Length > 0)
  1873. {
  1874. // #LEGENDTEXT - series name
  1875. cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
  1876. // Process rest of the keywords
  1877. cell.Text = point.ReplaceKeywords(cell.Text);
  1878. cell.ToolTip = point.ReplaceKeywords(cell.ToolTip);
  1879. }
  1880. }
  1881. legendItems.Add(item);
  1882. }
  1883. }
  1884. // Add item based on series name and fore color
  1885. else
  1886. {
  1887. // Point should not be shown in the legend
  1888. if(!series.IsVisibleInLegend)
  1889. {
  1890. continue;
  1891. }
  1892. // Create legend item
  1893. LegendItem item = new LegendItem(series.Name, series.Color, "");
  1894. item.SetAttributes(this.Common, series);
  1895. item.ToolTip = series.ReplaceKeywords(series.LegendToolTip);
  1896. if (series.LegendText.Length > 0)
  1897. {
  1898. item.Name = series.ReplaceKeywords(series.LegendText);
  1899. }
  1900. // Add legend item cells based on predefined columns
  1901. item.AddAutomaticCells(this);
  1902. foreach(LegendCell cell in item.Cells)
  1903. {
  1904. if(cell.Text.Length > 0)
  1905. {
  1906. // #LEGENDTEXT - series name
  1907. cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
  1908. // Process rest of the keywords
  1909. cell.Text = series.ReplaceKeywords(cell.Text);
  1910. cell.ToolTip = series.ReplaceKeywords(cell.ToolTip);
  1911. }
  1912. }
  1913. legendItems.Add(item);
  1914. }
  1915. }
  1916. }
  1917. }
  1918. // Check if series legend items should be reversed
  1919. if (this.LegendItemOrder == LegendItemOrder.SameAsSeriesOrder ||
  1920. (this.LegendItemOrder == LegendItemOrder.Auto && seriesWithReversedLegendItemsPresent))
  1921. {
  1922. // Reversed series generated legend items
  1923. legendItems.Reverse();
  1924. }
  1925. // Add custom items
  1926. foreach(LegendItem item in this._customLegends)
  1927. {
  1928. if(item.Enabled)
  1929. {
  1930. legendItems.Add(item);
  1931. }
  1932. }
  1933. // Legend can't be empty at design time
  1934. if(legendItems.Count == 0 && this.Common != null && this.Common.Chart != null)
  1935. {
  1936. if(this.Common.Chart.IsDesignMode())
  1937. {
  1938. LegendItem item = new LegendItem(this.Name + " - " + SR.DescriptionTypeEmpty, Color.White, "");
  1939. item.ImageStyle = LegendImageStyle.Line;
  1940. legendItems.Add(item);
  1941. }
  1942. }
  1943. // Add legend item cells based on predefined columns
  1944. foreach(LegendItem item in this.legendItems)
  1945. {
  1946. item.AddAutomaticCells(this);
  1947. }
  1948. }
  1949. #endregion
  1950. #region Legend painting methods
  1951. /// <summary>
  1952. /// Paints legend using chart graphics object.
  1953. /// </summary>
  1954. /// <param name="chartGraph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
  1955. internal void Paint(ChartGraphics chartGraph )
  1956. {
  1957. // Reset some values
  1958. this._offset = Size.Empty;
  1959. this._itemColumns = 0;
  1960. this._horizontalSpaceLeft = 0;
  1961. this._verticalSpaceLeft = 0;
  1962. this._subColumnSizes = null;
  1963. this._numberOfRowsPerColumn = null;
  1964. this._cellHeights = null;
  1965. this.autofitFont = null;
  1966. this._autoFitFontSizeAdjustment = 0;
  1967. this._numberOfCells = -1;
  1968. this._numberOfLegendItemsToProcess = -1;
  1969. // Do nothing if legend disabled
  1970. if(!this.IsEnabled() ||
  1971. (this.MaximumAutoSize == 0f && this.Position.Auto))
  1972. {
  1973. return;
  1974. }
  1975. // Add all series legend into items collection and then add custom legend items
  1976. FillLegendItemsCollection();
  1977. // Clear all legend item cells information
  1978. foreach(LegendItem legendItem in this.legendItems)
  1979. {
  1980. foreach(LegendCell cell in legendItem.Cells)
  1981. {
  1982. cell.ResetCache();
  1983. }
  1984. }
  1985. // Call a notification event, so that legend items collection can be modified by user
  1986. this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
  1987. // Check if legend is empty
  1988. if(this.legendItems.Count == 0)
  1989. {
  1990. return;
  1991. }
  1992. //***********************************************************
  1993. //** RecalculateAxesScale legend information
  1994. //***********************************************************
  1995. this.RecalcLegendInfo(chartGraph);
  1996. //***********************************************************
  1997. //** Paint legend
  1998. //***********************************************************
  1999. // Call BackPaint event
  2000. if( Common.ProcessModePaint )
  2001. {
  2002. // Draw legend background, border and shadow
  2003. chartGraph.FillRectangleRel(
  2004. chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
  2005. BackColor,
  2006. BackHatchStyle,
  2007. BackImage,
  2008. BackImageWrapMode,
  2009. BackImageTransparentColor,
  2010. BackImageAlignment,
  2011. BackGradientStyle,
  2012. BackSecondaryColor,
  2013. BorderColor,
  2014. this.GetBorderSize(),
  2015. BorderDashStyle,
  2016. ShadowColor,
  2017. ShadowOffset,
  2018. PenAlignment.Inset);
  2019. Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
  2020. }
  2021. if( Common.ProcessModeRegions )
  2022. {
  2023. SelectLegendBackground();
  2024. }
  2025. //***********************************************************
  2026. //** Draw legend header
  2027. //***********************************************************
  2028. this.DrawLegendHeader(chartGraph);
  2029. //***********************************************************
  2030. //** Draw legend title
  2031. //***********************************************************
  2032. this.DrawLegendTitle(chartGraph);
  2033. // Add legend title hot region
  2034. if( Common.ProcessModeRegions && !this._titlePosition.IsEmpty)
  2035. {
  2036. Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._titlePosition), this, ChartElementType.LegendTitle, true );
  2037. }
  2038. //***********************************************************
  2039. //** Draw legend items
  2040. //***********************************************************
  2041. if(this._numberOfLegendItemsToProcess < 0)
  2042. {
  2043. this._numberOfLegendItemsToProcess = this.legendItems.Count;
  2044. }
  2045. for(int itemIndex = 0; itemIndex < this._numberOfLegendItemsToProcess; itemIndex++)
  2046. {
  2047. LegendItem legendItem = this.legendItems[itemIndex];
  2048. // Iterate through legend item cells
  2049. for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
  2050. {
  2051. // Get legend cell
  2052. LegendCell legendCell = legendItem.Cells[cellIndex];
  2053. // Paint cell
  2054. legendCell.Paint(
  2055. chartGraph,
  2056. this._autoFitFontSizeAdjustment,
  2057. this.autofitFont,
  2058. this.singleWCharacterSize);
  2059. }
  2060. // Paint legend item separator
  2061. if(legendItem.SeparatorType != LegendSeparatorStyle.None &&
  2062. legendItem.Cells.Count > 0)
  2063. {
  2064. // Calculate separator position
  2065. Rectangle separatorPosition = Rectangle.Empty;
  2066. separatorPosition.X = legendItem.Cells[0].cellPosition.Left;
  2067. // Find right most cell position excluding ovelapped cells that have negative size
  2068. int right = 0;
  2069. for(int index = legendItem.Cells.Count - 1; index >= 0; index--)
  2070. {
  2071. right = legendItem.Cells[index].cellPosition.Right;
  2072. if(right > 0)
  2073. {
  2074. break;
  2075. }
  2076. }
  2077. separatorPosition.Width = right - separatorPosition.X;
  2078. separatorPosition.Y = legendItem.Cells[0].cellPosition.Bottom;
  2079. separatorPosition.Height = this.GetSeparatorSize(legendItem.SeparatorType).Height;
  2080. separatorPosition.Intersect(this._legendItemsAreaPosition);
  2081. // Draw separator
  2082. this.DrawSeparator(
  2083. chartGraph,
  2084. legendItem.SeparatorType,
  2085. legendItem.SeparatorColor,
  2086. true,
  2087. separatorPosition);
  2088. }
  2089. }
  2090. //***********************************************************
  2091. //** If legend items are in multiple columns draw vertical
  2092. //** separator
  2093. //***********************************************************
  2094. if(this.ItemColumnSeparator != LegendSeparatorStyle.None)
  2095. {
  2096. Rectangle separatorRect = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
  2097. separatorRect.Y += this.GetBorderSize() + this._titlePosition.Height;
  2098. separatorRect.Height -= 2 * this.GetBorderSize() + this._titlePosition.Height;
  2099. separatorRect.X += this.GetBorderSize() + this._offset.Width;
  2100. separatorRect.Width = this.GetSeparatorSize(this.ItemColumnSeparator).Width;
  2101. if(this._horizontalSpaceLeft > 0)
  2102. {
  2103. separatorRect.X += this._horizontalSpaceLeft / 2;
  2104. }
  2105. // Check position
  2106. if(separatorRect.Width > 0 && separatorRect.Height > 0)
  2107. {
  2108. // Iterate through all columns
  2109. for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
  2110. {
  2111. // Iterate through all sub-columns
  2112. int cellCount = this.GetNumberOfCells();
  2113. for(int subColumnIndex = 0; subColumnIndex < cellCount; subColumnIndex++ )
  2114. {
  2115. separatorRect.X += this._subColumnSizes[columnIndex, subColumnIndex];
  2116. }
  2117. // Draw separator if not the last column
  2118. if(columnIndex < this._itemColumns - 1)
  2119. {
  2120. this.DrawSeparator(chartGraph, this.ItemColumnSeparator, this.ItemColumnSeparatorColor, false, separatorRect);
  2121. }
  2122. // Add separator width
  2123. separatorRect.X += separatorRect.Width;
  2124. }
  2125. }
  2126. }
  2127. //***********************************************************
  2128. //** Draw special indicator on the bottom of the legend if
  2129. //** it was truncated.
  2130. //***********************************************************
  2131. if(this._legendItemsTruncated &&
  2132. this._legendItemsAreaPosition.Height > this._truncatedDotsSize / 2)
  2133. {
  2134. // Calculate dots step (no more than 10 pixel)
  2135. int markerCount = 3;
  2136. int step = (this._legendItemsAreaPosition.Width / 3) / markerCount;
  2137. step = (int)Math.Min(step, 10);
  2138. // Calculate start point
  2139. PointF point = new PointF(
  2140. this._legendItemsAreaPosition.X + this._legendItemsAreaPosition.Width / 2 - step * (float)Math.Floor(markerCount/2f),
  2141. this._legendItemsAreaPosition.Bottom + (this._truncatedDotsSize + this._offset.Height) / 2);
  2142. // Draw several dots at the bottom of the legend
  2143. for(int index = 0; index < markerCount; index++)
  2144. {
  2145. chartGraph.DrawMarkerRel(
  2146. chartGraph.GetRelativePoint(point),
  2147. MarkerStyle.Circle,
  2148. this._truncatedDotsSize,
  2149. this.ForeColor,
  2150. Color.Empty,
  2151. 0,
  2152. string.Empty,
  2153. Color.Empty,
  2154. 0,
  2155. Color.Empty,
  2156. RectangleF.Empty);
  2157. // Shift to the right
  2158. point.X += step;
  2159. }
  2160. }
  2161. // Call Paint event
  2162. if( Common.ProcessModePaint )
  2163. {
  2164. Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
  2165. }
  2166. // Remove temporary cells from legend items
  2167. foreach(LegendItem legendItem in this.legendItems)
  2168. {
  2169. if(legendItem.clearTempCells)
  2170. {
  2171. legendItem.clearTempCells = false;
  2172. legendItem.Cells.Clear();
  2173. }
  2174. }
  2175. }
  2176. #endregion
  2177. #region Legend properties
  2178. /// <summary>
  2179. /// Gets or sets the name of the legend.
  2180. /// </summary>
  2181. [
  2182. SRCategory("CategoryAttributeMisc"),
  2183. Bindable(true),
  2184. SRDescription("DescriptionAttributeLegend_Name"),
  2185. NotifyParentPropertyAttribute(true)
  2186. ]
  2187. public override string Name
  2188. {
  2189. get
  2190. {
  2191. return base.Name;
  2192. }
  2193. set
  2194. {
  2195. base.Name = value;
  2196. CallOnModifing();
  2197. }
  2198. }
  2199. /// <summary>
  2200. /// Gets or sets the name of the chart area where the legend
  2201. /// should be docked.
  2202. /// </summary>
  2203. [
  2204. SRCategory("CategoryAttributeDocking"),
  2205. Bindable(true),
  2206. DefaultValue(Constants.NotSetValue),
  2207. SRDescription("DescriptionAttributeLegend_DockToChartArea"),
  2208. TypeConverter(typeof(LegendAreaNameConverter)),
  2209. NotifyParentPropertyAttribute(true)
  2210. ]
  2211. public string DockedToChartArea
  2212. {
  2213. get
  2214. {
  2215. return _dockedToChartArea;
  2216. }
  2217. set
  2218. {
  2219. if(value != _dockedToChartArea)
  2220. {
  2221. if (String.IsNullOrEmpty(value))
  2222. {
  2223. _dockedToChartArea = Constants.NotSetValue;
  2224. }
  2225. else
  2226. {
  2227. if (Chart != null && Chart.ChartAreas != null)
  2228. {
  2229. Chart.ChartAreas.VerifyNameReference(value);
  2230. }
  2231. _dockedToChartArea = value;
  2232. }
  2233. this.Invalidate(false);
  2234. CallOnModifing();
  2235. }
  2236. }
  2237. }
  2238. /// <summary>
  2239. /// Gets or sets a property which indicates whether
  2240. /// the legend is docked inside the chart area.
  2241. /// This property is only available when DockedToChartArea is set.
  2242. /// </summary>
  2243. [
  2244. SRCategory("CategoryAttributeDocking"),
  2245. Bindable(true),
  2246. DefaultValue(true),
  2247. SRDescription("DescriptionAttributeLegend_DockInsideChartArea"),
  2248. NotifyParentPropertyAttribute(true)
  2249. ]
  2250. public bool IsDockedInsideChartArea
  2251. {
  2252. get
  2253. {
  2254. return _isDockedInsideChartArea;
  2255. }
  2256. set
  2257. {
  2258. if(value != _isDockedInsideChartArea)
  2259. {
  2260. _isDockedInsideChartArea = value;
  2261. this.Invalidate(false);
  2262. CallOnModifing();
  2263. }
  2264. }
  2265. }
  2266. /// <summary>
  2267. /// Gets or sets the position of the legend.
  2268. /// </summary>
  2269. [
  2270. SRCategory("CategoryAttributeAppearance"),
  2271. Bindable(true),
  2272. SRDescription("DescriptionAttributeLegend_Position"),
  2273. DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  2274. NotifyParentPropertyAttribute(true),
  2275. TypeConverter(typeof(ElementPositionConverter)),
  2276. SerializationVisibilityAttribute(SerializationVisibility.Element)
  2277. ]
  2278. public ElementPosition Position
  2279. {
  2280. get
  2281. {
  2282. // Serialize only position values if Auto set to false
  2283. if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
  2284. {
  2285. if(_position.Auto)
  2286. {
  2287. return new ElementPosition();
  2288. }
  2289. else
  2290. {
  2291. ElementPosition newPosition = new ElementPosition();
  2292. newPosition.Auto = false;
  2293. newPosition.SetPositionNoAuto(_position.X, _position.Y, _position.Width, _position.Height);
  2294. return newPosition;
  2295. }
  2296. }
  2297. return _position;
  2298. }
  2299. set
  2300. {
  2301. _position = value;
  2302. this.Invalidate(false);
  2303. CallOnModifing();
  2304. }
  2305. }
  2306. /// <summary>
  2307. /// Determoines if this position should be serialized.
  2308. /// </summary>
  2309. /// <returns></returns>
  2310. internal bool ShouldSerializePosition()
  2311. {
  2312. return !this.Position.Auto;
  2313. }
  2314. /// <summary>
  2315. /// Gets or sets a property which indicates whether
  2316. /// all legend items are equally spaced.
  2317. /// </summary>
  2318. [
  2319. SRCategory("CategoryAttributeAppearance"),
  2320. Bindable(true),
  2321. DefaultValue(false),
  2322. SRDescription("DescriptionAttributeLegend_EquallySpacedItems"),
  2323. NotifyParentPropertyAttribute(true)
  2324. ]
  2325. public bool IsEquallySpacedItems
  2326. {
  2327. get
  2328. {
  2329. return _isEquallySpacedItems;
  2330. }
  2331. set
  2332. {
  2333. _isEquallySpacedItems = value;
  2334. this.Invalidate(false);
  2335. CallOnModifing();
  2336. }
  2337. }
  2338. /// <summary>
  2339. /// Gets or sets a flag which indicates whether the legend is enabled.
  2340. /// </summary>
  2341. [
  2342. SRCategory("CategoryAttributeAppearance"),
  2343. Bindable(true),
  2344. DefaultValue(true),
  2345. SRDescription("DescriptionAttributeLegend_Enabled"),
  2346. NotifyParentPropertyAttribute(true),
  2347. ParenthesizePropertyNameAttribute(true)
  2348. ]
  2349. public bool Enabled
  2350. {
  2351. get
  2352. {
  2353. return _enabled;
  2354. }
  2355. set
  2356. {
  2357. _enabled = value;
  2358. this.Invalidate(false);
  2359. CallOnModifing();
  2360. }
  2361. }
  2362. /// <summary>
  2363. /// Gets or sets a value that indicates if legend text is automatically sized.
  2364. /// </summary>
  2365. [
  2366. SRCategory("CategoryAttributeAppearance"),
  2367. Bindable(true),
  2368. DefaultValue(true),
  2369. SRDescription("DescriptionAttributeLegend_AutoFitText"),
  2370. NotifyParentPropertyAttribute(true)
  2371. ]
  2372. public bool IsTextAutoFit
  2373. {
  2374. get
  2375. {
  2376. return _isTextAutoFit;
  2377. }
  2378. set
  2379. {
  2380. _isTextAutoFit = value;
  2381. if(_isTextAutoFit)
  2382. {
  2383. // Reset the font size to "8"
  2384. // Use current font family name ans style if possible.
  2385. if(_font != null)
  2386. {
  2387. _font = _fontCache.GetFont(_font.FontFamily, 8, _font.Style); ;
  2388. }
  2389. else
  2390. {
  2391. _font = _fontCache.DefaultFont;
  2392. }
  2393. }
  2394. this.Invalidate(false);
  2395. CallOnModifing();
  2396. }
  2397. }
  2398. /// <summary>
  2399. /// Gets or sets the legend style.
  2400. /// </summary>
  2401. [
  2402. SRCategory("CategoryAttributeAppearance"),
  2403. Bindable(true),
  2404. DefaultValue(LegendStyle.Table),
  2405. SRDescription("DescriptionAttributeLegend_LegendStyle"),
  2406. NotifyParentPropertyAttribute(true),
  2407. ParenthesizePropertyNameAttribute(true)
  2408. ]
  2409. public LegendStyle LegendStyle
  2410. {
  2411. get
  2412. {
  2413. return _legendStyle;
  2414. }
  2415. set
  2416. {
  2417. _legendStyle = value;
  2418. this.Invalidate(false);
  2419. CallOnModifing();
  2420. }
  2421. }
  2422. /// <summary>
  2423. /// Gets or sets the minimum font size that can be used by the legend text's auto-fitting algorithm.
  2424. /// </summary>
  2425. [
  2426. SRCategory("CategoryAttributeAppearance"),
  2427. DefaultValue(7),
  2428. SRDescription("DescriptionAttributeLegend_AutoFitMinFontSize"),
  2429. ]
  2430. public int AutoFitMinFontSize
  2431. {
  2432. get
  2433. {
  2434. return this._autoFitMinFontSize;
  2435. }
  2436. set
  2437. {
  2438. // Font size cannot be less than 5
  2439. if(value < 5)
  2440. {
  2441. throw (new InvalidOperationException(SR.ExceptionLegendAutoFitMinFontSizeInvalid));
  2442. }
  2443. this._autoFitMinFontSize = value;
  2444. this.Invalidate(false);
  2445. CallOnModifing();
  2446. }
  2447. }
  2448. /// <summary>
  2449. /// Gets or sets the maximum size (in percentage) of the legend used in the automatic layout algorithm.
  2450. /// </summary>
  2451. /// <remarks>
  2452. /// If the legend is docked to the left or right, this property determines the maximum width of the legend, measured as a percentage.
  2453. /// If the legend is docked to the top or bottom, this property determines the maximum height of the legend, measured as a percentage.
  2454. /// </remarks>
  2455. [
  2456. SRCategory("CategoryAttributeDocking"),
  2457. DefaultValue(50f),
  2458. SRDescription("DescriptionAttributeLegend_MaxAutoSize"),
  2459. ]
  2460. public float MaximumAutoSize
  2461. {
  2462. get
  2463. {
  2464. return this._maximumLegendAutoSize;
  2465. }
  2466. set
  2467. {
  2468. if(value < 0f || value > 100f)
  2469. {
  2470. throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMaximumAutoSizeInvalid));
  2471. }
  2472. this._maximumLegendAutoSize = value;
  2473. this.Invalidate(false);
  2474. CallOnModifing();
  2475. }
  2476. }
  2477. /// <summary>
  2478. /// Gets a collection of legend columns.
  2479. /// </summary>
  2480. [
  2481. SRCategory("CategoryAttributeCellColumns"),
  2482. SRDescription("DescriptionAttributeLegend_CellColumns"),
  2483. DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  2484. #if DESIGNER
  2485. Editor(typeof(LegendCellColumnCollectionEditor), typeof(UITypeEditor)),
  2486. #endif
  2487. ]
  2488. public LegendCellColumnCollection CellColumns
  2489. {
  2490. get
  2491. {
  2492. return this._cellColumns;
  2493. }
  2494. }
  2495. /// <summary>
  2496. /// Gets the legend table style.
  2497. /// </summary>
  2498. [
  2499. SRCategory("CategoryAttributeAppearance"),
  2500. Bindable(true),
  2501. DefaultValue(LegendTableStyle.Auto),
  2502. SRDescription("DescriptionAttributeLegend_TableStyle"),
  2503. NotifyParentPropertyAttribute(true),
  2504. ParenthesizePropertyNameAttribute(true)
  2505. ]
  2506. public LegendTableStyle TableStyle
  2507. {
  2508. get
  2509. {
  2510. return this._legendTableStyle;
  2511. }
  2512. set
  2513. {
  2514. this._legendTableStyle = value;
  2515. this.Invalidate(false);
  2516. CallOnModifing();
  2517. }
  2518. }
  2519. /// <summary>
  2520. /// Gets the legend header separator style.
  2521. /// </summary>
  2522. [
  2523. SRCategory("CategoryAttributeCellColumns"),
  2524. DefaultValue(typeof(LegendSeparatorStyle), "None"),
  2525. SRDescription("DescriptionAttributeLegend_HeaderSeparator"),
  2526. ]
  2527. public LegendSeparatorStyle HeaderSeparator
  2528. {
  2529. get
  2530. {
  2531. return this._headerSeparator;
  2532. }
  2533. set
  2534. {
  2535. if(value != this._headerSeparator)
  2536. {
  2537. this._headerSeparator = value;
  2538. this.Invalidate(false);
  2539. CallOnModifing();
  2540. }
  2541. }
  2542. }
  2543. /// <summary>
  2544. /// Gets or sets the color of the legend header separator.
  2545. /// </summary>
  2546. [
  2547. SRCategory("CategoryAttributeCellColumns"),
  2548. DefaultValue(typeof(Color), "Black"),
  2549. SRDescription("DescriptionAttributeLegend_HeaderSeparatorColor"),
  2550. TypeConverter(typeof(ColorConverter)),
  2551. #if DESIGNER
  2552. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2553. #endif
  2554. ]
  2555. public Color HeaderSeparatorColor
  2556. {
  2557. get
  2558. {
  2559. return this._headerSeparatorColor;
  2560. }
  2561. set
  2562. {
  2563. if(value != this._headerSeparatorColor)
  2564. {
  2565. this._headerSeparatorColor = value;
  2566. this.Invalidate(false);
  2567. CallOnModifing();
  2568. }
  2569. }
  2570. }
  2571. /// <summary>
  2572. /// Gets or sets the separator style of the legend table columns.
  2573. /// </summary>
  2574. [
  2575. SRCategory("CategoryAttributeCellColumns"),
  2576. DefaultValue(typeof(LegendSeparatorStyle), "None"),
  2577. SRDescription("DescriptionAttributeLegend_ItemColumnSeparator"),
  2578. ]
  2579. public LegendSeparatorStyle ItemColumnSeparator
  2580. {
  2581. get
  2582. {
  2583. return this._itemColumnSeparator;
  2584. }
  2585. set
  2586. {
  2587. if(value != this._itemColumnSeparator)
  2588. {
  2589. this._itemColumnSeparator = value;
  2590. this.Invalidate(false);
  2591. CallOnModifing();
  2592. }
  2593. }
  2594. }
  2595. /// <summary>
  2596. /// Gets or sets the color of the separator of the legend table columns.
  2597. /// </summary>
  2598. [
  2599. SRCategory("CategoryAttributeCellColumns"),
  2600. DefaultValue(typeof(Color), "Black"),
  2601. SRDescription("DescriptionAttributeLegend_ItemColumnSeparatorColor"),
  2602. TypeConverter(typeof(ColorConverter)),
  2603. #if DESIGNER
  2604. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2605. #endif
  2606. ]
  2607. public Color ItemColumnSeparatorColor
  2608. {
  2609. get
  2610. {
  2611. return this._itemColumnSeparatorColor;
  2612. }
  2613. set
  2614. {
  2615. if(value != this._itemColumnSeparatorColor)
  2616. {
  2617. this._itemColumnSeparatorColor = value;
  2618. this.Invalidate(false);
  2619. CallOnModifing();
  2620. }
  2621. }
  2622. }
  2623. /// <summary>
  2624. /// Gets or sets the legend table column spacing, as a percentage of the legend text font.
  2625. /// </summary>
  2626. [
  2627. SRCategory("CategoryAttributeCellColumns"),
  2628. DefaultValue(50),
  2629. SRDescription("DescriptionAttributeLegend_ItemColumnSpacing"),
  2630. ]
  2631. public int ItemColumnSpacing
  2632. {
  2633. get
  2634. {
  2635. return this._itemColumnSpacing;
  2636. }
  2637. set
  2638. {
  2639. if(value != this._itemColumnSpacing)
  2640. {
  2641. if(value < 0)
  2642. {
  2643. throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendColumnSpacingInvalid));
  2644. }
  2645. this._itemColumnSpacing = value;
  2646. this.Invalidate(false);
  2647. CallOnModifing();
  2648. }
  2649. }
  2650. }
  2651. /// <summary>
  2652. /// Gets or sets the legend background color.
  2653. /// </summary>
  2654. [
  2655. DefaultValue(typeof(Color), ""),
  2656. SRCategory("CategoryAttributeAppearance"),
  2657. Bindable(true),
  2658. SRDescription("DescriptionAttributeBackColor"),
  2659. NotifyParentPropertyAttribute(true),
  2660. TypeConverter(typeof(ColorConverter)),
  2661. #if DESIGNER
  2662. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2663. #endif
  2664. ]
  2665. public Color BackColor
  2666. {
  2667. get
  2668. {
  2669. return _backColor;
  2670. }
  2671. set
  2672. {
  2673. _backColor = value;
  2674. this.Invalidate(false);
  2675. CallOnModifing();
  2676. }
  2677. }
  2678. /// <summary>
  2679. /// Gets or sets the legend border color.
  2680. /// </summary>
  2681. [
  2682. DefaultValue(typeof(Color), ""),
  2683. SRCategory("CategoryAttributeAppearance"),
  2684. Bindable(true),
  2685. SRDescription("DescriptionAttributeBorderColor"),
  2686. NotifyParentPropertyAttribute(true),
  2687. TypeConverter(typeof(ColorConverter)),
  2688. #if DESIGNER
  2689. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2690. #endif
  2691. ]
  2692. public Color BorderColor
  2693. {
  2694. get
  2695. {
  2696. return _borderColor;
  2697. }
  2698. set
  2699. {
  2700. _borderColor = value;
  2701. this.Invalidate(false);
  2702. CallOnModifing();
  2703. }
  2704. }
  2705. /// <summary>
  2706. /// Gets or sets the legend border style.
  2707. /// </summary>
  2708. [
  2709. SRCategory("CategoryAttributeAppearance"),
  2710. Bindable(true),
  2711. DefaultValue(ChartDashStyle.Solid),
  2712. SRDescription("DescriptionAttributeBorderDashStyle"),
  2713. NotifyParentPropertyAttribute(true)
  2714. ]
  2715. public ChartDashStyle BorderDashStyle
  2716. {
  2717. get
  2718. {
  2719. return _borderDashStyle;
  2720. }
  2721. set
  2722. {
  2723. _borderDashStyle = value;
  2724. this.Invalidate(false);
  2725. CallOnModifing();
  2726. }
  2727. }
  2728. /// <summary>
  2729. /// Gets or sets the legend border width.
  2730. /// </summary>
  2731. [
  2732. SRCategory("CategoryAttributeAppearance"),
  2733. Bindable(true),
  2734. DefaultValue(1),
  2735. SRDescription("DescriptionAttributeBorderWidth"),
  2736. NotifyParentPropertyAttribute(true)
  2737. ]
  2738. public int BorderWidth
  2739. {
  2740. get
  2741. {
  2742. return _borderWidth;
  2743. }
  2744. set
  2745. {
  2746. if(value < 0)
  2747. {
  2748. throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendBorderWidthIsNegative));
  2749. }
  2750. _borderWidth = value;
  2751. this.Invalidate(false);
  2752. CallOnModifing();
  2753. }
  2754. }
  2755. /// <summary>
  2756. /// Gets or sets the legend background image.
  2757. /// </summary>
  2758. [
  2759. SRCategory("CategoryAttributeAppearance"),
  2760. Bindable(true),
  2761. DefaultValue(""),
  2762. SRDescription("DescriptionAttributeBackImage"),
  2763. #if DESIGNER
  2764. Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
  2765. #endif
  2766. NotifyParentPropertyAttribute(true)
  2767. ]
  2768. public string BackImage
  2769. {
  2770. get
  2771. {
  2772. return _backImage;
  2773. }
  2774. set
  2775. {
  2776. _backImage = value;
  2777. this.Invalidate(true);
  2778. CallOnModifing();
  2779. }
  2780. }
  2781. /// <summary>
  2782. /// Gets or sets the legend background image drawing mode.
  2783. /// </summary>
  2784. [
  2785. SRCategory("CategoryAttributeAppearance"),
  2786. Bindable(true),
  2787. DefaultValue(ChartImageWrapMode.Tile),
  2788. NotifyParentPropertyAttribute(true),
  2789. SRDescription("DescriptionAttributeImageWrapMode")
  2790. ]
  2791. public ChartImageWrapMode BackImageWrapMode
  2792. {
  2793. get
  2794. {
  2795. return _backImageWrapMode;
  2796. }
  2797. set
  2798. {
  2799. _backImageWrapMode = value;
  2800. this.Invalidate(true);
  2801. CallOnModifing();
  2802. }
  2803. }
  2804. /// <summary>
  2805. /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
  2806. /// </summary>
  2807. [
  2808. SRCategory("CategoryAttributeAppearance"),
  2809. Bindable(true),
  2810. DefaultValue(typeof(Color), ""),
  2811. NotifyParentPropertyAttribute(true),
  2812. SRDescription("DescriptionAttributeImageTransparentColor"),
  2813. TypeConverter(typeof(ColorConverter)),
  2814. #if DESIGNER
  2815. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2816. #endif
  2817. ]
  2818. public Color BackImageTransparentColor
  2819. {
  2820. get
  2821. {
  2822. return _backImageTransparentColor;
  2823. }
  2824. set
  2825. {
  2826. _backImageTransparentColor = value;
  2827. this.Invalidate(true);
  2828. CallOnModifing();
  2829. }
  2830. }
  2831. /// <summary>
  2832. /// Gets or sets the background image alignment used for the unscaled drawing mode.
  2833. /// </summary>
  2834. [
  2835. SRCategory("CategoryAttributeAppearance"),
  2836. Bindable(true),
  2837. DefaultValue(ChartImageAlignmentStyle.TopLeft),
  2838. NotifyParentPropertyAttribute(true),
  2839. SRDescription("DescriptionAttributeBackImageAlign")
  2840. ]
  2841. public ChartImageAlignmentStyle BackImageAlignment
  2842. {
  2843. get
  2844. {
  2845. return _backImageAlignment;
  2846. }
  2847. set
  2848. {
  2849. _backImageAlignment = value;
  2850. this.Invalidate(true);
  2851. CallOnModifing();
  2852. }
  2853. }
  2854. /// <summary>
  2855. /// Gets or sets background gradient style of the legend.
  2856. /// </summary>
  2857. [
  2858. SRCategory("CategoryAttributeAppearance"),
  2859. Bindable(true),
  2860. DefaultValue(GradientStyle.None),
  2861. NotifyParentPropertyAttribute(true),
  2862. SRDescription("DescriptionAttributeBackGradientStyle"),
  2863. #if DESIGNER
  2864. Editor(typeof(GradientEditor), typeof(UITypeEditor))
  2865. #endif
  2866. ]
  2867. public GradientStyle BackGradientStyle
  2868. {
  2869. get
  2870. {
  2871. return _backGradientStyle;
  2872. }
  2873. set
  2874. {
  2875. _backGradientStyle = value;
  2876. this.Invalidate(true);
  2877. CallOnModifing();
  2878. }
  2879. }
  2880. /// <summary>
  2881. /// Gets or sets the secondary background color.
  2882. /// <seealso cref="BackColor"/>
  2883. /// <seealso cref="BackHatchStyle"/>
  2884. /// <seealso cref="BackGradientStyle"/>
  2885. /// </summary>
  2886. /// <value>
  2887. /// A <see cref="Color"/> value used for the secondary color of background with
  2888. /// hatching or gradient fill.
  2889. /// </value>
  2890. /// <remarks>
  2891. /// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
  2892. /// <see cref="BackGradientStyle"/> are used.
  2893. /// </remarks>
  2894. [
  2895. SRCategory("CategoryAttributeAppearance"),
  2896. Bindable(true),
  2897. DefaultValue(typeof(Color), ""),
  2898. NotifyParentPropertyAttribute(true),
  2899. SRDescription("DescriptionAttributeBackSecondaryColor"),
  2900. TypeConverter(typeof(ColorConverter)),
  2901. #if DESIGNER
  2902. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2903. #endif
  2904. ]
  2905. public Color BackSecondaryColor
  2906. {
  2907. get
  2908. {
  2909. return _backSecondaryColor;
  2910. }
  2911. set
  2912. {
  2913. _backSecondaryColor = value;
  2914. this.Invalidate(true);
  2915. CallOnModifing();
  2916. }
  2917. }
  2918. /// <summary>
  2919. /// Gets or sets the background hatch style.
  2920. /// <seealso cref="BackSecondaryColor"/>
  2921. /// <seealso cref="BackColor"/>
  2922. /// <seealso cref="BackGradientStyle"/>
  2923. /// </summary>
  2924. /// <value>
  2925. /// A <see cref="ChartHatchStyle"/> value used for the background.
  2926. /// </value>
  2927. /// <remarks>
  2928. /// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
  2929. /// </remarks>
  2930. [
  2931. SRCategory("CategoryAttributeAppearance"),
  2932. Bindable(true),
  2933. DefaultValue(ChartHatchStyle.None),
  2934. NotifyParentPropertyAttribute(true),
  2935. SRDescription("DescriptionAttributeBackHatchStyle"),
  2936. #if DESIGNER
  2937. Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
  2938. #endif
  2939. ]
  2940. public ChartHatchStyle BackHatchStyle
  2941. {
  2942. get
  2943. {
  2944. return _backHatchStyle;
  2945. }
  2946. set
  2947. {
  2948. _backHatchStyle = value;
  2949. this.Invalidate(true);
  2950. CallOnModifing();
  2951. }
  2952. }
  2953. /// <summary>
  2954. /// Gets or sets the font of the legend text.
  2955. /// </summary>
  2956. [
  2957. SRCategory("CategoryAttributeAppearance"),
  2958. Bindable(true),
  2959. DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
  2960. SRDescription("DescriptionAttributeLegend_Font"),
  2961. NotifyParentPropertyAttribute(true)
  2962. ]
  2963. public Font Font
  2964. {
  2965. get
  2966. {
  2967. return _font;
  2968. }
  2969. set
  2970. {
  2971. this.IsTextAutoFit = false;
  2972. _font = value;
  2973. this.Invalidate(false);
  2974. }
  2975. }
  2976. /// <summary>
  2977. /// Gets or sets the color of the legend text.
  2978. /// </summary>
  2979. [
  2980. SRCategory("CategoryAttributeAppearance"),
  2981. Bindable(true),
  2982. DefaultValue(typeof(Color), "Black"),
  2983. SRDescription("DescriptionAttributeLegendFontColor"),
  2984. NotifyParentPropertyAttribute(true),
  2985. TypeConverter(typeof(ColorConverter)),
  2986. #if DESIGNER
  2987. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2988. #endif
  2989. ]
  2990. public Color ForeColor
  2991. {
  2992. get
  2993. {
  2994. return _foreColor;
  2995. }
  2996. set
  2997. {
  2998. _foreColor = value;
  2999. this.Invalidate(true);
  3000. CallOnModifing();
  3001. }
  3002. }
  3003. /// <summary>
  3004. /// Gets or sets the text alignment.
  3005. /// </summary>
  3006. [
  3007. SRCategory("CategoryAttributeDocking"),
  3008. Bindable(true),
  3009. DefaultValue(StringAlignment.Near),
  3010. SRDescription("DescriptionAttributeLegend_Alignment"),
  3011. NotifyParentPropertyAttribute(true)
  3012. ]
  3013. public StringAlignment Alignment
  3014. {
  3015. get
  3016. {
  3017. return _legendAlignment;
  3018. }
  3019. set
  3020. {
  3021. _legendAlignment = value;
  3022. this.Invalidate(false);
  3023. CallOnModifing();
  3024. }
  3025. }
  3026. /// <summary>
  3027. /// Gets or sets the property that specifies where the legend docks.
  3028. /// </summary>
  3029. [
  3030. SRCategory("CategoryAttributeDocking"),
  3031. Bindable(true),
  3032. DefaultValue(Docking.Right),
  3033. SRDescription("DescriptionAttributeLegend_Docking"),
  3034. NotifyParentPropertyAttribute(true)
  3035. ]
  3036. public Docking Docking
  3037. {
  3038. get
  3039. {
  3040. return _legendDocking;
  3041. }
  3042. set
  3043. {
  3044. _legendDocking = value;
  3045. this.Invalidate(false);
  3046. CallOnModifing();
  3047. }
  3048. }
  3049. /// <summary>
  3050. /// Gets or sets the offset between the legend and its shadow.
  3051. /// <seealso cref="ShadowColor"/>
  3052. /// </summary>
  3053. /// <value>
  3054. /// An integer value that represents the offset between the legend and its shadow.
  3055. /// </value>
  3056. [
  3057. SRCategory("CategoryAttributeAppearance"),
  3058. Bindable(true),
  3059. DefaultValue(0),
  3060. SRDescription("DescriptionAttributeShadowOffset"),
  3061. NotifyParentPropertyAttribute(true)
  3062. ]
  3063. public int ShadowOffset
  3064. {
  3065. get
  3066. {
  3067. return _shadowOffset;
  3068. }
  3069. set
  3070. {
  3071. _shadowOffset = value;
  3072. this.Invalidate(false);
  3073. CallOnModifing();
  3074. }
  3075. }
  3076. /// <summary>
  3077. /// Gets or sets the color of a legend's shadow.
  3078. /// <seealso cref="ShadowOffset"/>
  3079. /// </summary>
  3080. /// <value>
  3081. /// A <see cref="Color"/> value used to draw a legend's shadow.
  3082. /// </value>
  3083. [
  3084. SRCategory("CategoryAttributeAppearance"),
  3085. Bindable(true),
  3086. DefaultValue(typeof(Color), "128, 0, 0, 0"),
  3087. SRDescription("DescriptionAttributeShadowColor"),
  3088. NotifyParentPropertyAttribute(true),
  3089. TypeConverter(typeof(ColorConverter)),
  3090. #if DESIGNER
  3091. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  3092. #endif
  3093. ]
  3094. public Color ShadowColor
  3095. {
  3096. get
  3097. {
  3098. return _shadowColor;
  3099. }
  3100. set
  3101. {
  3102. _shadowColor = value;
  3103. this.Invalidate(true);
  3104. CallOnModifing();
  3105. }
  3106. }
  3107. /// <summary>
  3108. /// Gets or sets the name of the chart area name inside which the legend is drawn.
  3109. /// </summary>
  3110. [
  3111. SRCategory("CategoryAttributeAppearance"),
  3112. Browsable(false),
  3113. Bindable(false),
  3114. DefaultValue(Constants.NotSetValue),
  3115. NotifyParentPropertyAttribute(true),
  3116. SRDescription("DescriptionAttributeLegend_InsideChartArea"),
  3117. EditorBrowsableAttribute(EditorBrowsableState.Never),
  3118. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content),
  3119. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  3120. TypeConverter(typeof(LegendAreaNameConverter))
  3121. ]
  3122. public string InsideChartArea
  3123. {
  3124. get
  3125. {
  3126. if(this.Common != null &&
  3127. this.Common.Chart != null &&
  3128. this.Common.Chart.serializing)
  3129. {
  3130. return "NotSet";
  3131. }
  3132. return this.DockedToChartArea;
  3133. }
  3134. set
  3135. {
  3136. if(value.Length == 0)
  3137. {
  3138. this.DockedToChartArea = Constants.NotSetValue;
  3139. }
  3140. else
  3141. {
  3142. this.DockedToChartArea = value;
  3143. }
  3144. this.Invalidate(false);
  3145. }
  3146. }
  3147. /// <summary>
  3148. /// Gets the custom legend items.
  3149. /// </summary>
  3150. [
  3151. SRCategory("CategoryAttributeAppearance"),
  3152. Bindable(true),
  3153. NotifyParentPropertyAttribute(true),
  3154. SRDescription("DescriptionAttributeLegend_CustomItems"),
  3155. DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  3156. #if DESIGNER
  3157. Editor(typeof(LegendItemCollectionEditor), typeof(UITypeEditor))
  3158. #endif
  3159. ]
  3160. public LegendItemsCollection CustomItems
  3161. {
  3162. get
  3163. {
  3164. return _customLegends;
  3165. }
  3166. }
  3167. /// <summary>
  3168. /// Gets or sets a property that defines the preferred number of characters in a line of the legend text.
  3169. /// </summary>
  3170. /// <remarks>
  3171. /// When legend text exceeds the value defined in the <b>TextWrapThreshold</b> property, it will be
  3172. /// automatically wrapped on the next whitespace. Text will not be wrapped if there is no whitespace
  3173. /// characters in the text. Set this property to zero to disable the feature.
  3174. /// </remarks>
  3175. [
  3176. SRCategory("CategoryAttributeAppearance"),
  3177. DefaultValue(25),
  3178. SRDescription("DescriptionAttributeLegend_TextWrapThreshold"),
  3179. ]
  3180. public int TextWrapThreshold
  3181. {
  3182. get
  3183. {
  3184. return this._textWrapThreshold;
  3185. }
  3186. set
  3187. {
  3188. if(value != this._textWrapThreshold)
  3189. {
  3190. if(value < 0)
  3191. {
  3192. throw (new ArgumentException(SR.ExceptionTextThresholdIsNegative, "value"));
  3193. }
  3194. this._textWrapThreshold = value;
  3195. this.Invalidate(false);
  3196. CallOnModifing();
  3197. }
  3198. }
  3199. }
  3200. /// <summary>
  3201. /// Gets or sets a property that specifies the order that legend items are shown. This property only affects
  3202. /// legend items automatically added for the chart series and has no effect on custom legend items.
  3203. /// </summary>
  3204. /// <remarks>
  3205. /// When the <b>LegendItemOrder</b> property is set to <b>Auto</b>, the legend will automatically be reversed
  3206. /// if StackedColumn, StackedColumn100, StackedArea or StackedArea100 chart types are used.
  3207. /// </remarks>
  3208. [
  3209. SRCategory("CategoryAttributeAppearance"),
  3210. DefaultValue(LegendItemOrder.Auto),
  3211. SRDescription("DescriptionAttributeLegend_Reversed"),
  3212. ]
  3213. public LegendItemOrder LegendItemOrder
  3214. {
  3215. get
  3216. {
  3217. return this._legendItemOrder;
  3218. }
  3219. set
  3220. {
  3221. if(value != this._legendItemOrder)
  3222. {
  3223. this._legendItemOrder = value;
  3224. this.Invalidate(false);
  3225. CallOnModifing();
  3226. }
  3227. }
  3228. }
  3229. /// <summary>
  3230. /// Gets or sets a flag which indicates whether
  3231. /// legend rows should be drawn with interlaced background color.
  3232. /// </summary>
  3233. [
  3234. SRCategory("CategoryAttributeAppearance"),
  3235. DefaultValue(false),
  3236. SRDescription("DescriptionAttributeLegend_InterlacedRows"),
  3237. ]
  3238. public bool InterlacedRows
  3239. {
  3240. get
  3241. {
  3242. return this._interlacedRows;
  3243. }
  3244. set
  3245. {
  3246. if(value != this._interlacedRows)
  3247. {
  3248. this._interlacedRows = value;
  3249. this.Invalidate(false);
  3250. CallOnModifing();
  3251. }
  3252. }
  3253. }
  3254. /// <summary>
  3255. /// Gets or sets the legend interlaced row's background color. Only applicable if interlaced rows are used.
  3256. /// </summary>
  3257. [
  3258. SRCategory("CategoryAttributeAppearance"),
  3259. DefaultValue(typeof(Color), ""),
  3260. SRDescription("DescriptionAttributeLegend_InterlacedRowsColor"),
  3261. TypeConverter(typeof(ColorConverter)),
  3262. #if DESIGNER
  3263. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  3264. #endif
  3265. ]
  3266. public Color InterlacedRowsColor
  3267. {
  3268. get
  3269. {
  3270. return this._interlacedRowsColor;
  3271. }
  3272. set
  3273. {
  3274. if(value != this._interlacedRowsColor)
  3275. {
  3276. this._interlacedRowsColor = value;
  3277. this.Invalidate(false);
  3278. CallOnModifing();
  3279. }
  3280. }
  3281. }
  3282. #endregion
  3283. #region Legend Title Properties
  3284. /// <summary>
  3285. /// Gets or sets the title text of the legend.
  3286. /// </summary>
  3287. [
  3288. SRCategory("CategoryAttributeTitle"),
  3289. DefaultValue(""),
  3290. SRDescription("DescriptionAttributeLegend_Title"),
  3291. ]
  3292. public string Title
  3293. {
  3294. get
  3295. {
  3296. return this._title;
  3297. }
  3298. set
  3299. {
  3300. if(value != this._title)
  3301. {
  3302. this._title = value;
  3303. this.Invalidate(false);
  3304. CallOnModifing();
  3305. }
  3306. }
  3307. }
  3308. /// <summary>
  3309. /// Gets or sets the text color of the legend title.
  3310. /// </summary>
  3311. [
  3312. SRCategory("CategoryAttributeTitle"),
  3313. DefaultValue(typeof(Color), "Black"),
  3314. SRDescription("DescriptionAttributeLegend_TitleColor"),
  3315. TypeConverter(typeof(ColorConverter)),
  3316. #if DESIGNER
  3317. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  3318. #endif
  3319. ]
  3320. public Color TitleForeColor
  3321. {
  3322. get
  3323. {
  3324. return this._titleForeColor;
  3325. }
  3326. set
  3327. {
  3328. if(value != this._titleForeColor)
  3329. {
  3330. this._titleForeColor = value;
  3331. this.Invalidate(false);
  3332. CallOnModifing();
  3333. }
  3334. }
  3335. }
  3336. /// <summary>
  3337. /// Gets or sets the background color of the legend title.
  3338. /// </summary>
  3339. [
  3340. SRCategory("CategoryAttributeTitle"),
  3341. DefaultValue(typeof(Color), ""),
  3342. SRDescription("DescriptionAttributeTitleBackColor"),
  3343. TypeConverter(typeof(ColorConverter)),
  3344. #if DESIGNER
  3345. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  3346. #endif
  3347. ]
  3348. public Color TitleBackColor
  3349. {
  3350. get
  3351. {
  3352. return this._titleBackColor;
  3353. }
  3354. set
  3355. {
  3356. if(value != this._titleBackColor)
  3357. {
  3358. this._titleBackColor = value;
  3359. this.Invalidate(false);
  3360. CallOnModifing();
  3361. }
  3362. }
  3363. }
  3364. /// <summary>
  3365. /// Gets or sets the font of the legend title.
  3366. /// </summary>
  3367. [
  3368. SRCategory("CategoryAttributeTitle"),
  3369. DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt, style=Bold"),
  3370. SRDescription("DescriptionAttributeTitleFont"),
  3371. ]
  3372. public Font TitleFont
  3373. {
  3374. get
  3375. {
  3376. return this._titleFont;
  3377. }
  3378. set
  3379. {
  3380. if(value != this._titleFont)
  3381. {
  3382. this._titleFont = value;
  3383. this.Invalidate(false);
  3384. CallOnModifing();
  3385. }
  3386. }
  3387. }
  3388. /// <summary>
  3389. /// Gets or sets the text alignment of the legend title.
  3390. /// </summary>
  3391. [
  3392. SRCategory("CategoryAttributeTitle"),
  3393. DefaultValue(typeof(StringAlignment), "Center"),
  3394. SRDescription("DescriptionAttributeLegend_TitleAlignment"),
  3395. ]
  3396. public StringAlignment TitleAlignment
  3397. {
  3398. get
  3399. {
  3400. return this._titleAlignment;
  3401. }
  3402. set
  3403. {
  3404. if(value != this._titleAlignment)
  3405. {
  3406. this._titleAlignment = value;
  3407. this.Invalidate(false);
  3408. CallOnModifing();
  3409. }
  3410. }
  3411. }
  3412. /// <summary>
  3413. /// Gets or sets the separator style of the legend title.
  3414. /// </summary>
  3415. [
  3416. SRCategory("CategoryAttributeTitle"),
  3417. DefaultValue(typeof(LegendSeparatorStyle), "None"),
  3418. SRDescription("DescriptionAttributeLegend_TitleSeparator"),
  3419. ]
  3420. public LegendSeparatorStyle TitleSeparator
  3421. {
  3422. get
  3423. {
  3424. return this._titleSeparator;
  3425. }
  3426. set
  3427. {
  3428. if(value != this._titleSeparator)
  3429. {
  3430. this._titleSeparator = value;
  3431. this.Invalidate(false);
  3432. CallOnModifing();
  3433. }
  3434. }
  3435. }
  3436. /// <summary>
  3437. /// Gets or sets the separator color of the legend title.
  3438. /// </summary>
  3439. [
  3440. SRCategory("CategoryAttributeTitle"),
  3441. DefaultValue(typeof(Color), "Black"),
  3442. SRDescription("DescriptionAttributeLegend_TitleSeparatorColor"),
  3443. TypeConverter(typeof(ColorConverter)),
  3444. #if DESIGNER
  3445. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  3446. #endif
  3447. ]
  3448. public Color TitleSeparatorColor
  3449. {
  3450. get
  3451. {
  3452. return this._titleSeparatorColor;
  3453. }
  3454. set
  3455. {
  3456. if(value != this._titleSeparatorColor)
  3457. {
  3458. this._titleSeparatorColor = value;
  3459. this.Invalidate(false);
  3460. CallOnModifing();
  3461. }
  3462. }
  3463. }
  3464. #endregion // Legend Title Properties
  3465. #region Legent Title and Header Helper methods
  3466. /// <summary>
  3467. /// Gets legend title size in relative coordinates.
  3468. /// </summary>
  3469. /// <param name="chartGraph">Chart graphics.</param>
  3470. /// <param name="titleMaxSize">Maximum possible legend title size.</param>
  3471. /// <returns>Legend yitle size.</returns>
  3472. private Size GetTitleSize(ChartGraphics chartGraph, Size titleMaxSize)
  3473. {
  3474. Size titleSize = Size.Empty;
  3475. if(this.Title.Length > 0)
  3476. {
  3477. // Adjust available space
  3478. titleMaxSize.Width -= this.GetBorderSize() * 2 + this._offset.Width;
  3479. // Measure title text size
  3480. titleSize = chartGraph.MeasureStringAbs(
  3481. this.Title.Replace("\\n", "\n"),
  3482. this.TitleFont,
  3483. titleMaxSize,
  3484. StringFormat.GenericTypographic);
  3485. // Add text spacing
  3486. titleSize.Height += this._offset.Height;
  3487. titleSize.Width += this._offset.Width;
  3488. // Add space required for the title separator
  3489. titleSize.Height += this.GetSeparatorSize(this.TitleSeparator).Height;
  3490. }
  3491. return titleSize;
  3492. }
  3493. /// <summary>
  3494. /// Gets legend header size in relative coordinates.
  3495. /// </summary>
  3496. /// <param name="chartGraph">Chart graphics.</param>
  3497. /// <param name="legendColumn">Legend column to get the header for.</param>
  3498. /// <returns>Legend yitle size.</returns>
  3499. private Size GetHeaderSize(ChartGraphics chartGraph, LegendCellColumn legendColumn)
  3500. {
  3501. Size headerSize = Size.Empty;
  3502. if(legendColumn.HeaderText.Length > 0)
  3503. {
  3504. // Measure title text size
  3505. headerSize = chartGraph.MeasureStringAbs(
  3506. legendColumn.HeaderText.Replace("\\n", "\n") + "I",
  3507. legendColumn.HeaderFont);
  3508. // Add text spacing
  3509. headerSize.Height += this._offset.Height;
  3510. headerSize.Width += this._offset.Width;
  3511. // Add space required for the title separator
  3512. headerSize.Height += this.GetSeparatorSize(this.HeaderSeparator).Height;
  3513. }
  3514. return headerSize;
  3515. }
  3516. /// <summary>
  3517. /// Draw Legend header.
  3518. /// </summary>
  3519. /// <param name="chartGraph">Chart graphics to draw the header on.</param>
  3520. private void DrawLegendHeader(ChartGraphics chartGraph)
  3521. {
  3522. // Check if header should be drawn
  3523. if(!this._headerPosition.IsEmpty &&
  3524. this._headerPosition.Width > 0 &&
  3525. this._headerPosition.Height > 0)
  3526. {
  3527. int prevRightLocation = -1;
  3528. bool redrawLegendBorder = false;
  3529. // Get Legend position
  3530. Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
  3531. legendPosition.Y += /*this.offset.Height + */this.GetBorderSize();
  3532. legendPosition.Height -= 2 * (this._offset.Height + this.GetBorderSize());
  3533. legendPosition.X += this.GetBorderSize();
  3534. legendPosition.Width -= 2 * this.GetBorderSize();
  3535. if(this.GetBorderSize() > 0)
  3536. {
  3537. ++legendPosition.Height;
  3538. ++legendPosition.Width;
  3539. }
  3540. // Check if at least 1 column header has non-empty background color
  3541. bool headerBackFill = false;
  3542. for(int subColumnIndex = 0; subColumnIndex < this.CellColumns.Count; subColumnIndex++ )
  3543. {
  3544. LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
  3545. if(!legendColumn.HeaderBackColor.IsEmpty)
  3546. {
  3547. headerBackFill = true;
  3548. }
  3549. }
  3550. // Iterate through all columns
  3551. for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
  3552. {
  3553. int columnStart = 0;
  3554. int columnWidth = 0;
  3555. // Iterate through all sub-columns
  3556. int numberOfSubColumns = this._subColumnSizes.GetLength(1);
  3557. for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++ )
  3558. {
  3559. // Calculate position of the header
  3560. Rectangle rect = this._headerPosition;
  3561. if(_horizontalSpaceLeft > 0)
  3562. {
  3563. rect.X += (int)(this._horizontalSpaceLeft / 2f);
  3564. }
  3565. if(prevRightLocation != -1)
  3566. {
  3567. rect.X = prevRightLocation;
  3568. }
  3569. rect.Width = this._subColumnSizes[columnIndex, subColumnIndex];
  3570. prevRightLocation = rect.Right;
  3571. // Remember column start position and update width
  3572. if(subColumnIndex == 0)
  3573. {
  3574. columnStart = rect.Left;
  3575. }
  3576. columnWidth += rect.Width;
  3577. // Make sure header position do not go outside of the legend
  3578. rect.Intersect(legendPosition);
  3579. if(rect.Width > 0 && rect.Height > 0)
  3580. {
  3581. // Define fill rectangle
  3582. Rectangle fillRect = rect;
  3583. // Make sure header fill riches legend top border
  3584. if(this._titlePosition.Height <= 0)
  3585. {
  3586. fillRect.Y -= this._offset.Height;
  3587. fillRect.Height += this._offset.Height;
  3588. }
  3589. // Stretch header fill rectangle and separators when vertical
  3590. // separator are used or if there is 1 column with header background
  3591. if( (this._itemColumns == 1 && headerBackFill) ||
  3592. this.ItemColumnSeparator != LegendSeparatorStyle.None)
  3593. {
  3594. // For the first cell in the first column stretch filling
  3595. // to the left side of the legend
  3596. if(columnIndex == 0 && subColumnIndex == 0)
  3597. {
  3598. int newX = legendPosition.X;
  3599. columnWidth += columnStart - newX;
  3600. columnStart = newX;
  3601. fillRect.Width += fillRect.X - legendPosition.X;
  3602. fillRect.X = newX;
  3603. }
  3604. // For the last cell in the last column stretch filling
  3605. // to the right side of the legend
  3606. if(columnIndex == (this._itemColumns - 1) &&
  3607. subColumnIndex == (numberOfSubColumns - 1) )
  3608. {
  3609. columnWidth += legendPosition.Right - fillRect.Right + 1;
  3610. fillRect.Width += legendPosition.Right - fillRect.Right + 1;
  3611. }
  3612. // For the first cell of any column except the first one
  3613. // make sure we also fill the item column spacing
  3614. if(columnIndex != 0 && subColumnIndex == 0)
  3615. {
  3616. columnWidth += this._itemColumnSpacingRel / 2;
  3617. columnStart -= this._itemColumnSpacingRel / 2;
  3618. fillRect.Width += this._itemColumnSpacingRel / 2;
  3619. fillRect.X -= this._itemColumnSpacingRel / 2;
  3620. }
  3621. // For the last cell in all columns except the last one
  3622. // make sure we also fill the item column spacing
  3623. if(columnIndex != (this._itemColumns - 1) &&
  3624. subColumnIndex == (numberOfSubColumns - 1) )
  3625. {
  3626. columnWidth += this._itemColumnSpacingRel / 2;
  3627. fillRect.Width += this._itemColumnSpacingRel / 2;
  3628. }
  3629. }
  3630. if(subColumnIndex < this.CellColumns.Count)
  3631. {
  3632. // Draw header background
  3633. LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
  3634. if(!legendColumn.HeaderBackColor.IsEmpty)
  3635. {
  3636. redrawLegendBorder = true;
  3637. // Fill title background
  3638. if(fillRect.Right > legendPosition.Right)
  3639. {
  3640. fillRect.Width -= (legendPosition.Right - fillRect.Right);
  3641. }
  3642. if(fillRect.X < legendPosition.X)
  3643. {
  3644. fillRect.X += legendPosition.X - fillRect.X;
  3645. fillRect.Width -= (legendPosition.X - fillRect.X);
  3646. }
  3647. fillRect.Intersect(legendPosition);
  3648. chartGraph.FillRectangleRel(
  3649. chartGraph.GetRelativeRectangle(fillRect),
  3650. legendColumn.HeaderBackColor,
  3651. ChartHatchStyle.None,
  3652. string.Empty,
  3653. ChartImageWrapMode.Tile,
  3654. Color.Empty,
  3655. ChartImageAlignmentStyle.Center,
  3656. GradientStyle.None,
  3657. Color.Empty,
  3658. Color.Empty,
  3659. 0,
  3660. ChartDashStyle.NotSet,
  3661. Color.Empty,
  3662. 0,
  3663. PenAlignment.Inset);
  3664. }
  3665. // Draw header text
  3666. using(SolidBrush textBrush = new SolidBrush(legendColumn.HeaderForeColor))
  3667. {
  3668. // Set text alignment
  3669. using (StringFormat format = new StringFormat())
  3670. {
  3671. format.Alignment = legendColumn.HeaderAlignment;
  3672. format.LineAlignment = StringAlignment.Center;
  3673. format.FormatFlags = StringFormatFlags.LineLimit;
  3674. format.Trimming = StringTrimming.EllipsisCharacter;
  3675. // Draw string using relative coordinates
  3676. chartGraph.DrawStringRel(
  3677. legendColumn.HeaderText,
  3678. legendColumn.HeaderFont,
  3679. textBrush,
  3680. chartGraph.GetRelativeRectangle(rect),
  3681. format);
  3682. }
  3683. }
  3684. }
  3685. }
  3686. }
  3687. // Draw header separator for each column
  3688. Rectangle separatorRect = this._headerPosition;
  3689. separatorRect.X = columnStart;
  3690. separatorRect.Width = columnWidth;
  3691. if(this.HeaderSeparator == LegendSeparatorStyle.Line || this.HeaderSeparator == LegendSeparatorStyle.DoubleLine)
  3692. {
  3693. // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than
  3694. // any other line. Reduce width to solve the issue.
  3695. legendPosition.Width -= 1;
  3696. }
  3697. separatorRect.Intersect(legendPosition);
  3698. this.DrawSeparator(chartGraph, this.HeaderSeparator, this.HeaderSeparatorColor, true, separatorRect);
  3699. // Add spacing between columns
  3700. prevRightLocation += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
  3701. }
  3702. // Draw legend border to solve any issues with header background overlapping
  3703. if(redrawLegendBorder)
  3704. {
  3705. chartGraph.FillRectangleRel(
  3706. chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
  3707. Color.Transparent,
  3708. ChartHatchStyle.None,
  3709. string.Empty,
  3710. ChartImageWrapMode.Tile,
  3711. Color.Empty,
  3712. ChartImageAlignmentStyle.Center,
  3713. GradientStyle.None,
  3714. Color.Empty,
  3715. BorderColor,
  3716. this.GetBorderSize(),
  3717. BorderDashStyle,
  3718. Color.Empty,
  3719. 0,
  3720. PenAlignment.Inset);
  3721. }
  3722. // Add legend header hot region
  3723. if( Common.ProcessModeRegions && !this._headerPosition.IsEmpty)
  3724. {
  3725. Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._headerPosition), this, ChartElementType.LegendHeader, true );
  3726. }
  3727. }
  3728. }
  3729. /// <summary>
  3730. /// Draw Legend title.
  3731. /// </summary>
  3732. /// <param name="chartGraph">Chart graphics to draw the title on.</param>
  3733. private void DrawLegendTitle(ChartGraphics chartGraph)
  3734. {
  3735. // Check if title text is specified and position recalculated
  3736. if(this.Title.Length > 0 &&
  3737. !this._titlePosition.IsEmpty)
  3738. {
  3739. // Get Legend position
  3740. Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
  3741. legendPosition.Y += this.GetBorderSize();
  3742. legendPosition.Height -= 2 * this.GetBorderSize();
  3743. legendPosition.X += this.GetBorderSize();
  3744. legendPosition.Width -= 2 * this.GetBorderSize();
  3745. if(this.GetBorderSize() > 0)
  3746. {
  3747. ++legendPosition.Height;
  3748. ++legendPosition.Width;
  3749. }
  3750. // Draw title background
  3751. if(!this.TitleBackColor.IsEmpty)
  3752. {
  3753. // Fill title background
  3754. Rectangle fillRect = this._titlePosition;
  3755. fillRect.Intersect(legendPosition);
  3756. chartGraph.FillRectangleRel(
  3757. chartGraph.GetRelativeRectangle(fillRect),
  3758. this.TitleBackColor,
  3759. ChartHatchStyle.None,
  3760. string.Empty,
  3761. ChartImageWrapMode.Tile,
  3762. Color.Empty,
  3763. ChartImageAlignmentStyle.Center,
  3764. GradientStyle.None,
  3765. Color.Empty,
  3766. Color.Empty,
  3767. 0,
  3768. ChartDashStyle.NotSet,
  3769. Color.Empty,
  3770. 0,
  3771. PenAlignment.Inset);
  3772. }
  3773. // Draw title text
  3774. using(SolidBrush textBrush = new SolidBrush(this.TitleForeColor))
  3775. {
  3776. // Set text alignment
  3777. StringFormat format = new StringFormat();
  3778. format.Alignment = this.TitleAlignment;
  3779. //format.LineAlignment = StringAlignment.Center;
  3780. // Shift text rectangle by the top offset amount
  3781. Rectangle rect = this._titlePosition;
  3782. rect.Y += this._offset.Height;
  3783. rect.X += this._offset.Width;
  3784. rect.X += this.GetBorderSize();
  3785. rect.Width -= this.GetBorderSize() * 2 + this._offset.Width;
  3786. // Draw string using relative coordinates
  3787. rect.Intersect(legendPosition);
  3788. chartGraph.DrawStringRel(
  3789. this.Title.Replace("\\n", "\n"),
  3790. this.TitleFont,
  3791. textBrush,
  3792. chartGraph.GetRelativeRectangle(rect),
  3793. format);
  3794. }
  3795. // Draw title separator
  3796. Rectangle separatorPosition = this._titlePosition;
  3797. if(this.TitleSeparator == LegendSeparatorStyle.Line || this.TitleSeparator == LegendSeparatorStyle.DoubleLine)
  3798. {
  3799. // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than
  3800. // any other line. Reduce width to solve the issue.
  3801. legendPosition.Width -= 1;
  3802. }
  3803. separatorPosition.Intersect(legendPosition);
  3804. this.DrawSeparator(chartGraph, this.TitleSeparator, this.TitleSeparatorColor, true, separatorPosition);
  3805. // Draw legend border to solve any issues with title background overlapping
  3806. if(!this.TitleBackColor.IsEmpty ||
  3807. this.TitleSeparator != LegendSeparatorStyle.None)
  3808. {
  3809. chartGraph.FillRectangleRel(
  3810. chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
  3811. Color.Transparent,
  3812. ChartHatchStyle.None,
  3813. string.Empty,
  3814. ChartImageWrapMode.Tile,
  3815. Color.Empty,
  3816. ChartImageAlignmentStyle.Center,
  3817. GradientStyle.None,
  3818. Color.Empty,
  3819. BorderColor,
  3820. this.GetBorderSize(),
  3821. BorderDashStyle,
  3822. Color.Empty,
  3823. 0,
  3824. PenAlignment.Inset);
  3825. }
  3826. }
  3827. }
  3828. /// <summary>
  3829. /// Gets legend separator size in pixels
  3830. /// </summary>
  3831. /// <param name="separatorType">Separator type.</param>
  3832. /// <returns>Separator size in relative coordinates.</returns>
  3833. internal Size GetSeparatorSize(LegendSeparatorStyle separatorType)
  3834. {
  3835. Size size = Size.Empty;
  3836. if(separatorType == LegendSeparatorStyle.None)
  3837. {
  3838. size = Size.Empty;
  3839. }
  3840. else if(separatorType == LegendSeparatorStyle.Line)
  3841. {
  3842. size = new Size(1, 1);
  3843. }
  3844. else if(separatorType == LegendSeparatorStyle.DashLine)
  3845. {
  3846. size = new Size(1, 1);
  3847. }
  3848. else if(separatorType == LegendSeparatorStyle.DotLine)
  3849. {
  3850. size = new Size(1, 1);
  3851. }
  3852. else if(separatorType == LegendSeparatorStyle.ThickLine)
  3853. {
  3854. size = new Size(2, 2);
  3855. }
  3856. else if(separatorType == LegendSeparatorStyle.DoubleLine)
  3857. {
  3858. size = new Size(3, 3);
  3859. }
  3860. else if(separatorType == LegendSeparatorStyle.GradientLine)
  3861. {
  3862. size = new Size(1, 1);
  3863. }
  3864. else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
  3865. {
  3866. size = new Size(2, 2);
  3867. }
  3868. else
  3869. {
  3870. throw (new InvalidOperationException(SR.ExceptionLegendSeparatorTypeUnknown(separatorType.ToString())));
  3871. }
  3872. // For the vertical part of the separator always add additiobal spacing
  3873. size.Width += this._itemColumnSpacingRel;
  3874. return size;
  3875. }
  3876. /// <summary>
  3877. /// Draws specified legend separator.
  3878. /// </summary>
  3879. /// <param name="chartGraph">Chart graphics.</param>
  3880. /// <param name="separatorType">Separator type.</param>
  3881. /// <param name="color">Separator color.</param>
  3882. /// <param name="horizontal">Flag that determines if separator is vertical or horizontal.</param>
  3883. /// <param name="position">Separator position.</param>
  3884. private void DrawSeparator(
  3885. ChartGraphics chartGraph,
  3886. LegendSeparatorStyle separatorType,
  3887. Color color,
  3888. bool horizontal,
  3889. Rectangle position)
  3890. {
  3891. // Temporary disable antialiasing
  3892. SmoothingMode oldSmoothingMode = chartGraph.SmoothingMode;
  3893. chartGraph.SmoothingMode = SmoothingMode.None;
  3894. // Get line position in absolute coordinates
  3895. RectangleF rect = position;
  3896. if(!horizontal)
  3897. {
  3898. rect.X += (int)(_itemColumnSpacingRel / 2f);
  3899. rect.Width -= _itemColumnSpacingRel;
  3900. }
  3901. if(separatorType == LegendSeparatorStyle.Line)
  3902. {
  3903. if(horizontal)
  3904. {
  3905. // Draw horizontal line separator
  3906. chartGraph.DrawLineAbs(
  3907. color,
  3908. 1,
  3909. ChartDashStyle.Solid,
  3910. new PointF(rect.Left, rect.Bottom - 1),
  3911. new PointF(rect.Right, rect.Bottom - 1) );
  3912. }
  3913. else
  3914. {
  3915. // Draw vertical line separator
  3916. chartGraph.DrawLineAbs(
  3917. color,
  3918. 1,
  3919. ChartDashStyle.Solid,
  3920. new PointF(rect.Right - 1, rect.Top),
  3921. new PointF(rect.Right - 1, rect.Bottom) );
  3922. }
  3923. }
  3924. else if(separatorType == LegendSeparatorStyle.DashLine)
  3925. {
  3926. if(horizontal)
  3927. {
  3928. // Draw horizontal line separator
  3929. chartGraph.DrawLineAbs(
  3930. color,
  3931. 1,
  3932. ChartDashStyle.Dash,
  3933. new PointF(rect.Left, rect.Bottom - 1),
  3934. new PointF(rect.Right, rect.Bottom - 1) );
  3935. }
  3936. else
  3937. {
  3938. // Draw vertical line separator
  3939. chartGraph.DrawLineAbs(
  3940. color,
  3941. 1,
  3942. ChartDashStyle.Dash,
  3943. new PointF(rect.Right - 1, rect.Top),
  3944. new PointF(rect.Right - 1, rect.Bottom) );
  3945. }
  3946. }
  3947. else if(separatorType == LegendSeparatorStyle.DotLine)
  3948. {
  3949. if(horizontal)
  3950. {
  3951. // Draw horizontal line separator
  3952. chartGraph.DrawLineAbs(
  3953. color,
  3954. 1,
  3955. ChartDashStyle.Dot,
  3956. new PointF(rect.Left, rect.Bottom - 1),
  3957. new PointF(rect.Right, rect.Bottom - 1) );
  3958. }
  3959. else
  3960. {
  3961. // Draw vertical line separator
  3962. chartGraph.DrawLineAbs(
  3963. color,
  3964. 1,
  3965. ChartDashStyle.Dot,
  3966. new PointF(rect.Right - 1, rect.Top),
  3967. new PointF(rect.Right - 1, rect.Bottom) );
  3968. }
  3969. }
  3970. else if(separatorType == LegendSeparatorStyle.ThickLine)
  3971. {
  3972. if(horizontal)
  3973. {
  3974. // Draw horizontal line separator
  3975. chartGraph.DrawLineAbs(
  3976. color,
  3977. 2,
  3978. ChartDashStyle.Solid,
  3979. new PointF(rect.Left, rect.Bottom - 1f),
  3980. new PointF(rect.Right, rect.Bottom - 1f) );
  3981. }
  3982. else
  3983. {
  3984. // Draw vertical line separator
  3985. chartGraph.DrawLineAbs(
  3986. color,
  3987. 2,
  3988. ChartDashStyle.Solid,
  3989. new PointF(rect.Right - 1f, rect.Top),
  3990. new PointF(rect.Right - 1f, rect.Bottom) );
  3991. }
  3992. }
  3993. else if(separatorType == LegendSeparatorStyle.DoubleLine)
  3994. {
  3995. if(horizontal)
  3996. {
  3997. // Draw horizontal line separator
  3998. chartGraph.DrawLineAbs(
  3999. color,
  4000. 1,
  4001. ChartDashStyle.Solid,
  4002. new PointF(rect.Left, rect.Bottom - 3),
  4003. new PointF(rect.Right, rect.Bottom - 3) );
  4004. chartGraph.DrawLineAbs(
  4005. color,
  4006. 1,
  4007. ChartDashStyle.Solid,
  4008. new PointF(rect.Left, rect.Bottom - 1),
  4009. new PointF(rect.Right, rect.Bottom - 1) );
  4010. }
  4011. else
  4012. {
  4013. // Draw vertical line separator
  4014. chartGraph.DrawLineAbs(
  4015. color,
  4016. 1,
  4017. ChartDashStyle.Solid,
  4018. new PointF(rect.Right - 3, rect.Top),
  4019. new PointF(rect.Right - 3, rect.Bottom) );
  4020. chartGraph.DrawLineAbs(
  4021. color,
  4022. 1,
  4023. ChartDashStyle.Solid,
  4024. new PointF(rect.Right - 1, rect.Top),
  4025. new PointF(rect.Right - 1, rect.Bottom) );
  4026. }
  4027. }
  4028. else if(separatorType == LegendSeparatorStyle.GradientLine)
  4029. {
  4030. if(horizontal)
  4031. {
  4032. // Draw horizontal line separator
  4033. chartGraph.FillRectangleAbs(
  4034. new RectangleF(rect.Left, rect.Bottom - 1f, rect.Width, 0f),
  4035. Color.Transparent,
  4036. ChartHatchStyle.None,
  4037. string.Empty,
  4038. ChartImageWrapMode.Tile,
  4039. Color.Empty,
  4040. ChartImageAlignmentStyle.Center,
  4041. GradientStyle.VerticalCenter,
  4042. color,
  4043. Color.Empty,
  4044. 0,
  4045. ChartDashStyle.NotSet,
  4046. PenAlignment.Inset);
  4047. }
  4048. else
  4049. {
  4050. // Draw vertical line separator
  4051. chartGraph.FillRectangleAbs(
  4052. new RectangleF(rect.Right - 1f, rect.Top, 0f, rect.Height),
  4053. Color.Transparent,
  4054. ChartHatchStyle.None,
  4055. string.Empty,
  4056. ChartImageWrapMode.Tile,
  4057. Color.Empty,
  4058. ChartImageAlignmentStyle.Center,
  4059. GradientStyle.HorizontalCenter,
  4060. color,
  4061. Color.Empty,
  4062. 0,
  4063. ChartDashStyle.NotSet,
  4064. PenAlignment.Inset);
  4065. }
  4066. }
  4067. else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
  4068. {
  4069. if(horizontal)
  4070. {
  4071. // Draw horizontal line separator
  4072. chartGraph.FillRectangleAbs(
  4073. new RectangleF(rect.Left, rect.Bottom - 2f, rect.Width, 1f),
  4074. Color.Transparent,
  4075. ChartHatchStyle.None,
  4076. string.Empty,
  4077. ChartImageWrapMode.Tile,
  4078. Color.Empty,
  4079. ChartImageAlignmentStyle.Center,
  4080. GradientStyle.VerticalCenter,
  4081. color,
  4082. Color.Empty,
  4083. 0,
  4084. ChartDashStyle.NotSet,
  4085. PenAlignment.Inset);
  4086. }
  4087. else
  4088. {
  4089. // Draw vertical line separator
  4090. chartGraph.FillRectangleAbs(
  4091. new RectangleF(rect.Right - 2f, rect.Top, 1f, rect.Height),
  4092. Color.Transparent,
  4093. ChartHatchStyle.None,
  4094. string.Empty,
  4095. ChartImageWrapMode.Tile,
  4096. Color.Empty,
  4097. ChartImageAlignmentStyle.Center,
  4098. GradientStyle.HorizontalCenter,
  4099. color,
  4100. Color.Empty,
  4101. 0,
  4102. ChartDashStyle.NotSet,
  4103. PenAlignment.Inset);
  4104. }
  4105. }
  4106. // Restore smoothing
  4107. chartGraph.SmoothingMode = oldSmoothingMode;
  4108. }
  4109. #endregion // Legent Title Helper methods
  4110. #region Helper methods
  4111. /// <summary>
  4112. /// Get visible legend border size.
  4113. /// </summary>
  4114. /// <returns>Visible legend border size.</returns>
  4115. private int GetBorderSize()
  4116. {
  4117. if(this.BorderWidth > 0 &&
  4118. this.BorderDashStyle != ChartDashStyle.NotSet &&
  4119. !this.BorderColor.IsEmpty &&
  4120. this.BorderColor != Color.Transparent)
  4121. {
  4122. return this.BorderWidth;
  4123. }
  4124. return 0;
  4125. }
  4126. /// <summary>
  4127. /// Helper method which returns current legend table style.
  4128. /// </summary>
  4129. /// <param name="chartGraph">Chart graphics.</param>
  4130. /// <returns>Legend table style.</returns>
  4131. private LegendTableStyle GetLegendTableStyle(ChartGraphics chartGraph)
  4132. {
  4133. LegendTableStyle style = this.TableStyle;
  4134. if(this.TableStyle == LegendTableStyle.Auto)
  4135. {
  4136. if(this.Position.Auto)
  4137. {
  4138. // If legend is automatically positioned, use docking
  4139. // do determine preffered table style
  4140. if(this.Docking == Docking.Left ||
  4141. this.Docking == Docking.Right)
  4142. {
  4143. return LegendTableStyle.Tall;
  4144. }
  4145. else
  4146. {
  4147. return LegendTableStyle.Wide;
  4148. }
  4149. }
  4150. else
  4151. {
  4152. // If legend is custom positioned, use legend width and heiht
  4153. // to determine the best table layout.
  4154. SizeF legendPixelSize = chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()).Size;
  4155. if(legendPixelSize.Width < legendPixelSize.Height)
  4156. {
  4157. return LegendTableStyle.Tall;
  4158. }
  4159. else
  4160. {
  4161. return LegendTableStyle.Wide;
  4162. }
  4163. }
  4164. }
  4165. return style;
  4166. }
  4167. /// <summary>
  4168. /// Helper method that checks if legend is enabled.
  4169. /// </summary>
  4170. /// <returns>True if legend is enabled.</returns>
  4171. internal bool IsEnabled()
  4172. {
  4173. if(this.Enabled)
  4174. {
  4175. // Check if legend is docked to the chart area
  4176. if(this.DockedToChartArea.Length > 0 &&
  4177. this.Common != null &&
  4178. this.Common.ChartPicture != null)
  4179. {
  4180. if(this.Common.ChartPicture.ChartAreas.IndexOf(this.DockedToChartArea) >= 0)
  4181. {
  4182. // Do not show legend when it is docked to invisible chart area
  4183. ChartArea area = this.Common.ChartPicture.ChartAreas[this.DockedToChartArea];
  4184. if(!area.Visible)
  4185. {
  4186. return false;
  4187. }
  4188. }
  4189. }
  4190. return true;
  4191. }
  4192. return false;
  4193. }
  4194. /// <summary>
  4195. /// Invalidate chart legend when one of the properties is changed
  4196. /// </summary>
  4197. /// <param name="invalidateLegendOnly">Indicates that only legend area should be invalidated.</param>
  4198. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the WinForms version of Chart")]
  4199. internal void Invalidate(bool invalidateLegendOnly)
  4200. {
  4201. if(Chart != null && !Chart.disableInvalidates)
  4202. {
  4203. if(invalidateLegendOnly)
  4204. {
  4205. // Calculate the position of the legend
  4206. Rectangle invalRect = Chart.ClientRectangle;
  4207. if(this.Position.Width != 0 && this.Position.Height != 0 )
  4208. {
  4209. // Convert relative coordinates to absolute coordinates
  4210. invalRect.X = (int)(this.Position.X * (this.Common.ChartPicture.Width - 1) / 100F);
  4211. invalRect.Y = (int)(this.Position.Y * (this.Common.ChartPicture.Height - 1) / 100F);
  4212. invalRect.Width = (int)(this.Position.Width * (this.Common.ChartPicture.Width - 1) / 100F);
  4213. invalRect.Height = (int)(this.Position.Height * (this.Common.ChartPicture.Height - 1) / 100F);
  4214. // Inflate rectangle size using border size and shadow size
  4215. invalRect.Inflate(this.BorderWidth + this.ShadowOffset + 1, this.BorderWidth + this.ShadowOffset + 1);
  4216. }
  4217. // Invalidate legend rectangle only
  4218. Chart.dirtyFlag = true;
  4219. Chart.Invalidate(invalRect);
  4220. }
  4221. else
  4222. {
  4223. Invalidate();
  4224. }
  4225. }
  4226. }
  4227. #endregion
  4228. #region IDisposable Members
  4229. /// <summary>
  4230. /// Releases unmanaged and - optionally - managed resources
  4231. /// </summary>
  4232. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  4233. protected override void Dispose(bool disposing)
  4234. {
  4235. if (disposing)
  4236. {
  4237. //Free managed resources
  4238. if (_fontCache != null)
  4239. {
  4240. _fontCache.Dispose();
  4241. _fontCache = null;
  4242. }
  4243. if (legendItems != null)
  4244. {
  4245. legendItems.Dispose();
  4246. legendItems = null;
  4247. }
  4248. if (_cellColumns != null)
  4249. {
  4250. _cellColumns.Dispose();
  4251. _cellColumns = null;
  4252. }
  4253. if (_customLegends != null)
  4254. {
  4255. _customLegends.Dispose();
  4256. _customLegends = null;
  4257. }
  4258. if (_position != null)
  4259. {
  4260. _position.Dispose();
  4261. _position = null;
  4262. }
  4263. }
  4264. }
  4265. #endregion
  4266. }
  4267. /// <summary>
  4268. /// The LegendCollection class is a strongly typed collection of legends.
  4269. /// </summary>
  4270. [
  4271. SRDescription("DescriptionAttributeLegendCollection_LegendCollection"),
  4272. ]
  4273. public class LegendCollection : ChartNamedElementCollection<Legend>
  4274. {
  4275. #region Constructors
  4276. /// <summary>
  4277. /// LegendCollection constructor.
  4278. /// </summary>
  4279. /// <param name="chartPicture">Chart picture object.</param>
  4280. internal LegendCollection(ChartPicture chartPicture)
  4281. : base(chartPicture)
  4282. {
  4283. }
  4284. #endregion
  4285. #region Properties
  4286. /// <summary>
  4287. /// Gets the default legend name.
  4288. /// </summary>
  4289. internal string DefaultNameReference
  4290. {
  4291. get { return this.Count > 0 ? this[0].Name : String.Empty; }
  4292. }
  4293. #endregion
  4294. #region Methods
  4295. /// <summary>
  4296. /// Creates a new Legend with the specified name and adds it to the collection.
  4297. /// </summary>
  4298. /// <param name="name">The new chart area name.</param>
  4299. /// <returns>New legend</returns>
  4300. public Legend Add(string name)
  4301. {
  4302. Legend legend = new Legend(name);
  4303. this.Add(legend);
  4304. return legend;
  4305. }
  4306. /// <summary>
  4307. /// Recalculates legend position in the collection.
  4308. /// </summary>
  4309. /// <param name="chartGraph">Chart graphics used.</param>
  4310. /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
  4311. /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
  4312. internal void CalcLegendPosition(
  4313. ChartGraphics chartGraph,
  4314. ref RectangleF chartAreasRectangle,
  4315. float elementSpacing)
  4316. {
  4317. // Loop through all legends
  4318. foreach(Legend legend in this)
  4319. {
  4320. // Calculate position of the legends docked to the chart picture
  4321. if(legend.IsEnabled() &&
  4322. legend.DockedToChartArea == Constants.NotSetValue &&
  4323. legend.Position.Auto)
  4324. {
  4325. legend.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
  4326. }
  4327. }
  4328. }
  4329. /// <summary>
  4330. /// Recalculates legend position in the collection for legends docked outside of chart area.
  4331. /// </summary>
  4332. /// <param name="chartGraph">Chart graphics used.</param>
  4333. /// <param name="area">Area the legend is docked to.</param>
  4334. /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
  4335. /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
  4336. internal void CalcOutsideLegendPosition(
  4337. ChartGraphics chartGraph,
  4338. ChartArea area,
  4339. ref RectangleF chartAreasRectangle,
  4340. float elementSpacing)
  4341. {
  4342. if(Common != null && Common.ChartPicture != null)
  4343. {
  4344. // Get elemets spacing
  4345. float areaSpacing = Math.Min((chartAreasRectangle.Height/100F) * elementSpacing, (chartAreasRectangle.Width/100F) * elementSpacing);
  4346. // Loop through all legends
  4347. foreach(Legend legend in this)
  4348. {
  4349. // Check if all chart area names are valid
  4350. if (legend.DockedToChartArea != Constants.NotSetValue && this.Chart.ChartAreas.IndexOf(legend.DockedToChartArea)<0)
  4351. {
  4352. throw (new ArgumentException(SR.ExceptionLegendDockedChartAreaIsMissing((string)legend.DockedToChartArea)));
  4353. }
  4354. // Process only legends docked to specified area
  4355. if(legend.IsEnabled() &&
  4356. legend.IsDockedInsideChartArea == false &&
  4357. legend.DockedToChartArea == area.Name &&
  4358. legend.Position.Auto)
  4359. {
  4360. // Calculate legend position
  4361. legend.CalcLegendPosition(chartGraph,
  4362. ref chartAreasRectangle,
  4363. areaSpacing);
  4364. // Adjust legend position
  4365. RectangleF legendPosition = legend.Position.ToRectangleF();
  4366. if(legend.Docking == Docking.Top)
  4367. {
  4368. legendPosition.Y -= areaSpacing;
  4369. if(!area.Position.Auto)
  4370. {
  4371. legendPosition.Y -= legendPosition.Height;
  4372. }
  4373. }
  4374. else if(legend.Docking == Docking.Bottom)
  4375. {
  4376. legendPosition.Y += areaSpacing;
  4377. if(!area.Position.Auto)
  4378. {
  4379. legendPosition.Y = area.Position.Bottom + areaSpacing;
  4380. }
  4381. }
  4382. if(legend.Docking == Docking.Left)
  4383. {
  4384. legendPosition.X -= areaSpacing;
  4385. if(!area.Position.Auto)
  4386. {
  4387. legendPosition.X -= legendPosition.Width;
  4388. }
  4389. }
  4390. if(legend.Docking == Docking.Right)
  4391. {
  4392. legendPosition.X += areaSpacing;
  4393. if(!area.Position.Auto)
  4394. {
  4395. legendPosition.X = area.Position.Right + areaSpacing;
  4396. }
  4397. }
  4398. legend.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
  4399. }
  4400. }
  4401. }
  4402. }
  4403. /// <summary>
  4404. /// Recalculates legend position inside chart area in the collection.
  4405. /// </summary>
  4406. /// <param name="chartGraph">Chart graphics used.</param>
  4407. /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
  4408. internal void CalcInsideLegendPosition(
  4409. ChartGraphics chartGraph,
  4410. float elementSpacing)
  4411. {
  4412. if(Common != null && Common.ChartPicture != null)
  4413. {
  4414. // Check if all chart area names are valid
  4415. foreach(Legend legend in this)
  4416. {
  4417. if (legend.DockedToChartArea != Constants.NotSetValue)
  4418. {
  4419. try
  4420. {
  4421. ChartArea area = Common.ChartPicture.ChartAreas[legend.DockedToChartArea];
  4422. }
  4423. catch
  4424. {
  4425. throw(new ArgumentException( SR.ExceptionLegendDockedChartAreaIsMissing( (string)legend.DockedToChartArea ) ) );
  4426. }
  4427. }
  4428. }
  4429. // Loop through all chart areas
  4430. foreach (ChartArea area in Common.ChartPicture.ChartAreas)
  4431. {
  4432. // Check if chart area is visible
  4433. if(area.Visible)
  4434. {
  4435. // Get area position
  4436. RectangleF legendPlottingRectangle = area.PlotAreaPosition.ToRectangleF();
  4437. // Get elemets spacing
  4438. float areaSpacing = Math.Min((legendPlottingRectangle.Height/100F) * elementSpacing, (legendPlottingRectangle.Width/100F) * elementSpacing);
  4439. // Loop through all legends
  4440. foreach(Legend legend in this)
  4441. {
  4442. if(legend.IsEnabled() &&
  4443. legend.IsDockedInsideChartArea == true &&
  4444. legend.DockedToChartArea == area.Name &&
  4445. legend.Position.Auto)
  4446. {
  4447. // Calculate legend position
  4448. legend.CalcLegendPosition(chartGraph,
  4449. ref legendPlottingRectangle,
  4450. areaSpacing);
  4451. }
  4452. }
  4453. }
  4454. }
  4455. }
  4456. }
  4457. #endregion
  4458. #region Event handlers
  4459. internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
  4460. {
  4461. //If all the chart areas are removed and then the first one is added we don't want to dock the legends
  4462. if (e.OldElement == null)
  4463. return;
  4464. foreach (Legend legend in this)
  4465. if (legend.DockedToChartArea == e.OldName)
  4466. legend.DockedToChartArea = e.NewName;
  4467. }
  4468. #endregion
  4469. }
  4470. /// <summary>
  4471. /// The LegendItemsCollection class is a strongly typed collection of legend items.
  4472. /// </summary>
  4473. [
  4474. SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
  4475. ]
  4476. public class LegendItemsCollection : ChartElementCollection<LegendItem>
  4477. {
  4478. #region Constructors
  4479. /// <summary>
  4480. /// LegendItemsCollection constructor
  4481. /// </summary>
  4482. internal LegendItemsCollection(Legend legend)
  4483. : base(legend)
  4484. {
  4485. }
  4486. #endregion
  4487. #region Methods
  4488. /// <summary>
  4489. /// Adds a legend item into the collection.
  4490. /// </summary>
  4491. /// <param name="color">Legend item color.</param>
  4492. /// <param name="text">Legend item text.</param>
  4493. /// <returns>Index of newly added item.</returns>
  4494. public int Add(Color color, string text)
  4495. {
  4496. LegendItem item = new LegendItem(text, color, "");
  4497. Add(item);
  4498. return Count - 1;
  4499. }
  4500. /// <summary>
  4501. /// Insert a legend item into the collection.
  4502. /// </summary>
  4503. /// <param name="index">Index to insert at.</param>
  4504. /// <param name="color">Legend item color.</param>
  4505. /// <param name="text">Legend item text.</param>
  4506. /// <returns>Index of newly added item.</returns>
  4507. public void Insert(int index, Color color, string text)
  4508. {
  4509. LegendItem item = new LegendItem(text, color, "");
  4510. this.Insert(index, item);
  4511. }
  4512. /// <summary>
  4513. /// Adds a legend item into the collection.
  4514. /// </summary>
  4515. /// <param name="image">Legend item image.</param>
  4516. /// <param name="text">Legend item text.</param>
  4517. /// <returns>Index of newly added item.</returns>
  4518. public int Add(string image, string text)
  4519. {
  4520. LegendItem item = new LegendItem(text, Color.Empty, image);
  4521. Add(item);
  4522. return Count-1;
  4523. }
  4524. /// <summary>
  4525. /// Insert one legend item into the collection.
  4526. /// </summary>
  4527. /// <param name="index">Index to insert at.</param>
  4528. /// <param name="image">Legend item image.</param>
  4529. /// <param name="text">Legend item text.</param>
  4530. /// <returns>Index of newly added item.</returns>
  4531. public void Insert(int index, string image, string text)
  4532. {
  4533. LegendItem item = new LegendItem(text, Color.Empty, image);
  4534. this.Insert(index, item);
  4535. }
  4536. /// <summary>
  4537. /// Reverses the order of items in the collection.
  4538. /// </summary>
  4539. public void Reverse()
  4540. {
  4541. List<LegendItem> list = this.Items as List<LegendItem>;
  4542. list.Reverse();
  4543. Invalidate();
  4544. }
  4545. #endregion
  4546. }
  4547. /// <summary>
  4548. /// The LegendItem class represents a single item (row) in the legend.
  4549. /// It contains properties which describe visual appearance and
  4550. /// content of the legend item.
  4551. /// </summary>
  4552. [
  4553. SRDescription("DescriptionAttributeLegendItem_LegendItem"),
  4554. DefaultProperty("Name")
  4555. ]
  4556. public class LegendItem : ChartNamedElement
  4557. {
  4558. #region Fields
  4559. // Private data members, which store properties values
  4560. private Color _color = Color.Empty;
  4561. private string _image = "";
  4562. private string _seriesName = "";
  4563. private int _seriesPointIndex = -1;
  4564. // Chart image map properties
  4565. private string _toolTip = "";
  4566. // Additional appearance properties
  4567. internal LegendImageStyle style = LegendImageStyle.Rectangle;
  4568. internal GradientStyle backGradientStyle = GradientStyle.None;
  4569. internal Color backSecondaryColor = Color.Empty;
  4570. internal Color backImageTransparentColor = Color.Empty;
  4571. internal Color borderColor = Color.Black;
  4572. internal int borderWidth = 1;
  4573. internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid;
  4574. internal ChartHatchStyle backHatchStyle = ChartHatchStyle.None;
  4575. internal int shadowOffset = 0;
  4576. internal Color shadowColor = Color.FromArgb(128, 0, 0, 0);
  4577. internal ChartImageWrapMode backImageWrapMode = ChartImageWrapMode.Tile;
  4578. internal ChartImageAlignmentStyle backImageAlign = ChartImageAlignmentStyle.TopLeft;
  4579. // Marker properties
  4580. internal MarkerStyle markerStyle = MarkerStyle.None;
  4581. internal int markerSize = 5;
  4582. internal string markerImage = "";
  4583. internal Color markerImageTransparentColor = Color.Empty;
  4584. internal Color markerColor = Color.Empty;
  4585. internal Color markerBorderColor = Color.Empty;
  4586. // True if legend item is enabled.
  4587. private bool _enabled = true;
  4588. // Series marker border width
  4589. private int _markerBorderWidth = 1;
  4590. // Collection of legend item cells
  4591. private LegendCellCollection _cells = null;
  4592. // Legend item visual separator
  4593. private LegendSeparatorStyle _separatorType = LegendSeparatorStyle.None;
  4594. // Legend item visual separator color
  4595. private Color _separatorColor = Color.Black;
  4596. // Indicates that temporary cells where added and thet have to be removed
  4597. internal bool clearTempCells = false;
  4598. #endregion
  4599. #region Constructors
  4600. /// <summary>
  4601. /// LegendItem constructor
  4602. /// </summary>
  4603. public LegendItem()
  4604. {
  4605. // Create collection of legend item cells
  4606. this._cells = new LegendCellCollection(this);
  4607. }
  4608. /// <summary>
  4609. /// LegendItem constructor
  4610. /// </summary>
  4611. /// <param name="name">Item name.</param>
  4612. /// <param name="color">Item color.</param>
  4613. /// <param name="image">Item image.</param>
  4614. public LegendItem(string name, Color color, string image) : base (name)
  4615. {
  4616. this._color = color;
  4617. this._image = image;
  4618. // Create collection of legend item cells
  4619. this._cells = new LegendCellCollection(this);
  4620. }
  4621. #endregion
  4622. #region Legend item properties
  4623. /// <summary>
  4624. /// Gets the Legend object which the item belongs to.
  4625. /// </summary>
  4626. [
  4627. Bindable(false),
  4628. Browsable(false),
  4629. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  4630. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  4631. ]
  4632. public Legend Legend
  4633. {
  4634. get
  4635. {
  4636. if (Parent != null)
  4637. return Parent.Parent as Legend;
  4638. else
  4639. return null;
  4640. }
  4641. }
  4642. /// <summary>
  4643. /// Gets or sets the name of the legend item.
  4644. /// </summary>
  4645. [
  4646. SRCategory("CategoryAttributeAppearance"),
  4647. Bindable(true),
  4648. SRDescription("DescriptionAttributeLegendItem_Name"),
  4649. NotifyParentPropertyAttribute(true),
  4650. ParenthesizePropertyNameAttribute(true)
  4651. ]
  4652. public override string Name
  4653. {
  4654. get
  4655. {
  4656. return base.Name;
  4657. }
  4658. set
  4659. {
  4660. base.Name = value;
  4661. CallOnModifing();
  4662. }
  4663. }
  4664. /// <summary>
  4665. /// Gets or sets the color of the legend item.
  4666. /// </summary>
  4667. [
  4668. SRCategory("CategoryAttributeAppearance"),
  4669. Bindable(true),
  4670. SRDescription("DescriptionAttributeLegendItem_Color"),
  4671. DefaultValue(typeof(Color), ""),
  4672. NotifyParentPropertyAttribute(true),
  4673. TypeConverter(typeof(ColorConverter)),
  4674. #if DESIGNER
  4675. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  4676. #endif
  4677. ]
  4678. public Color Color
  4679. {
  4680. get
  4681. {
  4682. return _color;
  4683. }
  4684. set
  4685. {
  4686. _color = value;
  4687. this.Invalidate(true);
  4688. CallOnModifing();
  4689. }
  4690. }
  4691. /// <summary>
  4692. /// Gets or sets a string value that represents a URL to an image file, which will be used for the legend item's symbol.
  4693. /// </summary>
  4694. [
  4695. SRCategory("CategoryAttributeAppearance"),
  4696. Bindable(true),
  4697. SRDescription("DescriptionAttributeLegendItem_Image"),
  4698. DefaultValue(""),
  4699. #if DESIGNER
  4700. Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
  4701. #endif
  4702. NotifyParentPropertyAttribute(true)
  4703. ]
  4704. public string Image
  4705. {
  4706. get
  4707. {
  4708. return _image;
  4709. }
  4710. set
  4711. {
  4712. _image = value;
  4713. this.Invalidate(false);
  4714. CallOnModifing();
  4715. }
  4716. }
  4717. /// <summary>
  4718. /// Gets or sets the picture style of the legend item image.
  4719. /// </summary>
  4720. [
  4721. SRCategory("CategoryAttributeAppearance"),
  4722. Bindable(true),
  4723. DefaultValue(typeof(LegendImageStyle), "Rectangle"),
  4724. SRDescription("DescriptionAttributeLegendItem_Style"),
  4725. ParenthesizePropertyNameAttribute(true)
  4726. ]
  4727. public LegendImageStyle ImageStyle
  4728. {
  4729. get
  4730. {
  4731. return style;
  4732. }
  4733. set
  4734. {
  4735. style = value;
  4736. this.Invalidate(true);
  4737. CallOnModifing();
  4738. }
  4739. }
  4740. /// <summary>
  4741. /// Gets or sets the border color of the legend item.
  4742. /// </summary>
  4743. [
  4744. SRCategory("CategoryAttributeAppearance"),
  4745. Bindable(true),
  4746. DefaultValue(typeof(Color), "Black"),
  4747. SRDescription("DescriptionAttributeBorderColor"),
  4748. TypeConverter(typeof(ColorConverter)),
  4749. #if DESIGNER
  4750. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  4751. #endif
  4752. ]
  4753. public Color BorderColor
  4754. {
  4755. get
  4756. {
  4757. return borderColor;
  4758. }
  4759. set
  4760. {
  4761. borderColor = value;
  4762. this.Invalidate(true);
  4763. CallOnModifing();
  4764. }
  4765. }
  4766. /// <summary>
  4767. /// Gets or sets the background hatch style of the legend item.
  4768. /// </summary>
  4769. [
  4770. SRCategory("CategoryAttributeAppearance"),
  4771. Bindable(true),
  4772. DefaultValue(ChartHatchStyle.None),
  4773. SRDescription("DescriptionAttributeBackHatchStyle"),
  4774. #if DESIGNER
  4775. Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
  4776. #endif
  4777. ]
  4778. public ChartHatchStyle BackHatchStyle
  4779. {
  4780. get
  4781. {
  4782. return backHatchStyle;
  4783. }
  4784. set
  4785. {
  4786. backHatchStyle = value;
  4787. this.Invalidate(true);
  4788. CallOnModifing();
  4789. }
  4790. }
  4791. /// <summary>
  4792. /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
  4793. /// </summary>
  4794. [
  4795. SRCategory("CategoryAttributeAppearance"),
  4796. Bindable(true),
  4797. DefaultValue(typeof(Color), ""),
  4798. NotifyParentPropertyAttribute(true),
  4799. SRDescription("DescriptionAttributeImageTransparentColor"),
  4800. TypeConverter(typeof(ColorConverter)),
  4801. #if DESIGNER
  4802. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  4803. #endif
  4804. ]
  4805. public Color BackImageTransparentColor
  4806. {
  4807. get
  4808. {
  4809. return backImageTransparentColor;
  4810. }
  4811. set
  4812. {
  4813. backImageTransparentColor = value;
  4814. this.Invalidate(true);
  4815. CallOnModifing();
  4816. }
  4817. }
  4818. /// <summary>
  4819. /// Gets or sets background gradient style of the legend item.
  4820. /// </summary>
  4821. [
  4822. SRCategory("CategoryAttributeAppearance"),
  4823. Bindable(true),
  4824. DefaultValue(GradientStyle.None),
  4825. SRDescription("DescriptionAttributeBackGradientStyle"),
  4826. #if DESIGNER
  4827. Editor(typeof(GradientEditor), typeof(UITypeEditor))
  4828. #endif
  4829. ]
  4830. public GradientStyle BackGradientStyle
  4831. {
  4832. get
  4833. {
  4834. return backGradientStyle;
  4835. }
  4836. set
  4837. {
  4838. backGradientStyle = value;
  4839. this.Invalidate(true);
  4840. CallOnModifing();
  4841. }
  4842. }
  4843. /// <summary>
  4844. /// Gets or sets the secondary background color.
  4845. /// <seealso cref="Color"/>
  4846. /// <seealso cref="BackHatchStyle"/>
  4847. /// <seealso cref="BackGradientStyle"/>
  4848. /// </summary>
  4849. /// <value>
  4850. /// A <see cref="Color"/> value used for the secondary color of background with
  4851. /// hatching or gradient fill.
  4852. /// </value>
  4853. /// <remarks>
  4854. /// This color is used with <see cref="Color"/> when <see cref="BackHatchStyle"/> or
  4855. /// <see cref="BackGradientStyle"/> are used.
  4856. /// </remarks>
  4857. [
  4858. SRCategory("CategoryAttributeAppearance"),
  4859. Bindable(true),
  4860. DefaultValue(typeof(Color), ""),
  4861. SRDescription("DescriptionAttributeBackSecondaryColor"),
  4862. TypeConverter(typeof(ColorConverter)),
  4863. #if DESIGNER
  4864. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  4865. #endif
  4866. ]
  4867. public Color BackSecondaryColor
  4868. {
  4869. get
  4870. {
  4871. return backSecondaryColor;
  4872. }
  4873. set
  4874. {
  4875. if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
  4876. {
  4877. throw (new ArgumentException(SR.ExceptionBackSecondaryColorIsTransparent));
  4878. }
  4879. backSecondaryColor = value;
  4880. this.Invalidate(true);
  4881. CallOnModifing();
  4882. }
  4883. }
  4884. /// <summary>
  4885. /// Gets or sets the border width of the legend item.
  4886. /// </summary>
  4887. [
  4888. SRCategory("CategoryAttributeAppearance"),
  4889. Bindable(true),
  4890. DefaultValue(1),
  4891. SRDescription("DescriptionAttributeBorderWidth"),
  4892. ]
  4893. public int BorderWidth
  4894. {
  4895. get
  4896. {
  4897. return borderWidth;
  4898. }
  4899. set
  4900. {
  4901. if(value < 0)
  4902. {
  4903. throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsZero));
  4904. }
  4905. borderWidth = value;
  4906. this.Invalidate(false);
  4907. CallOnModifing();
  4908. }
  4909. }
  4910. /// <summary>
  4911. /// Gets or sets a flag which indicates whether the Legend item is enabled.
  4912. /// </summary>
  4913. [
  4914. SRCategory("CategoryAttributeAppearance"),
  4915. DefaultValue(true),
  4916. SRDescription("DescriptionAttributeLegendItem_Enabled"),
  4917. ParenthesizePropertyNameAttribute(true),
  4918. ]
  4919. public bool Enabled
  4920. {
  4921. get
  4922. {
  4923. return this._enabled;
  4924. }
  4925. set
  4926. {
  4927. this._enabled = value;
  4928. this.Invalidate(false);
  4929. CallOnModifing();
  4930. }
  4931. }
  4932. /// <summary>
  4933. /// Gets or sets the marker border width of the legend item.
  4934. /// </summary>
  4935. [
  4936. SRCategory("CategoryAttributeMarker"),
  4937. DefaultValue(1),
  4938. SRDescription("DescriptionAttributeMarkerBorderWidth"),
  4939. ]
  4940. public int MarkerBorderWidth
  4941. {
  4942. get
  4943. {
  4944. return this._markerBorderWidth;
  4945. }
  4946. set
  4947. {
  4948. if(value < 0)
  4949. {
  4950. throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMarkerBorderWidthIsNegative));
  4951. }
  4952. this._markerBorderWidth = value;
  4953. this.Invalidate(false);
  4954. CallOnModifing();
  4955. }
  4956. }
  4957. /// <summary>
  4958. /// Gets or sets the legend item border style.
  4959. /// </summary>
  4960. [
  4961. SRCategory("CategoryAttributeAppearance"),
  4962. Bindable(true),
  4963. DefaultValue(ChartDashStyle.Solid),
  4964. SRDescription("DescriptionAttributeBorderDashStyle"),
  4965. ]
  4966. public ChartDashStyle BorderDashStyle
  4967. {
  4968. get
  4969. {
  4970. return borderDashStyle;
  4971. }
  4972. set
  4973. {
  4974. borderDashStyle = value;
  4975. this.Invalidate(true);
  4976. CallOnModifing();
  4977. }
  4978. }
  4979. /// <summary>
  4980. /// Gets or sets the offset between the legend item and its shadow.
  4981. /// <seealso cref="ShadowColor"/>
  4982. /// </summary>
  4983. /// <value>
  4984. /// An integer value that represents the offset between the legend item and its shadow.
  4985. /// </value>
  4986. [
  4987. SRCategory("CategoryAttributeAppearance"),
  4988. Bindable(true),
  4989. SRDescription("DescriptionAttributeShadowOffset"),
  4990. DefaultValue(0)
  4991. ]
  4992. public int ShadowOffset
  4993. {
  4994. get
  4995. {
  4996. return shadowOffset;
  4997. }
  4998. set
  4999. {
  5000. shadowOffset = value;
  5001. this.Invalidate(false);
  5002. CallOnModifing();
  5003. }
  5004. }
  5005. /// <summary>
  5006. /// Gets or sets the color of a legend item's shadow.
  5007. /// <seealso cref="ShadowOffset"/>
  5008. /// </summary>
  5009. /// <value>
  5010. /// A <see cref="Color"/> value used to draw a legend item's shadow.
  5011. /// </value>
  5012. [
  5013. SRCategory("CategoryAttributeAppearance"),
  5014. Bindable(true),
  5015. DefaultValue(typeof(Color), "128,0,0,0"),
  5016. SRDescription("DescriptionAttributeShadowColor"),
  5017. TypeConverter(typeof(ColorConverter)),
  5018. #if DESIGNER
  5019. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  5020. #endif
  5021. ]
  5022. public Color ShadowColor
  5023. {
  5024. get
  5025. {
  5026. return shadowColor;
  5027. }
  5028. set
  5029. {
  5030. shadowColor = value;
  5031. this.Invalidate(true);
  5032. CallOnModifing();
  5033. }
  5034. }
  5035. /// <summary>
  5036. /// Gets or sets the marker style of the legend item.
  5037. /// </summary>
  5038. [
  5039. SRCategory("CategoryAttributeMarker"),
  5040. Bindable(true),
  5041. DefaultValue(MarkerStyle.None),
  5042. SRDescription("DescriptionAttributeLegendItem_MarkerStyle"),
  5043. #if DESIGNER
  5044. Editor(typeof(MarkerStyleEditor), typeof(UITypeEditor)),
  5045. #endif
  5046. RefreshProperties(RefreshProperties.All)
  5047. ]
  5048. public MarkerStyle MarkerStyle
  5049. {
  5050. get
  5051. {
  5052. return markerStyle;
  5053. }
  5054. set
  5055. {
  5056. markerStyle = value;
  5057. this.Invalidate(true);
  5058. CallOnModifing();
  5059. }
  5060. }
  5061. /// <summary>
  5062. /// Gets or sets the marker size of the legend item.
  5063. /// </summary>
  5064. [
  5065. SRCategory("CategoryAttributeMarker"),
  5066. Bindable(true),
  5067. DefaultValue(5),
  5068. SRDescription("DescriptionAttributeLegendItem_MarkerSize"),
  5069. RefreshProperties(RefreshProperties.All)
  5070. ]
  5071. public int MarkerSize
  5072. {
  5073. get
  5074. {
  5075. return markerSize;
  5076. }
  5077. set
  5078. {
  5079. markerSize = value;
  5080. this.Invalidate(false);
  5081. CallOnModifing();
  5082. }
  5083. }
  5084. /// <summary>
  5085. /// Gets or sets the marker image of the legend item.
  5086. /// </summary>
  5087. [
  5088. SRCategory("CategoryAttributeMarker"),
  5089. Bindable(true),
  5090. DefaultValue(""),
  5091. SRDescription("DescriptionAttributeMarkerImage"),
  5092. #if DESIGNER
  5093. Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
  5094. #endif
  5095. RefreshProperties(RefreshProperties.All)
  5096. ]
  5097. public string MarkerImage
  5098. {
  5099. get
  5100. {
  5101. return markerImage;
  5102. }
  5103. set
  5104. {
  5105. markerImage = value;
  5106. this.Invalidate(true);
  5107. CallOnModifing();
  5108. }
  5109. }
  5110. /// <summary>
  5111. /// Gets or sets a color which will be replaced with a transparent color while drawing the marker image.
  5112. /// </summary>
  5113. [
  5114. SRCategory("CategoryAttributeMarker"),
  5115. Bindable(true),
  5116. DefaultValue(typeof(Color), ""),
  5117. SRDescription("DescriptionAttributeImageTransparentColor"),
  5118. TypeConverter(typeof(ColorConverter)),
  5119. #if DESIGNER
  5120. Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
  5121. #endif
  5122. RefreshProperties(RefreshProperties.All)
  5123. ]
  5124. public Color MarkerImageTransparentColor
  5125. {
  5126. get
  5127. {
  5128. return markerImageTransparentColor;
  5129. }
  5130. set
  5131. {
  5132. markerImageTransparentColor = value;
  5133. this.Invalidate(true);
  5134. CallOnModifing();
  5135. }
  5136. }
  5137. /// <summary>
  5138. /// Gets or sets the marker color of the legend item.
  5139. /// </summary>
  5140. [
  5141. SRCategory("CategoryAttributeMarker"),
  5142. Bindable(true),
  5143. DefaultValue(typeof(Color), ""),
  5144. SRDescription("DescriptionAttributeLegendItem_MarkerColor"),
  5145. TypeConverter(typeof(ColorConverter)),
  5146. #if DESIGNER
  5147. Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
  5148. #endif
  5149. RefreshProperties(RefreshProperties.All)
  5150. ]
  5151. public Color MarkerColor
  5152. {
  5153. get
  5154. {
  5155. return markerColor;
  5156. }
  5157. set
  5158. {
  5159. markerColor = value;
  5160. this.Invalidate(true);
  5161. CallOnModifing();
  5162. }
  5163. }
  5164. /// <summary>
  5165. /// Gets or sets the marker border color of the legend item.
  5166. /// </summary>
  5167. [
  5168. SRCategory("CategoryAttributeMarker"),
  5169. Bindable(true),
  5170. DefaultValue(typeof(Color), ""),
  5171. SRDescription("DescriptionAttributeMarkerBorderColor"),
  5172. TypeConverter(typeof(ColorConverter)),
  5173. #if DESIGNER
  5174. Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
  5175. #endif
  5176. RefreshProperties(RefreshProperties.All)
  5177. ]
  5178. public Color MarkerBorderColor
  5179. {
  5180. get
  5181. {
  5182. return markerBorderColor;
  5183. }
  5184. set
  5185. {
  5186. markerBorderColor = value;
  5187. this.Invalidate(true);
  5188. CallOnModifing();
  5189. }
  5190. }
  5191. /// <summary>
  5192. /// Gets or sets the series name of the legend item..
  5193. /// </summary>
  5194. [
  5195. Browsable(false),
  5196. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  5197. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  5198. SRDescription("DescriptionAttributeLegendItem_SeriesName"),
  5199. DefaultValue("")
  5200. ]
  5201. public string SeriesName
  5202. {
  5203. get
  5204. {
  5205. return _seriesName;
  5206. }
  5207. set
  5208. {
  5209. _seriesName = value;
  5210. }
  5211. }
  5212. /// <summary>
  5213. /// Gets or sets the index of the legend item's associated DataPoint object.
  5214. /// </summary>
  5215. [
  5216. Browsable(false),
  5217. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  5218. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  5219. SRDescription("DescriptionAttributeLegendItem_SeriesPointIndex"),
  5220. DefaultValue(-1)
  5221. ]
  5222. public int SeriesPointIndex
  5223. {
  5224. get
  5225. {
  5226. return _seriesPointIndex;
  5227. }
  5228. set
  5229. {
  5230. _seriesPointIndex = value;
  5231. }
  5232. }
  5233. /// <summary>
  5234. /// Gets or sets the separator style of the legend item.
  5235. /// </summary>
  5236. [
  5237. SRCategory("CategoryAttributeAppearance"),
  5238. DefaultValue(typeof(LegendSeparatorStyle), "None"),
  5239. SRDescription("DescriptionAttributeLegendItem_Separator"),
  5240. ]
  5241. public LegendSeparatorStyle SeparatorType
  5242. {
  5243. get
  5244. {
  5245. return this._separatorType;
  5246. }
  5247. set
  5248. {
  5249. if(value != this._separatorType)
  5250. {
  5251. this._separatorType = value;
  5252. this.Invalidate(false);
  5253. CallOnModifing();
  5254. }
  5255. }
  5256. }
  5257. /// <summary>
  5258. /// Gets or sets the separator color of the legend item.
  5259. /// </summary>
  5260. [
  5261. SRCategory("CategoryAttributeAppearance"),
  5262. DefaultValue(typeof(Color), "Black"),
  5263. SRDescription("DescriptionAttributeLegendItem_SeparatorColor"),
  5264. TypeConverter(typeof(ColorConverter)),
  5265. #if DESIGNER
  5266. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  5267. #endif
  5268. ]
  5269. public Color SeparatorColor
  5270. {
  5271. get
  5272. {
  5273. return this._separatorColor;
  5274. }
  5275. set
  5276. {
  5277. if(value != this._separatorColor)
  5278. {
  5279. this._separatorColor = value;
  5280. this.Invalidate(false);
  5281. CallOnModifing();
  5282. }
  5283. }
  5284. }
  5285. /// <summary>
  5286. /// The LegendCellCollection class is a collection of legend item cells.
  5287. /// </summary>
  5288. [
  5289. SRCategory("CategoryAttributeAppearance"),
  5290. SRDescription("DescriptionAttributeLegendItem_Cells"),
  5291. DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  5292. #if DESIGNER
  5293. Editor(typeof(LegendCollectionEditor), typeof(UITypeEditor))
  5294. #endif
  5295. ]
  5296. public LegendCellCollection Cells
  5297. {
  5298. get
  5299. {
  5300. return this._cells;
  5301. }
  5302. }
  5303. #endregion
  5304. #region IMapAreaAttributesutes Properties implementation
  5305. /// <summary>
  5306. /// Tooltip of the area.
  5307. /// </summary>
  5308. [
  5309. SRCategory("CategoryAttributeMapArea"),
  5310. Bindable(true),
  5311. SRDescription("DescriptionAttributeToolTip"),
  5312. DefaultValue("")
  5313. ]
  5314. public string ToolTip
  5315. {
  5316. set
  5317. {
  5318. _toolTip = value;
  5319. if(Chart != null && Chart.selection != null)
  5320. {
  5321. Chart.selection.enabledChecked = false;
  5322. }
  5323. }
  5324. get
  5325. {
  5326. return _toolTip;
  5327. }
  5328. }
  5329. #endregion
  5330. #region Helper methods
  5331. /// <summary>
  5332. /// Helper method adds default legend item cells based on the columns
  5333. /// specified. If columns collection is empty we assume the presence of
  5334. /// two columns: series marker and legend item text.
  5335. /// </summary>
  5336. /// <param name="legend">Legend this item belongs to.</param>
  5337. internal void AddAutomaticCells(Legend legend)
  5338. {
  5339. // Check if cells defined
  5340. if(this.Cells.Count == 0)
  5341. {
  5342. // Check if legend item was generated for the series
  5343. if(this.SeriesName.Length > 0)
  5344. {
  5345. // If legend do not have any columns set add a series marker
  5346. // and legend text cells
  5347. if(legend.CellColumns.Count == 0)
  5348. {
  5349. // VSTS 96787 - Text Direction (RTL/LTR)
  5350. if (legend.Common != null && legend.Common.ChartPicture.RightToLeft == RightToLeft.Yes)
  5351. {
  5352. this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
  5353. this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
  5354. }
  5355. else
  5356. {
  5357. this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
  5358. this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
  5359. }
  5360. }
  5361. else
  5362. {
  5363. // Add cell for each of the columns
  5364. foreach(LegendCellColumn legendColumn in legend.CellColumns)
  5365. {
  5366. this.Cells.Add(legendColumn.CreateNewCell());
  5367. }
  5368. }
  5369. }
  5370. else
  5371. {
  5372. // Add Marker plus text for everything else
  5373. this.clearTempCells = true;
  5374. this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
  5375. this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
  5376. }
  5377. }
  5378. }
  5379. /// <summary>
  5380. /// Sets legend item properties from the series
  5381. /// </summary>
  5382. /// <param name="series">Series object.</param>
  5383. /// <param name="common">Common elements object.</param>
  5384. internal void SetAttributes(CommonElements common, Series series)
  5385. {
  5386. // Get legend item picture style
  5387. IChartType chartType = common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
  5388. style = chartType.GetLegendImageStyle(series);
  5389. // Set series name
  5390. _seriesName = series.Name;
  5391. // Get shadow properties
  5392. shadowOffset = series.ShadowOffset;
  5393. shadowColor = series.ShadowColor;
  5394. // Check if series is drawn in 3D chart area
  5395. bool area3D = common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
  5396. // Get other properties
  5397. SetAttributes((DataPointCustomProperties) series, area3D);
  5398. }
  5399. /// <summary>
  5400. /// Sets legend item properties from the DataPointCustomProperties object.
  5401. /// </summary>
  5402. /// <param name="properties">DataPointCustomProperties object.</param>
  5403. /// <param name="area3D">Element belongs to the 3D area.</param>
  5404. internal void SetAttributes(DataPointCustomProperties properties, bool area3D)
  5405. {
  5406. borderColor = properties.BorderColor;
  5407. borderWidth = properties.BorderWidth;
  5408. borderDashStyle = properties.BorderDashStyle;
  5409. markerStyle = properties.MarkerStyle;
  5410. markerSize = properties.MarkerSize;
  5411. markerImage = properties.MarkerImage;
  5412. markerImageTransparentColor = properties.MarkerImageTransparentColor;
  5413. markerColor = properties.MarkerColor;
  5414. markerBorderColor = properties.MarkerBorderColor;
  5415. this._markerBorderWidth = properties.MarkerBorderWidth;
  5416. float dpi = 96;
  5417. if(Common != null)
  5418. dpi = Common.graph.Graphics.DpiX;
  5419. int maxBorderWidth = (int)Math.Round((2 * dpi) / 96);
  5420. if (this._markerBorderWidth > maxBorderWidth)
  5421. {
  5422. this._markerBorderWidth = maxBorderWidth;
  5423. }
  5424. if(properties.MarkerBorderWidth <= 0)
  5425. {
  5426. markerBorderColor = Color.Transparent;
  5427. }
  5428. // Improve readability of the line series marker by using at least 2 pixel wide lines
  5429. if(this.style == LegendImageStyle.Line &&
  5430. borderWidth <= (int)Math.Round(dpi / 96) )
  5431. {
  5432. borderWidth = maxBorderWidth;
  5433. }
  5434. if(!area3D)
  5435. {
  5436. backGradientStyle = properties.BackGradientStyle;
  5437. backSecondaryColor = properties.BackSecondaryColor;
  5438. backImageTransparentColor = properties.BackImageTransparentColor;
  5439. backImageWrapMode = properties.BackImageWrapMode;
  5440. backImageAlign = properties.BackImageAlignment;
  5441. backHatchStyle = properties.BackHatchStyle;
  5442. }
  5443. }
  5444. /// <summary>
  5445. /// Invalidate chart (or just legend )when collection is changed
  5446. /// </summary>
  5447. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the WinForms version of Chart")]
  5448. private void Invalidate(bool invalidateLegendOnly)
  5449. {
  5450. if(Legend != null)
  5451. {
  5452. // Invalidate control
  5453. Legend.Invalidate(invalidateLegendOnly);
  5454. }
  5455. }
  5456. #endregion
  5457. #region IDisposable Members
  5458. /// <summary>
  5459. /// Releases unmanaged and - optionally - managed resources
  5460. /// </summary>
  5461. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  5462. protected override void Dispose(bool disposing)
  5463. {
  5464. if (disposing)
  5465. {
  5466. if (_cells != null)
  5467. {
  5468. _cells.Dispose();
  5469. _cells = null;
  5470. }
  5471. }
  5472. base.Dispose(disposing);
  5473. }
  5474. #endregion
  5475. }
  5476. }