123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // Purpose: Chart Legend consist of default and custom legend
- // items. Default items are automatically added based
- // on the data series and custom items are added by
- // the user. Each item usually consist of 2 cells;
- // series color marker and series name. Legend item
- // cells form vertical columns in the legend.
- // Please refer to the Chart documentation which
- // contains images and samples describing legend features.
- // :
- // NOTE: In early versions of the Chart control only 1 legend was
- // exposed through the Legend property of the root chart object.
- // Due to the customer requests, support for unlimited number of
- // legends was added through the LegendCollection exposed as a
- // Legends property in the root chart object. Old propertys was
- // deprecated and marked as non-browsable.
- //
- using System;
- using System.Windows.Forms;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Drawing;
- using System.Drawing.Design;
- using System.Drawing.Drawing2D;
- using FastReport.DataVisualization.Charting.ChartTypes;
- using FastReport.DataVisualization.Charting.Utilities;
- namespace FastReport.DataVisualization.Charting
- {
- using Size = System.Drawing.Size;
- #region Legend enumerations
- /// <summary>
- /// An enumeration of legend item orderings.
- /// </summary>
- public enum LegendItemOrder
- {
- /// <summary>
- /// Items will be added into the legend in an order automatically determined by the chart.
- /// </summary>
- Auto,
- /// <summary>
- /// Items will be added into the legend in the same order as the chart series.
- /// </summary>
- SameAsSeriesOrder,
- /// <summary>
- /// Items will be added into the legend in the same order as the chart series.
- /// </summary>
- ReversedSeriesOrder
- };
- /// <summary>
- /// An enumeration of legend separator styles.
- /// </summary>
- public enum LegendSeparatorStyle
- {
- /// <summary>
- /// No separator will be shown.
- /// </summary>
- None,
- /// <summary>
- /// Single solid line separator.
- /// </summary>
- Line,
- /// <summary>
- /// Single solid thick line separator.
- /// </summary>
- ThickLine,
- /// <summary>
- /// Double solid line separator.
- /// </summary>
- DoubleLine,
- /// <summary>
- /// Single dash line separator.
- /// </summary>
- DashLine,
- /// <summary>
- /// Single dot line separator.
- /// </summary>
- DotLine,
- /// <summary>
- /// Gradient solid line separator.
- /// </summary>
- GradientLine,
- /// <summary>
- /// Thick gradient solid line separator.
- /// </summary>
- ThickGradientLine,
- }
- /// <summary>
- /// An enumeration that specifies a style for a legend item's symbol.
- /// </summary>
- public enum LegendImageStyle
- {
- /// <summary>
- /// The symbol will be a rectangle.
- /// </summary>
- Rectangle,
- /// <summary>
- /// The symbol will be a line.
- /// </summary>
- Line,
- /// <summary>
- /// The symbol will be a marker.
- /// </summary>
- Marker
- }
- /// <summary>
- /// An enumeration of legend styles.
- /// </summary>
- public enum LegendStyle
- {
- /// <summary>
- /// One column, many rows.
- /// </summary>
- Column,
- /// <summary>
- /// One row, many columns.
- /// </summary>
- Row,
- /// <summary>
- /// Many column, many rows.
- /// </summary>
- Table
- };
- /// <summary>
- /// An enumeration of legend table styles.
- /// </summary>
- public enum LegendTableStyle
- {
- /// <summary>
- /// The legend table style is automatically determined by the chart.
- /// </summary>
- Auto,
- /// <summary>
- /// The legend items will be fit horizontally within the legend.
- /// It is preferred to use this style when the docking is set to top or bottom.
- /// </summary>
- Wide,
- /// <summary>
- /// The legend items will be fit vertically within the legend.
- /// It is preferred to use this style when docking is set to left or right.
- /// </summary>
- Tall
- };
-
- #endregion
- /// <summary>
- /// The legend class represents a single chart legend. It contains visual
- /// appearance, position and content properties. This class is also
- /// responsible for drawing and positioning of the legend.
- /// </summary>
- [
- SRDescription("DescriptionAttributeLegend_Legend"),
- DefaultProperty("Enabled"),
- ]
- public class Legend : ChartNamedElement
- {
- #region Fields
- //***********************************************************
- //** Private data members, which store properties values
- //***********************************************************
- private ElementPosition _position = null;
- private bool _enabled = true;
- private LegendStyle _legendStyle = LegendStyle.Table;
- private LegendTableStyle _legendTableStyle = LegendTableStyle.Auto;
- private LegendItemsCollection _customLegends = null;
- private ChartHatchStyle _backHatchStyle = ChartHatchStyle.None;
- private string _backImage = "";
- private ChartImageWrapMode _backImageWrapMode = ChartImageWrapMode.Tile;
- private Color _backImageTransparentColor = Color.Empty;
- private ChartImageAlignmentStyle _backImageAlignment = ChartImageAlignmentStyle.TopLeft;
- private GradientStyle _backGradientStyle = GradientStyle.None;
- private Color _backSecondaryColor = Color.Empty;
- private Color _borderColor = Color.Empty;
- private Color _backColor = Color.Empty;
- private int _borderWidth = 1;
- private ChartDashStyle _borderDashStyle = ChartDashStyle.Solid;
- private FontCache _fontCache = new FontCache();
- private Font _font = null;
- private Color _foreColor = Color.Black;
- private StringAlignment _legendAlignment = StringAlignment.Near;
- private Docking _legendDocking = Docking.Right;
- private int _shadowOffset = 0;
- private Color _shadowColor = Color.FromArgb(128, 0, 0, 0);
- private bool _isTextAutoFit = true;
- private string _dockedToChartArea = Constants.NotSetValue;
- private bool _isDockedInsideChartArea = true;
- //***********************************************************
- //** Private data members
- //***********************************************************
- // Collection of custom and series legend items
- internal LegendItemsCollection legendItems = null;
- // Number of rows and columns
- private int _itemColumns = 0;
- // Font calculated by auto fitting
- internal Font autofitFont = null;
- // Indicates that all items in the legend should be equally spaced
- private bool _isEquallySpacedItems = false;
- // Indicate that legend rows should be drawn with isInterlaced background color.
- private bool _interlacedRows = false;
- // Legend isInterlaced rows color
- private Color _interlacedRowsColor = Color.Empty;
- // Legend offsets
- private Size _offset = Size.Empty;
- // Adjustment point used for legend animation
- private float _maximumLegendAutoSize = 50f;
- // Text length after which the legend item text will be wrapped on the next whitespace.
- private int _textWrapThreshold = 25;
- // Value used to calculate auto-fit font size from the legend Font.
- private int _autoFitFontSizeAdjustment = 0;
- // Legend column collection
- private LegendCellColumnCollection _cellColumns = null;
- // Indicates that legend items automatically added based on the exsisting
- // series in reversed order.
- private LegendItemOrder _legendItemOrder = LegendItemOrder.Auto;
- // Legend title text
- private string _title = String.Empty;
- // Legend title color
- private Color _titleForeColor = Color.Black;
- // Legend title back color
- private Color _titleBackColor = Color.Empty;
- // Legend title font
- private Font _titleFont = null;
- // Legend title alignment
- private StringAlignment _titleAlignment = StringAlignment.Center;
- // Legend title visual separator
- private LegendSeparatorStyle _titleSeparator = LegendSeparatorStyle.None;
- // Legend title visual separator color
- private Color _titleSeparatorColor = Color.Black;
- // Legend header visual separator
- private LegendSeparatorStyle _headerSeparator = LegendSeparatorStyle.None;
- // Legend header visual separator color
- private Color _headerSeparatorColor = Color.Black;
- // Legend table columns visual separator
- private LegendSeparatorStyle _itemColumnSeparator = LegendSeparatorStyle.None;
- // Legend table columns visual separator color
- private Color _itemColumnSeparatorColor = Color.Black;
- // Legend table column spacing calculated as a percentage of the font
- private int _itemColumnSpacing = 50;
- // Legend table column spacing calculated in relative coordinates
- private int _itemColumnSpacingRel = 0;
- // Legend title position in pixelcoordinates.
- // Note that legend title always docked to the top of the legend.
- private Rectangle _titlePosition = Rectangle.Empty;
- // Legend header position in pixel coordinates.
- private Rectangle _headerPosition = Rectangle.Empty;
- // Minimum font size that can be used by the legend auto-fitting algorithm
- private int _autoFitMinFontSize = 7;
- // Horizontal space left after fitting legend items
- private int _horizontalSpaceLeft = 0;
- // Vertical space left after fitting legend items
- private int _verticalSpaceLeft = 0;
- // Sub-columns sizes calculated during the fitting process
- private int[,] _subColumnSizes = null;
- // Legend item heigts
- private int[,] _cellHeights = null;
- // Number of rows per each legend table column
- private int[] _numberOfRowsPerColumn = null;
- // Number of items from the collection that should be processed
- private int _numberOfLegendItemsToProcess = -1;
- // Legend items area position in pixels
- private Rectangle _legendItemsAreaPosition = Rectangle.Empty;
- // Indicates that not all legend items were able to fit the legend
- private bool _legendItemsTruncated = false;
- // Size of the dots (pixels) that will drawn on the bottom of the legend when it is truncated
- private int _truncatedDotsSize = 3;
- // Maximum number of cells in the legend item
- private int _numberOfCells = -1;
- // Pixel size of the 'W' character
- internal Size singleWCharacterSize = Size.Empty;
- #endregion
- #region Constructors
- /// <summary>
- /// Legend constructor
- /// </summary>
- public Legend()
- {
- _position = new ElementPosition(this);
- // Initialize custom items collection
- _customLegends = new LegendItemsCollection(this);
- legendItems = new LegendItemsCollection(this);
- _cellColumns = new LegendCellColumnCollection(this);
- _font = _fontCache.DefaultFont;
- _titleFont = _fontCache.DefaultBoldFont;
- }
- /// <summary>
- /// Legend constructor
- /// </summary>
- /// <param name="name">The legend name.</param>
- public Legend(string name) : base (name)
- {
- _position = new ElementPosition(this);
- // Initialize custom items collection
- _customLegends = new LegendItemsCollection(this);
- legendItems = new LegendItemsCollection(this);
- _cellColumns = new LegendCellColumnCollection(this);
- _font = _fontCache.DefaultFont;
- _titleFont = _fontCache.DefaultBoldFont;
- }
- #endregion
- #region Legend position & size methods
- /// <summary>
- /// Recalculates legend information:
- /// - legend items collection
- /// - maximum text rectangle
- /// </summary>
- /// <param name="chartGraph">Reference to the chart graphics.</param>
- private void RecalcLegendInfo(ChartGraphics chartGraph)
- {
- // Reset some values
- RectangleF legendPositionRel = _position.ToRectangleF();
- Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(legendPositionRel));
- //***********************************************************
- //** Use size of the "W" characters in current font to
- //** calculate legend spacing
- //***********************************************************
- this.singleWCharacterSize = chartGraph.MeasureStringAbs("W", this.Font);
- Size doubleCharacterSize = chartGraph.MeasureStringAbs("WW", this.Font);
- this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
-
- // Calculate left, top offset and column spacing
- this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
- this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
- // Calculate item column spacing and make sure it is dividable by 2
- this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
- if(this._itemColumnSpacingRel % 2 == 1)
- {
- this._itemColumnSpacingRel += 1;
- }
- //***********************************************************
- //** Calculate how much space required for the title.
- //***********************************************************
- this._titlePosition = Rectangle.Empty;
- if(this.Title.Length > 0)
- {
- // Measure title text size
- Size titleSize = this.GetTitleSize(chartGraph, legendPosition.Size);
- // Set legend title position
- this._titlePosition = new Rectangle(
- legendPosition.Location.X,
- legendPosition.Location.Y,
- legendPosition.Width,
- Math.Min(legendPosition.Height, titleSize.Height));
- // Adjust legend items position height
- legendPosition.Height -= this._titlePosition.Height;
- // Increase title top location by border height
- this._titlePosition.Y += this.GetBorderSize();
- }
- //***********************************************************
- //** Calculate how much space required for the header.
- //***********************************************************
- this._headerPosition = Rectangle.Empty;
- // Find the largest (height only) header
- Size highestHeader = Size.Empty;
- foreach(LegendCellColumn legendColumn in this.CellColumns)
- {
- if(legendColumn.HeaderText.Length > 0)
- {
- // Measure header text size
- Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
- // Get header with maximum height
- highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
- }
- }
- // Check if any headers where found
- if(!highestHeader.IsEmpty)
- {
- // Set legend header position
- this._headerPosition = new Rectangle(
- legendPosition.Location.X + this.GetBorderSize() + this._offset.Width,
- legendPosition.Location.Y + this._titlePosition.Height,
- legendPosition.Width - (this.GetBorderSize() + this._offset.Width) * 2,
- Math.Min(legendPosition.Height - this._titlePosition.Height, highestHeader.Height));
- this._headerPosition.Height = Math.Max(this._headerPosition.Height, 0);
- // Adjust legend items position height
- legendPosition.Height -= this._headerPosition.Height;
- // Increase header top location by border height
- this._headerPosition.Y += this.GetBorderSize();
- }
- //***********************************************************
- //** Calculate size available for all legend items
- //***********************************************************
- this._legendItemsAreaPosition = new Rectangle(
- legendPosition.X + this._offset.Width + this.GetBorderSize(),
- legendPosition.Y + this._offset.Height + this.GetBorderSize() + this._titlePosition.Height + this._headerPosition.Height,
- legendPosition.Width - 2 * (this._offset.Width + this.GetBorderSize()),
- legendPosition.Height - 2 * (this._offset.Height + this.GetBorderSize()) );
- //***********************************************************
- //** Calculate number of rows and columns depending on
- //** the legend style
- //***********************************************************
- this.GetNumberOfRowsAndColumns(
- chartGraph,
- this._legendItemsAreaPosition.Size,
- -1,
- out this._numberOfRowsPerColumn,
- out this._itemColumns,
- out this._horizontalSpaceLeft,
- out this._verticalSpaceLeft);
- //***********************************************************
- //** Try to fit all legend item cells reducing the font size
- //***********************************************************
- // Reset auto-fit font adjustment value and truncated legend flag
- this._autoFitFontSizeAdjustment = 0;
- this._legendItemsTruncated = false;
- // Check if legend items fit into the legend area
- bool autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
- // Calculate total number of items fit and make sure we fit all of them
- this._numberOfLegendItemsToProcess = this.legendItems.Count;
- int itemsFit = 0;
- for(int index = 0; index < this._itemColumns; index++)
- {
- itemsFit += this._numberOfRowsPerColumn[index];
- }
- if(itemsFit < this._numberOfLegendItemsToProcess)
- {
- autoFitDone = false;
- }
- // If items do not fit try reducing font or number of legend items
- this.autofitFont = this.Font;
- if(!autoFitDone)
- {
- do
- {
- // Check if legend item font size can be reduced
- if(this.IsTextAutoFit &&
- (this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
- {
- // Reduce font size by one
- ++this._autoFitFontSizeAdjustment;
- // Calculate new font size
- int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
- if(newFontSize < 1)
- {
- // Font can't be less than size 1
- newFontSize = 1;
- }
- // Create new font
- this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
- this.Font.FontFamily,
- newFontSize,
- this.Font.Style,
- this.Font.Unit);
- // Calculate number of rows and columns
- this.GetNumberOfRowsAndColumns(
- chartGraph,
- this._legendItemsAreaPosition.Size,
- -1,
- out this._numberOfRowsPerColumn,
- out this._itemColumns,
- out this._horizontalSpaceLeft,
- out this._verticalSpaceLeft);
- autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
- // Calculate total number of items fit and make sure we fit all of them
- itemsFit = 0;
- for(int index = 0; index < this._itemColumns; index++)
- {
- itemsFit += this._numberOfRowsPerColumn[index];
- }
- if(itemsFit < this._numberOfLegendItemsToProcess)
- {
- autoFitDone = false;
- }
- }
- else
- {
- // If font size cannot be reduced start removing legend items
- if(this._numberOfLegendItemsToProcess > 2)
- {
- // Handle case of 1 column that do not fit horizontally
- if(this._itemColumns == 1 && (this._horizontalSpaceLeft < 0 && this._verticalSpaceLeft >= 0))
- {
- autoFitDone = true;
- this._numberOfLegendItemsToProcess =
- Math.Min(this._numberOfLegendItemsToProcess, this._numberOfRowsPerColumn[0]);
- }
- // Handle case of 1 row that do not fit vertically
- else if(this.GetMaximumNumberOfRows() == 1 && (this._verticalSpaceLeft < 0 && this._horizontalSpaceLeft >= 0))
- {
- autoFitDone = true;
- this._numberOfLegendItemsToProcess =
- Math.Min(this._numberOfLegendItemsToProcess, this._itemColumns);
- }
- else
- {
- // Adjust legend items area height by size required to show
- // visually (dots) that legend is truncated
- if(!this._legendItemsTruncated)
- {
- this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
- }
- // Remove last legend item
- this._legendItemsTruncated = true;
- --this._numberOfLegendItemsToProcess;
- // RecalculateAxesScale number of rows and columns
- this.GetNumberOfRowsAndColumns(
- chartGraph,
- this._legendItemsAreaPosition.Size,
- this._numberOfLegendItemsToProcess,
- out this._numberOfRowsPerColumn,
- out this._itemColumns);
- }
- // Make sure we show truncated legend symbols when not all items shown
- if(autoFitDone &&
- !this._legendItemsTruncated &&
- this._numberOfLegendItemsToProcess < this.legendItems.Count)
- {
- // Adjust legend items area height by size required to show
- // visually (dots) that legend is truncated
- this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
- // Legend is truncated
- this._legendItemsTruncated = true;
- }
- }
- else
- {
- autoFitDone = true;
- }
-
- // Check if legend items fit into the legend area
- if(!autoFitDone)
- {
- autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- this._legendItemsAreaPosition.Size,
- this._numberOfLegendItemsToProcess,
- this._autoFitFontSizeAdjustment,
- this._itemColumns,
- this._numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out this._horizontalSpaceLeft,
- out this._verticalSpaceLeft);
- }
- }
- } while(!autoFitDone);
- }
-
- //***********************************************************
- //** Calculate position of all cells
- //***********************************************************
- // Calculate item vertical spacing in relative coordinates but rounded on pixel boundary
- Size itemHalfSpacing = Size.Empty;
- if(this._verticalSpaceLeft > 0)
- {
- itemHalfSpacing.Height = (int)(this._verticalSpaceLeft / this.GetMaximumNumberOfRows() / 2);
- }
- if(this._horizontalSpaceLeft > 0)
- {
- itemHalfSpacing.Width = (int)(_horizontalSpaceLeft / 2);
- }
- // Iterate through all legend items
- int currentColumn = 0;
- int currentRow = 0;
- if(this._numberOfLegendItemsToProcess < 0)
- {
- this._numberOfLegendItemsToProcess = this.legendItems.Count;
- }
- for(int legendItemIndex = 0; legendItemIndex < this._numberOfLegendItemsToProcess; legendItemIndex++)
- {
- LegendItem legendItem = this.legendItems[legendItemIndex];
- // Iterate through legend item cells
- for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
- {
- // Get legend cell
- LegendCell legendCell = legendItem.Cells[cellIndex];
- // Calculate cell position
- Rectangle cellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex, itemHalfSpacing);
- // Check if current cell spans through more than 1 cell
- int overlappedCellsNumber = 0;
- if(legendCell.CellSpan > 1)
- {
- for(int spanIndex = 1; spanIndex < legendCell.CellSpan && (cellIndex + spanIndex) < legendItem.Cells.Count; spanIndex++)
- {
- // Calculate overlapped cell position
- Rectangle overlappedCellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex + spanIndex, itemHalfSpacing);
- // Adjust current cell right position
- if(cellPosition.Right < overlappedCellPosition.Right)
- {
- cellPosition.Width += overlappedCellPosition.Right - cellPosition.Right;
- }
- // Increase number of overlapped cells
- ++overlappedCellsNumber;
- // Set empty size for the overlapped cells
- LegendCell overlappedLegendCell = legendItem.Cells[cellIndex + spanIndex];
- overlappedLegendCell.SetCellPosition(
- currentRow,
- Rectangle.Empty,
- this.singleWCharacterSize);
- }
- }
- // Make sure cell is drawn inside the legend
- cellPosition.Intersect(this._legendItemsAreaPosition);
- // Set cell object position
- legendCell.SetCellPosition(
- currentRow,
- cellPosition,
- this.singleWCharacterSize);
- // Skip overlapped cells
- cellIndex += overlappedCellsNumber;
- }
- // Advance to the next row/column. Break if number of legend items exceed
- // number of availabale rows/columns.
- ++currentRow;
- if(currentRow >= this._numberOfRowsPerColumn[currentColumn])
- {
- ++currentColumn;
- currentRow = 0;
- if(currentColumn >= this._itemColumns)
- {
- break;
- }
- }
- }
- }
- /// <summary>
- /// Gets single cell position in relative coordinates.
- /// </summary>
- /// <param name="columnIndex">Cell column index.</param>
- /// <param name="rowIndex">Cell row index.</param>
- /// <param name="cellIndex">Index of the cell in the legend item.</param>
- /// <param name="itemHalfSpacing">Half legend item spacing in relative coordinates.</param>
- /// <returns></returns>
- private Rectangle GetCellPosition(
- int columnIndex,
- int rowIndex,
- int cellIndex,
- Size itemHalfSpacing)
- {
- Rectangle cellPosition = this._legendItemsAreaPosition;
- //*****************************************************************
- //** Get cell Top location
- //*****************************************************************
- for(int index = 0; index < rowIndex; index++)
- {
- cellPosition.Y += this._cellHeights[columnIndex, index];
- }
- if(itemHalfSpacing.Height > 0)
- {
- cellPosition.Y += itemHalfSpacing.Height * rowIndex * 2 + itemHalfSpacing.Height;
- }
- //*****************************************************************
- //** Get cell Left location
- //*****************************************************************
- // Add extar space left after auto fitting
- if(this._horizontalSpaceLeft > 0)
- {
- cellPosition.X += itemHalfSpacing.Width;
- }
- // Calculate how many sub-columns (cells) this legend has
- int numberOfSubColumns = this.GetNumberOfCells();
- // Iterate through all prev. columns
- for(int index = 0; index < columnIndex; index++)
- {
- // Add width of previous columns
- for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++)
- {
- cellPosition.X += this._subColumnSizes[index, subColumnIndex];
- }
- // Add width of separator for the previous columns
- cellPosition.X += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
- }
- // Add width of current column cells
- for(int subColumnIndex = 0; subColumnIndex < cellIndex; subColumnIndex++)
- {
- cellPosition.X += this._subColumnSizes[columnIndex, subColumnIndex];
- }
- //*****************************************************************
- //** Get cell Height
- //*****************************************************************
- cellPosition.Height = this._cellHeights[columnIndex, rowIndex];
-
- //*****************************************************************
- //** Get cell Width
- //*****************************************************************
- cellPosition.Width = this._subColumnSizes[columnIndex, cellIndex];
- return cellPosition;
- }
- /// <summary>
- /// Calculates the optimal size of the legend.
- /// </summary>
- /// <param name="chartGraph">Chart graphics object.</param>
- /// <param name="maxSizeRel">Max size for the legend.</param>
- /// <returns>Legend optimal size.</returns>
- private SizeF GetOptimalSize(ChartGraphics chartGraph, SizeF maxSizeRel)
- {
- // Reset some values
- this._offset = Size.Empty;
- this._itemColumns = 0;
- this._horizontalSpaceLeft = 0;
- this._verticalSpaceLeft = 0;
- this._subColumnSizes = null;
- this._numberOfRowsPerColumn = null;
- this._cellHeights = null;
- this.autofitFont = null;
- this._autoFitFontSizeAdjustment = 0;
- this._numberOfCells = -1;
- this._numberOfLegendItemsToProcess = -1;
- Size optimalSize = Size.Empty;
- // Convert to pixels
- SizeF maxSizeAbs = chartGraph.GetAbsoluteSize(maxSizeRel);
- Size maxSize = new Size((int)maxSizeAbs.Width, (int)maxSizeAbs.Height);
- // Clear all legend item cells cached information
- foreach(LegendItem legendItem in this.legendItems)
- {
- foreach(LegendCell cell in legendItem.Cells)
- {
- cell.ResetCache();
- }
- }
- // Check if legend is enabled
- if(this.IsEnabled())
- {
- // Add all series legend into items collection and then add custom legend items
- FillLegendItemsCollection();
- // Call a notification event, so that legend items collection can be modified by user
- this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
- // Check if there are any items in the legend
- if(this.legendItems.Count > 0)
- {
- //***********************************************************
- //** Use size of the "W" character in current font to
- //** calculate legend spacing
- //***********************************************************
- this.singleWCharacterSize = chartGraph.MeasureStringAbs("W", this.Font);
- Size doubleCharacterSize = chartGraph.MeasureStringAbs("WW", this.Font);
- this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
-
- // Calculate left, top offset and column spacing
- this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
- this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
- this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
- if(this._itemColumnSpacingRel % 2 == 1)
- {
- this._itemColumnSpacingRel += 1;
- }
- //***********************************************************
- //** Add size required for the legend tile
- //***********************************************************
-
- Size titleSize = Size.Empty;
- if(this.Title.Length > 0)
- {
- titleSize = this.GetTitleSize(chartGraph, maxSize);
- }
- //***********************************************************
- //** Add size required for the legend header
- //***********************************************************
- Size highestHeader = Size.Empty;
- foreach(LegendCellColumn legendColumn in this.CellColumns)
- {
- if(legendColumn.HeaderText.Length > 0)
- {
- // Measure header text size
- Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
- // Get header with maximum height
- highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
- }
- }
- //***********************************************************
- //** Calculate size available for legend items
- //***********************************************************
- Size legenItemsMaxSize = maxSize;
- legenItemsMaxSize.Width -= 2 * (this._offset.Width + this.GetBorderSize());
- legenItemsMaxSize.Height -= 2 * (this._offset.Height + this.GetBorderSize());
- legenItemsMaxSize.Height -= titleSize.Height;
- legenItemsMaxSize.Height -= highestHeader.Height;
- //***********************************************************
- //** Calculate number of rows and columns depending on
- //** the legend style
- //***********************************************************
- this._autoFitFontSizeAdjustment = 0;
- this.autofitFont = this.Font;
- int vertSpaceLeft = 0;
- int horizSpaceLeft = 0;
- bool reduceFont = this.IsTextAutoFit;
- bool autoFit = false;
- do
- {
- // Get number of columns and rows that we can fit in the legend
- this.GetNumberOfRowsAndColumns(
- chartGraph,
- legenItemsMaxSize,
- -1,
- out this._numberOfRowsPerColumn,
- out this._itemColumns,
- out horizSpaceLeft,
- out vertSpaceLeft);
- // Calculate total number of items fit and make sure we fit all of them
- int itemsFit = 0;
- for(int index = 0; index < this._itemColumns; index++)
- {
- itemsFit += this._numberOfRowsPerColumn[index];
- }
- autoFit = (horizSpaceLeft >= 0 && vertSpaceLeft >= 0 && itemsFit >= this.legendItems.Count);
- // Check if items fit
- if(reduceFont && !autoFit)
- {
- if((this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
- {
- // Reduce font size by one
- ++this._autoFitFontSizeAdjustment;
- // Calculate new font size
- int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
- if(newFontSize < 1)
- {
- // Font can't be less than size 1
- newFontSize = 1;
- }
- // Create new font
- this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
- this.Font.FontFamily,
- newFontSize,
- this.Font.Style,
- this.Font.Unit);
- }
- else
- {
- reduceFont = false;
- }
- }
- } while(reduceFont && !autoFit);
- // Slightly reduce used space
- horizSpaceLeft -= Math.Min(4, horizSpaceLeft);
- vertSpaceLeft -= Math.Min(2, vertSpaceLeft);
-
- //***********************************************************
- //** Calculate legend size
- //***********************************************************
- optimalSize.Width = (legenItemsMaxSize.Width - horizSpaceLeft);
- optimalSize.Width = Math.Max(optimalSize.Width, titleSize.Width);
- optimalSize.Width += 2 * (this._offset.Width + this.GetBorderSize());
- optimalSize.Height = (legenItemsMaxSize.Height - vertSpaceLeft) + titleSize.Height + highestHeader.Height;
- optimalSize.Height += 2 * (this._offset.Height + this.GetBorderSize());
- // Adjust legend items area height by size required to show
- // visually (dots) that legend is truncated
- if(horizSpaceLeft < 0 || vertSpaceLeft < 0)
- {
- optimalSize.Height += this._truncatedDotsSize;
- }
- //***********************************************************
- //** Make sure legend size do not exceed max. value
- //***********************************************************
- if(optimalSize.Width > maxSize.Width)
- {
- optimalSize.Width = maxSize.Width;
- }
- if(optimalSize.Height > maxSize.Height)
- {
- optimalSize.Height = maxSize.Height;
- }
- if(optimalSize.Width < 0)
- {
- optimalSize.Width = 0;
- }
- if(optimalSize.Height < 0)
- {
- optimalSize.Height = 0;
- }
- }
- }
- // Convert result size from pixel to relative coordinates
- return chartGraph.GetRelativeSize(optimalSize);
- }
- /// <summary>
- /// Recalculates legend position.
- /// </summary>
- /// <param name="chartGraph">Chart graphics used.</param>
- /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
- /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
- internal void CalcLegendPosition(
- ChartGraphics chartGraph,
- ref RectangleF chartAreasRectangle,
- float elementSpacing)
- {
- RectangleF legendPosition = new RectangleF();
- // Get optimal legend size
- SizeF maxSize = new SizeF(chartAreasRectangle.Width - 2*elementSpacing, chartAreasRectangle.Height - 2*elementSpacing);
- if (this.DockedToChartArea == Constants.NotSetValue)
- {
- // Note: 'maxLegendSize' parameter is ignored. New legend property
- // 'maximumLegendAutoSize' is used instead.
- if(this.Docking == Docking.Top || this.Docking == Docking.Bottom)
- {
- maxSize.Height = (maxSize.Height / 100F) * this._maximumLegendAutoSize;
- }
- else
- {
- maxSize.Width = (maxSize.Width / 100F) * this._maximumLegendAutoSize;
- }
- }
- if(maxSize.Width <= 0 || maxSize.Height <= 0)
- {
- return;
- }
-
- SizeF legendSize = this.GetOptimalSize(chartGraph, maxSize);
- legendPosition.Height = legendSize.Height;
- legendPosition.Width = legendSize.Width;
- if(float.IsNaN(legendSize.Height) || float.IsNaN(legendSize.Width))
- {
- return;
- }
- // Calculate legend position
- if(this.Docking == Docking.Top)
- {
- legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
- if(this.Alignment == StringAlignment.Near)
- {
- legendPosition.X = chartAreasRectangle.X + elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Far)
- {
- legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Center)
- {
- legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
- }
- // Adjust position of the chart area(s)
- chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
- chartAreasRectangle.Y = legendPosition.Bottom;
- }
- else if(this.Docking == Docking.Bottom)
- {
- legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
- if(this.Alignment == StringAlignment.Near)
- {
- legendPosition.X = chartAreasRectangle.X + elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Far)
- {
- legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Center)
- {
- legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
- }
- // Adjust position of the chart area(s)
- chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
- }
- if(this.Docking == Docking.Left)
- {
- legendPosition.X = chartAreasRectangle.X + elementSpacing;
- if(this.Alignment == StringAlignment.Near)
- {
- legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Far)
- {
- legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Center)
- {
- legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
- }
- // Adjust position of the chart area(s)
- chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
- chartAreasRectangle.X = legendPosition.Right;
- }
- if(this.Docking == Docking.Right)
- {
- legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
- if(this.Alignment == StringAlignment.Near)
- {
- legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Far)
- {
- legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
- }
- else if(this.Alignment == StringAlignment.Center)
- {
- legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
- }
- // Adjust position of the chart area(s)
- chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
- }
- this.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
- }
- /// <summary>
- /// Get number of columns and rows that can be fit in specified size.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <param name="legendSize">Legend size.</param>
- /// <param name="numberOfItemsToCheck">Number of legend items to check.</param>
- /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
- /// <param name="columnNumber">Returns number of columns.</param>
- private void GetNumberOfRowsAndColumns(
- ChartGraphics chartGraph,
- Size legendSize,
- int numberOfItemsToCheck,
- out int[] numberOfRowsPerColumn,
- out int columnNumber)
- {
- int horSpaceLeft = 0;
- int vertSpaceLeft = 0;
- this.GetNumberOfRowsAndColumns(
- chartGraph,
- legendSize,
- numberOfItemsToCheck,
- out numberOfRowsPerColumn,
- out columnNumber,
- out horSpaceLeft,
- out vertSpaceLeft);
- }
- /// <summary>
- /// Get number of columns and rows that can be fit in specified size.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <param name="legendSize">Legend size.</param>
- /// <param name="numberOfItemsToCheck">Legend items number to check.</param>
- /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
- /// <param name="columnNumber">Returns number of columns.</param>
- /// <param name="horSpaceLeft">Returns horizontal spacing left.</param>
- /// <param name="vertSpaceLeft">Returns vertical spacing left.</param>
- private void GetNumberOfRowsAndColumns(
- ChartGraphics chartGraph,
- Size legendSize,
- int numberOfItemsToCheck,
- out int[] numberOfRowsPerColumn,
- out int columnNumber,
- out int horSpaceLeft,
- out int vertSpaceLeft)
- {
- // Initialize output parameters
- numberOfRowsPerColumn = null;
- columnNumber = 1;
- horSpaceLeft = 0;
- vertSpaceLeft = 0;
- // If number of items to check is nor set use total number of items in the collection
- if(numberOfItemsToCheck < 0)
- {
- numberOfItemsToCheck = legendItems.Count;
- }
- // Check legend style
- if(this.LegendStyle == LegendStyle.Column || numberOfItemsToCheck <= 1)
- {
- columnNumber = 1;
- numberOfRowsPerColumn = new int[] { numberOfItemsToCheck };
- }
- else if(this.LegendStyle == LegendStyle.Row)
- {
- columnNumber = numberOfItemsToCheck;
- numberOfRowsPerColumn = new int[columnNumber];
- for(int index = 0; index < columnNumber; index++)
- {
- numberOfRowsPerColumn[index] = 1;
- }
- }
- else if(this.LegendStyle == LegendStyle.Table)
- {
- // Start with 1 column and 1 row
- columnNumber = 1;
- numberOfRowsPerColumn = new int[] { 1 };
- // Get legend table style and adjust number of columns and rows accordinly
- LegendTableStyle tableStyle = this.GetLegendTableStyle(chartGraph);
-
- //*********************************************************************************
- //** Tall table layout
- //*********************************************************************************
- if(tableStyle == LegendTableStyle.Tall)
- {
- // Iterate from second item trying to add them and check if their fit
- bool exitLoop = false;
- int legendItemIndex = 1;
- for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
- {
- // Try to increase number of rows in the current column
- ++numberOfRowsPerColumn[columnNumber - 1];
- // Check if legend items fit into the legend area
- bool autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- // Check if we fit or if we have just one column that do not fit
- // horizontally but still have vertical space.
- if(autoFitDone ||
- ( (columnNumber == 1 || horSpaceLeft < 0) && vertSpaceLeft > 0) )
- {
- // Continue adding rows to the current column
- continue;
- }
- else
- {
- // Reduce number of rows in the current column
- if(numberOfRowsPerColumn[columnNumber - 1] > 1)
- {
- --numberOfRowsPerColumn[columnNumber - 1];
- }
- // Get half of average column width
- int averageColumnWidth = 0;
- if(horSpaceLeft > 0)
- {
- averageColumnWidth = (int)Math.Round((double)(legendSize.Width - horSpaceLeft) / columnNumber) / 2;
- }
- // Check if number of columns can be increased
- if(columnNumber < 50 && horSpaceLeft >= averageColumnWidth)
- {
- // Add new column
- ++columnNumber;
- // Resize array that stores number of rows per column
- int[] tempArray = numberOfRowsPerColumn;
- numberOfRowsPerColumn = new int[columnNumber];
- for(int index = 0; index < tempArray.Length; index++)
- {
- numberOfRowsPerColumn[index] = tempArray[index];
- }
- numberOfRowsPerColumn[columnNumber - 1] = 1;
- // If last legend item is moved into a new column
- // call the auto fitting method before leaving the loop
- if(legendItemIndex == numberOfItemsToCheck - 1)
- {
- this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- }
- }
- else
- {
- exitLoop = true;
- }
- }
- }
- // Check if we end up with legend with multiple columns
- // where last column has sinificantly lower height of all rows
- if(columnNumber > 1)
- {
- // Try reducing number of rows in the "tall" calumns and move them
- // into the last column.
- bool done = false;
- while(!done)
- {
- // By default no more iterations required
- done = true;
- // Find maximum column height not taking the last row in consideration
- int maxColumnHeight = -1;
- for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
- {
- // Calculate current column height not taking the last row in consideration
- int columnHeight = 0;
- for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex] - 1; rowIndex++)
- {
- columnHeight += this._cellHeights[columnIndex, rowIndex];
- }
- // Find maximum height
- maxColumnHeight = Math.Max(maxColumnHeight, columnHeight);
- }
- // Calculate total height of items in the last row
- int totalHieghtOfItemInLastRow = 0;
- for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
- {
- if(this._numberOfRowsPerColumn[columnIndex] > 1)
- {
- totalHieghtOfItemInLastRow += this._cellHeights[columnIndex, this._numberOfRowsPerColumn[columnIndex] - 1];
- }
- }
- // Check if rows are available for removal
- if(totalHieghtOfItemInLastRow > 0)
- {
- // Get last column height
- int lastColumnHeight = this.GetColumnHeight(columnNumber - 1);
- // Check if all items in the last row can vertically fit in last column
- if( (lastColumnHeight + totalHieghtOfItemInLastRow) <= maxColumnHeight )
- {
- // Reduce number of rows in all columns except last
- int itemsToAdd = 0;
- for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
- {
- if(this._numberOfRowsPerColumn[columnIndex] > 1)
- {
- --this._numberOfRowsPerColumn[columnIndex];
- ++itemsToAdd;
- }
- }
- // Add rows to last column
- if(itemsToAdd > 0)
- {
- // Add roes into the last column
- this._numberOfRowsPerColumn[columnNumber - 1] += itemsToAdd;
- // Check if legend items fit into the legend area
- bool autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- // Try doing one more time
- done = false;
- }
- }
- }
- }
- }
- }
- //*********************************************************************************
- //** Wide table layout
- //*********************************************************************************
- else if(tableStyle == LegendTableStyle.Wide)
- {
- // Iterate from second item trying to add them and check if they fit
- bool exitLoop = false;
- int legendItemIndex = 1;
- for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
- {
- // Try to increase number of columns
- ++columnNumber;
- // Resize array that stores number of rows per column
- int[] tempArray = numberOfRowsPerColumn;
- numberOfRowsPerColumn = new int[columnNumber];
- for(int index = 0; index < tempArray.Length; index++)
- {
- numberOfRowsPerColumn[index] = tempArray[index];
- }
- numberOfRowsPerColumn[columnNumber - 1] = 1;
- // Check if legend items fit into the legend area
- bool autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- // Check if we fit or if we have just one row that do not fit
- // vertically but still have horizontal space.
- if(autoFitDone ||
- ( (this.GetMaximumNumberOfRows(numberOfRowsPerColumn) == 1 || vertSpaceLeft < 0) && horSpaceLeft > 0) )
- {
- // Continue adding columns
- continue;
- }
- else
- {
- // Remove columns and increase number of rows
- bool columnFitting = true;
- while(columnFitting)
- {
- columnFitting = false;
- // If we can't fit current number of columns reduce current column number
- int rowsToAdd = 0;
- if(columnNumber > 1)
- {
- rowsToAdd = numberOfRowsPerColumn[columnNumber - 1];
- --columnNumber;
- // Resize array that stores number of rows per column
- tempArray = numberOfRowsPerColumn;
- numberOfRowsPerColumn = new int[columnNumber];
- for(int index = 0; index < columnNumber; index++)
- {
- numberOfRowsPerColumn[index] = tempArray[index];
- }
- }
- // We may need to add more than 1 row
- for(int indexRowToAdd = 0; indexRowToAdd < rowsToAdd; indexRowToAdd++)
- {
- // Find first column with smallest height
- int smallestColumnIndex = -1;
- int columnMinHeight = int.MaxValue;
- for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
- {
- int columnHeight = this.GetColumnHeight(columnIndex);
- int nextColumnFirstItemHeight = 0;
- if(columnIndex < columnNumber - 1)
- {
- nextColumnFirstItemHeight = this._cellHeights[columnIndex + 1, 0];
- }
- if(columnHeight < columnMinHeight &&
- (columnHeight + nextColumnFirstItemHeight) < legendSize.Height)
- {
- // Remember column index and height
- columnMinHeight = columnHeight;
- smallestColumnIndex = columnIndex;
- }
- }
- // No more items can fit
- if(smallestColumnIndex < 0)
- {
- // Check if legend items fit into the legend area
- autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- exitLoop = true;
- break;
- }
- // Add new row to the smallest column
- ++numberOfRowsPerColumn[smallestColumnIndex];
- // Check if next column will be removed if it contains only 1 row
- if(smallestColumnIndex < (columnNumber - 1))
- {
- if(numberOfRowsPerColumn[smallestColumnIndex + 1] == 1)
- {
- // Shift number of rows per column
- tempArray = numberOfRowsPerColumn;
- for(int index = smallestColumnIndex + 1; index < tempArray.Length - 1; index++)
- {
- numberOfRowsPerColumn[index] = tempArray[index + 1];
- }
- numberOfRowsPerColumn[columnNumber - 1] = 1;
- }
- }
- // Check if legend items fit into the legend area
- autoFitDone = this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- legendItemIndex + 1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- }
- // If there is more than 1 column and items do not fit
- // horizontally - reduce number of columns.
- if(!autoFitDone &&
- horSpaceLeft < 0f &&
- columnNumber > 1)
- {
- columnFitting = true;
- }
- }
- }
- }
- }
- }
- // Check if items fit and how much empty space left
- this.CheckLegendItemsFit(
- chartGraph,
- legendSize,
- -1,
- this._autoFitFontSizeAdjustment,
- columnNumber,
- numberOfRowsPerColumn,
- out this._subColumnSizes,
- out this._cellHeights,
- out horSpaceLeft,
- out vertSpaceLeft);
- }
-
- /// <summary>
- /// Gets column height.
- /// </summary>
- /// <param name="columnIndex">Index of the column to get the height for.</param>
- /// <returns>Column height in relative coordinates.</returns>
- private int GetColumnHeight(int columnIndex)
- {
- // Calculate current column height
- int columnHeight = 0;
- for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex]; rowIndex++)
- {
- columnHeight += this._cellHeights[columnIndex, rowIndex];
- }
- return columnHeight;
- }
- /// <summary>
- /// Checks if legend background is selected.
- /// </summary>
- internal void SelectLegendBackground()
- {
- Common.HotRegionsList.AddHotRegion(this.Position.ToRectangleF(), this, ChartElementType.LegendArea, true);
- }
- #endregion Legend position & size methods
- #region Legend Items Fitting Methods
- /// <summary>
- /// Gets maximum number of rows in all columns.
- /// </summary>
- /// <returns>Maximum number of rows.</returns>
- private int GetMaximumNumberOfRows()
- {
- return this.GetMaximumNumberOfRows(this._numberOfRowsPerColumn);
- }
- /// <summary>
- /// Gets maximum number of rows in all columns.
- /// </summary>
- /// <param name="rowsPerColumn">Array that stores number of rows per column.</param>
- /// <returns>Maximum number of rows.</returns>
- private int GetMaximumNumberOfRows(int[] rowsPerColumn)
- {
- // Find column with maximum number of rows
- int maxNumberOfColumns = 0;
- if(rowsPerColumn != null)
- {
- for(int columnIndex = 0; columnIndex < rowsPerColumn.Length; columnIndex++)
- {
- maxNumberOfColumns = Math.Max(maxNumberOfColumns, rowsPerColumn[columnIndex]);
- }
- }
- return maxNumberOfColumns;
- }
- /// <summary>
- /// Checks if specified legend will fit the specified size.
- /// </summary>
- /// <param name="graph">Chart graphics.</param>
- /// <param name="legendItemsAreaSize">Area that legend items must fit.</param>
- /// <param name="numberOfItemsToCheck">Number of items that should be fitted.</param>
- /// <param name="fontSizeReducedBy">Number of points the standard legend font is reduced by auto-fitting algorithm.</param>
- /// <param name="numberOfColumns">Legend column number.</param>
- /// <param name="numberOfRowsPerColumn">Array of number of rows per column.</param>
- /// <param name="subColumnSizes">Returns array of sub-column size.</param>
- /// <param name="cellHeights">Returns array of cell heights.</param>
- /// <param name="horizontalSpaceLeft">Returns horizontal space left.</param>
- /// <param name="verticalSpaceLeft">Returns vertical space left.</param>
- /// <returns>True if items fit.</returns>
- private bool CheckLegendItemsFit(
- ChartGraphics graph,
- Size legendItemsAreaSize,
- int numberOfItemsToCheck,
- int fontSizeReducedBy,
- int numberOfColumns,
- int[] numberOfRowsPerColumn,
- out int[,] subColumnSizes,
- out int[,] cellHeights,
- out int horizontalSpaceLeft,
- out int verticalSpaceLeft)
- {
- bool fitFlag = true;
- // Initialize output values
- horizontalSpaceLeft = 0;
- verticalSpaceLeft = 0;
- // Use current legend item count if number of items to check is not specified
- if(numberOfItemsToCheck < 0)
- {
- numberOfItemsToCheck = this.legendItems.Count;
- }
- // Calculate how many sub-columns (cells) this legend has
- int numberOfSubColumns = this.GetNumberOfCells();
- // Each column may have its own number of rows. Calculate the maximum number of rows.
- int maxNumberOfRows = this.GetMaximumNumberOfRows(numberOfRowsPerColumn);
- // Create multidimensional arrays that will be holding the widths and heightsof all
- // individual cells. First dimension will be the legend column index, second dimension
- // is row index and the third is sub-column (cell) index.
- int[,,] cellWidths = new int[numberOfColumns, maxNumberOfRows, numberOfSubColumns];
- cellHeights = new int[numberOfColumns, maxNumberOfRows];
- //*************************************************************************
- //** Measure legend font single character
- //*************************************************************************
- this.singleWCharacterSize = graph.MeasureStringAbs("W", (this.autofitFont == null) ? this.Font : this.autofitFont);
- Size doubleCharacterSize = graph.MeasureStringAbs("WW", (this.autofitFont == null) ? this.Font : this.autofitFont);
- this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
- //*************************************************************************
- //** Iterate through all legend items and measure each individual cell
- //*************************************************************************
- int currentColumn = 0;
- int currentRow = 0;
- for(int legendItemIndex = 0; legendItemIndex < numberOfItemsToCheck; legendItemIndex++)
- {
- LegendItem legendItem = this.legendItems[legendItemIndex];
- // Iterate through legend item cells
- int numberOfCellsToSkip = 0;
- for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
- {
- // Get legend cell
- LegendCell legendCell = legendItem.Cells[cellIndex];
- // Get assocated legend column object (may be NULL)
- LegendCellColumn legendColumn = null;
- if(cellIndex < this.CellColumns.Count)
- {
- legendColumn = this.CellColumns[cellIndex];
- }
- // Check if current cell should be skipped becuse it's overlapped
- // by the previous sell that uses CellSpan.
- if(numberOfCellsToSkip > 0)
- {
- // Put size (-1) for the cells that follow a cell using ColumnSpan
- cellWidths[currentColumn, currentRow, cellIndex] = -1;
- --numberOfCellsToSkip;
- continue;
- }
- // Check if current cell uses CellSpan
- if(legendCell.CellSpan > 1)
- {
- numberOfCellsToSkip = legendCell.CellSpan - 1;
- }
- // Measure cell and store the value in the array
- Size cellSize = legendCell.MeasureCell(
- graph,
- fontSizeReducedBy,
- (this.autofitFont == null) ? this.Font : this.autofitFont,
- this.singleWCharacterSize);
- // Check for column maximum/minimum cell width restrictions
- if(legendColumn != null)
- {
- if(legendColumn.MinimumWidth >= 0)
- {
- cellSize.Width = (int)Math.Max(cellSize.Width, legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
- }
- if(legendColumn.MaximumWidth >= 0)
- {
- cellSize.Width = (int)Math.Min(cellSize.Width, legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
- }
- }
- // Store cell size in arrays
- cellWidths[currentColumn, currentRow, cellIndex] = cellSize.Width;
- if(cellIndex == 0)
- {
- cellHeights[currentColumn, currentRow] = cellSize.Height;
- }
- else
- {
- cellHeights[currentColumn, currentRow] =
- Math.Max(cellHeights[currentColumn, currentRow], cellSize.Height);
- }
- }
- // Advance to the next row/column. Break if number of legend items exceed
- // number of availabale rows/columns.
- ++currentRow;
- if(currentRow >= numberOfRowsPerColumn[currentColumn])
- {
- ++currentColumn;
- currentRow = 0;
- if(currentColumn >= numberOfColumns)
- {
- // Check if we were able to fit all the items
- if(legendItemIndex < numberOfItemsToCheck - 1)
- {
- fitFlag = false;
- }
- break;
- }
- }
- }
- //*************************************************************************
- //** For each sub-column get the maximum cell width
- //*************************************************************************
- subColumnSizes = new int[numberOfColumns, numberOfSubColumns];
- bool secondIterationRequired = false;
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
- {
- int width = 0;
- for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
- {
- // Get current cell size
- int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
- // Skip overlapped cells and cells that use ColumnSpan during the
- // first iteration. Their size will be determined during the
- // second iteration.
- if(cellWidth < 0)
- {
- secondIterationRequired = true;
- continue;
- }
- if(currentSubColumn + 1 < numberOfSubColumns)
- {
- int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + 1];
- if(nextCellWidth < 0)
- {
- continue;
- }
- }
- // Get maximum width
- width = Math.Max(width, cellWidth );
- }
- // Store maximum width in the array
- subColumnSizes[currentColumn, currentSubColumn] = width;
- }
- }
- //*************************************************************************
- //** If leagend header text is used check if it fits into the currenly
- //** calculated sub-column sizes.
- //*************************************************************************
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
- {
- if(currentSubColumn < this.CellColumns.Count)
- {
- LegendCellColumn legendColumn = this.CellColumns[currentSubColumn];
- if(legendColumn.HeaderText.Length > 0)
- {
- // Note that extra "I" character added to add more horizontal spacing
- Size headerTextSize = graph.MeasureStringAbs(legendColumn.HeaderText + "I", legendColumn.HeaderFont);
- if(headerTextSize.Width > subColumnSizes[currentColumn, currentSubColumn])
- {
- // Set new width
- subColumnSizes[currentColumn, currentSubColumn] = headerTextSize.Width;
- // Check for column maximum/minimum cell width restrictions
- if(legendColumn.MinimumWidth >= 0)
- {
- subColumnSizes[currentColumn, currentSubColumn] =
- (int)Math.Max(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
- }
- if(legendColumn.MaximumWidth >= 0)
- {
- subColumnSizes[currentColumn, currentSubColumn] =
- (int)Math.Min(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
- }
- }
- }
- }
- }
- }
- //*************************************************************************
- //** Adjust width of the cells to fit cell content displayed across
- //** several cells (CellSpanning).
- //*************************************************************************
- if(secondIterationRequired)
- {
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
- {
- for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
- {
- // Get current cell size
- int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
- // Second iteration used to adjust width of the cells that are used to
- // draw content across several horizontal cells (CellSpanning)
- // Check if current cell will be spanned to the next ones
- int cellSpan = 0;
- while(currentSubColumn + cellSpan + 1 < numberOfSubColumns)
- {
- int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + cellSpan + 1];
- if(nextCellWidth >= 0)
- {
- break;
- }
- ++cellSpan;
- }
-
- // Cell span was detected
- if(cellSpan > 0)
- {
- // Calculate total width of current cell and all overlapped cells
- int spanWidth = 0;
- for(int index = 0; index <= cellSpan; index++)
- {
- spanWidth += subColumnSizes[currentColumn, currentSubColumn + index];
- }
- // Check if current cell fits into the cell span
- if(cellWidth > spanWidth)
- {
- // Adjust last span cell width to fit all curent cell content
- subColumnSizes[currentColumn, currentSubColumn + cellSpan] += cellWidth - spanWidth;
- }
- }
- }
- }
- }
- }
-
- //*************************************************************************
- //** Check if equally spaced legend columns are used
- //*************************************************************************
- if(this.IsEquallySpacedItems)
- {
- // Makre sure that same sub-colimn width are used in all columns
- for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
- {
- int width = 0;
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- width = Math.Max(width, subColumnSizes[currentColumn, currentSubColumn]);
- }
- // Set new sub-column width for each column
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- subColumnSizes[currentColumn, currentSubColumn] = width;
- }
- }
- }
- //*************************************************************************
- //** Calculate total width and height occupied by all cells
- //*************************************************************************
- int totalWidth = 0;
- int totalTableColumnSpacingWidth = 0;
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- // Add up all sub-columns
- for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
- {
- totalWidth += subColumnSizes[currentColumn, currentSubColumn];
- }
- // Add spacer between columns
- if(currentColumn < numberOfColumns - 1)
- {
- totalTableColumnSpacingWidth += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
- }
- }
- int totalHeight = 0;
- for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
- {
- int columnHeight = 0;
- for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
- {
- columnHeight += cellHeights[currentColumn, currentRow];
- }
- totalHeight = Math.Max(totalHeight, columnHeight);
- }
- //*************************************************************************
- //** Check if everything fits
- //*************************************************************************
- horizontalSpaceLeft = legendItemsAreaSize.Width - totalWidth - totalTableColumnSpacingWidth;
- if(horizontalSpaceLeft < 0)
- {
- fitFlag = false;
- }
-
- verticalSpaceLeft = legendItemsAreaSize.Height - totalHeight;
- if(verticalSpaceLeft < 0)
- {
- fitFlag = false;
- }
- return fitFlag;
- }
- /// <summary>
- /// Gets maximum number of legend cells defined as Column objects
- /// or Cells in the custom legend items.
- /// </summary>
- /// <returns>Maximum number of cells.</returns>
- private int GetNumberOfCells()
- {
- // Calculate cell number if it was not previously cached
- if(this._numberOfCells < 0)
- {
- // Initialize with number of defined columns
- this._numberOfCells = this.CellColumns.Count;
- // Check if number of cells in legend items exceed number of defined columns
- foreach(LegendItem legendItem in this.legendItems)
- {
- this._numberOfCells = Math.Max(this._numberOfCells, legendItem.Cells.Count);
- }
- }
- return this._numberOfCells;
- }
- #endregion // Legend Items Fitting Methods
- #region Legend items collection filling methods
- /// <summary>
- /// Add all series legend into items collection and then
- /// add custom legend items.
- /// </summary>
- private void FillLegendItemsCollection()
- {
- // Clear all items
- legendItems.Clear();
- // Check that there is no invalid legend names in the series
- foreach(Series series in this.Common.DataManager.Series)
- {
- if (this.Common.ChartPicture.Legends.IndexOf(series.Legend)<0)
- {
- throw (new InvalidOperationException(SR.ExceptionLegendReferencedInSeriesNotFound(series.Name, series.Legend)));
- }
- }
- // Flag which indicates that series requires legend items to be reversed
- bool seriesWithReversedLegendItemsPresent = false;
- // Add legend items based on the exsisting chart series
- foreach(Series series in this.Common.DataManager.Series)
- {
- // Check if series uses this legend
- // VSTS issue #140694 fix: support of series.Legend = "Default";
- if (this.Common.ChartPicture.Legends[series.Legend] != this)
- {
- continue;
- }
- // Make sure series is assigned to the chart area
- if(series.ChartArea.Length > 0)
- {
- // Check if chart area name is valid
- bool areaNameFound = false;
- foreach(ChartArea area in this.Common.ChartPicture.ChartAreas)
- {
- if(area.Name == series.ChartArea)
- {
- areaNameFound = true;
- break;
- }
- }
- // Check if series is visible and valid chart area name was used
- if(series.IsVisible() && areaNameFound)
- {
- // Check if we should add all data points into the legend
- IChartType chartType = this.Common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
- // Check if series legend items should be reversed
- if (this.LegendItemOrder == LegendItemOrder.Auto)
- {
- if(series.ChartType == SeriesChartType.StackedArea ||
- series.ChartType == SeriesChartType.StackedArea100 ||
- series.ChartType == SeriesChartType.Pyramid ||
- series.ChartType == SeriesChartType.StackedColumn ||
- series.ChartType == SeriesChartType.StackedColumn100 )
- {
- seriesWithReversedLegendItemsPresent = true;
- }
- }
- // Add item(s) based on series points label and fore color
- if(chartType.DataPointsInLegend)
- {
- // Check if data points have X values set
- bool xValuesSet = false;
- foreach(DataPoint point in series.Points)
- {
- if(point.XValue != 0.0)
- {
- xValuesSet = true;
- break;
- }
- }
- // Add legend items for each point
- int index = 0;
- foreach(DataPoint point in series.Points)
- {
- // Do not show empty data points in the legend
- if(point.IsEmpty)
- {
- ++index;
- continue;
- }
- // Point should not be shown in the legend
- if(!point.IsVisibleInLegend)
- {
- ++index;
- continue;
- }
- // Create new legend item
- LegendItem item = new LegendItem(point.Label, point.Color, "");
- // Check if series is drawn in 3D chart area
- bool area3D = this.Common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
- // Set legend item appearance properties
- item.SetAttributes(this.Common, series);
- item.SetAttributes(point, area3D);
- // Set chart image map properties
- item.ToolTip = point.ReplaceKeywords(point.LegendToolTip);
- item.Name = point.ReplaceKeywords(point.LegendText);
- item.SeriesPointIndex = index++;
- if(item.Name.Length == 0)
- {
- item.Name = point.ReplaceKeywords((point.Label.Length > 0) ? point.Label : point.AxisLabel);
- }
- // If legend item name is not defined - try using the X value
- if(item.Name.Length == 0 && xValuesSet)
- {
- item.Name = ValueConverter.FormatValue(
- series.Chart,
- this,
- this.Tag,
- point.XValue,
- "", // Do not use point label format! For Y values only! point.LabelFormat,
- point.series.XValueType,
- ChartElementType.LegendItem);
- }
- // If legend item name is not defined - use index
- if(item.Name.Length == 0)
- {
- item.Name = "Point " + index;
- }
- // Add legend item cells based on predefined columns
- item.AddAutomaticCells(this);
- foreach(LegendCell cell in item.Cells)
- {
- if(cell.Text.Length > 0)
- {
- // #LEGENDTEXT - series name
- cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
- // Process rest of the keywords
- cell.Text = point.ReplaceKeywords(cell.Text);
- cell.ToolTip = point.ReplaceKeywords(cell.ToolTip);
- }
- }
- legendItems.Add(item);
- }
- }
- // Add item based on series name and fore color
- else
- {
- // Point should not be shown in the legend
- if(!series.IsVisibleInLegend)
- {
- continue;
- }
- // Create legend item
- LegendItem item = new LegendItem(series.Name, series.Color, "");
- item.SetAttributes(this.Common, series);
- item.ToolTip = series.ReplaceKeywords(series.LegendToolTip);
- if (series.LegendText.Length > 0)
- {
- item.Name = series.ReplaceKeywords(series.LegendText);
- }
- // Add legend item cells based on predefined columns
- item.AddAutomaticCells(this);
- foreach(LegendCell cell in item.Cells)
- {
- if(cell.Text.Length > 0)
- {
- // #LEGENDTEXT - series name
- cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
- // Process rest of the keywords
- cell.Text = series.ReplaceKeywords(cell.Text);
- cell.ToolTip = series.ReplaceKeywords(cell.ToolTip);
- }
- }
- legendItems.Add(item);
- }
- }
- }
- }
-
- // Check if series legend items should be reversed
- if (this.LegendItemOrder == LegendItemOrder.SameAsSeriesOrder ||
- (this.LegendItemOrder == LegendItemOrder.Auto && seriesWithReversedLegendItemsPresent))
- {
- // Reversed series generated legend items
- legendItems.Reverse();
- }
- // Add custom items
- foreach(LegendItem item in this._customLegends)
- {
- if(item.Enabled)
- {
- legendItems.Add(item);
- }
- }
- // Legend can't be empty at design time
- if(legendItems.Count == 0 && this.Common != null && this.Common.Chart != null)
- {
- if(this.Common.Chart.IsDesignMode())
- {
- LegendItem item = new LegendItem(this.Name + " - " + SR.DescriptionTypeEmpty, Color.White, "");
- item.ImageStyle = LegendImageStyle.Line;
- legendItems.Add(item);
- }
- }
- // Add legend item cells based on predefined columns
- foreach(LegendItem item in this.legendItems)
- {
- item.AddAutomaticCells(this);
- }
- }
- #endregion
- #region Legend painting methods
- /// <summary>
- /// Paints legend using chart graphics object.
- /// </summary>
- /// <param name="chartGraph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
- internal void Paint(ChartGraphics chartGraph )
- {
- // Reset some values
- this._offset = Size.Empty;
- this._itemColumns = 0;
- this._horizontalSpaceLeft = 0;
- this._verticalSpaceLeft = 0;
- this._subColumnSizes = null;
- this._numberOfRowsPerColumn = null;
- this._cellHeights = null;
- this.autofitFont = null;
- this._autoFitFontSizeAdjustment = 0;
- this._numberOfCells = -1;
- this._numberOfLegendItemsToProcess = -1;
- // Do nothing if legend disabled
- if(!this.IsEnabled() ||
- (this.MaximumAutoSize == 0f && this.Position.Auto))
- {
- return;
- }
- // Add all series legend into items collection and then add custom legend items
- FillLegendItemsCollection();
- // Clear all legend item cells information
- foreach(LegendItem legendItem in this.legendItems)
- {
- foreach(LegendCell cell in legendItem.Cells)
- {
- cell.ResetCache();
- }
- }
- // Call a notification event, so that legend items collection can be modified by user
- this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
- // Check if legend is empty
- if(this.legendItems.Count == 0)
- {
- return;
- }
- //***********************************************************
- //** RecalculateAxesScale legend information
- //***********************************************************
- this.RecalcLegendInfo(chartGraph);
-
- //***********************************************************
- //** Paint legend
- //***********************************************************
- // Call BackPaint event
- if( Common.ProcessModePaint )
- {
- // Draw legend background, border and shadow
- chartGraph.FillRectangleRel(
- chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
- BackColor,
- BackHatchStyle,
- BackImage,
- BackImageWrapMode,
- BackImageTransparentColor,
- BackImageAlignment,
- BackGradientStyle,
- BackSecondaryColor,
- BorderColor,
- this.GetBorderSize(),
- BorderDashStyle,
- ShadowColor,
- ShadowOffset,
- PenAlignment.Inset);
- Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
- }
- if( Common.ProcessModeRegions )
- {
- SelectLegendBackground();
- }
- //***********************************************************
- //** Draw legend header
- //***********************************************************
- this.DrawLegendHeader(chartGraph);
- //***********************************************************
- //** Draw legend title
- //***********************************************************
- this.DrawLegendTitle(chartGraph);
- // Add legend title hot region
- if( Common.ProcessModeRegions && !this._titlePosition.IsEmpty)
- {
- Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._titlePosition), this, ChartElementType.LegendTitle, true );
- }
- //***********************************************************
- //** Draw legend items
- //***********************************************************
- if(this._numberOfLegendItemsToProcess < 0)
- {
- this._numberOfLegendItemsToProcess = this.legendItems.Count;
- }
- for(int itemIndex = 0; itemIndex < this._numberOfLegendItemsToProcess; itemIndex++)
- {
- LegendItem legendItem = this.legendItems[itemIndex];
- // Iterate through legend item cells
- for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
- {
- // Get legend cell
- LegendCell legendCell = legendItem.Cells[cellIndex];
- // Paint cell
- legendCell.Paint(
- chartGraph,
- this._autoFitFontSizeAdjustment,
- this.autofitFont,
- this.singleWCharacterSize);
- }
- // Paint legend item separator
- if(legendItem.SeparatorType != LegendSeparatorStyle.None &&
- legendItem.Cells.Count > 0)
- {
- // Calculate separator position
- Rectangle separatorPosition = Rectangle.Empty;
- separatorPosition.X = legendItem.Cells[0].cellPosition.Left;
- // Find right most cell position excluding ovelapped cells that have negative size
- int right = 0;
- for(int index = legendItem.Cells.Count - 1; index >= 0; index--)
- {
- right = legendItem.Cells[index].cellPosition.Right;
- if(right > 0)
- {
- break;
- }
- }
- separatorPosition.Width = right - separatorPosition.X;
- separatorPosition.Y = legendItem.Cells[0].cellPosition.Bottom;
- separatorPosition.Height = this.GetSeparatorSize(legendItem.SeparatorType).Height;
- separatorPosition.Intersect(this._legendItemsAreaPosition);
- // Draw separator
- this.DrawSeparator(
- chartGraph,
- legendItem.SeparatorType,
- legendItem.SeparatorColor,
- true,
- separatorPosition);
- }
- }
- //***********************************************************
- //** If legend items are in multiple columns draw vertical
- //** separator
- //***********************************************************
- if(this.ItemColumnSeparator != LegendSeparatorStyle.None)
- {
- Rectangle separatorRect = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
- separatorRect.Y += this.GetBorderSize() + this._titlePosition.Height;
- separatorRect.Height -= 2 * this.GetBorderSize() + this._titlePosition.Height;
- separatorRect.X += this.GetBorderSize() + this._offset.Width;
- separatorRect.Width = this.GetSeparatorSize(this.ItemColumnSeparator).Width;
- if(this._horizontalSpaceLeft > 0)
- {
- separatorRect.X += this._horizontalSpaceLeft / 2;
- }
- // Check position
- if(separatorRect.Width > 0 && separatorRect.Height > 0)
- {
- // Iterate through all columns
- for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
- {
- // Iterate through all sub-columns
- int cellCount = this.GetNumberOfCells();
- for(int subColumnIndex = 0; subColumnIndex < cellCount; subColumnIndex++ )
- {
- separatorRect.X += this._subColumnSizes[columnIndex, subColumnIndex];
- }
- // Draw separator if not the last column
- if(columnIndex < this._itemColumns - 1)
- {
- this.DrawSeparator(chartGraph, this.ItemColumnSeparator, this.ItemColumnSeparatorColor, false, separatorRect);
- }
- // Add separator width
- separatorRect.X += separatorRect.Width;
- }
- }
- }
- //***********************************************************
- //** Draw special indicator on the bottom of the legend if
- //** it was truncated.
- //***********************************************************
- if(this._legendItemsTruncated &&
- this._legendItemsAreaPosition.Height > this._truncatedDotsSize / 2)
- {
- // Calculate dots step (no more than 10 pixel)
- int markerCount = 3;
- int step = (this._legendItemsAreaPosition.Width / 3) / markerCount;
- step = (int)Math.Min(step, 10);
- // Calculate start point
- PointF point = new PointF(
- this._legendItemsAreaPosition.X + this._legendItemsAreaPosition.Width / 2 - step * (float)Math.Floor(markerCount/2f),
- this._legendItemsAreaPosition.Bottom + (this._truncatedDotsSize + this._offset.Height) / 2);
- // Draw several dots at the bottom of the legend
- for(int index = 0; index < markerCount; index++)
- {
- chartGraph.DrawMarkerRel(
- chartGraph.GetRelativePoint(point),
- MarkerStyle.Circle,
- this._truncatedDotsSize,
- this.ForeColor,
- Color.Empty,
- 0,
- string.Empty,
- Color.Empty,
- 0,
- Color.Empty,
- RectangleF.Empty);
- // Shift to the right
- point.X += step;
- }
- }
- // Call Paint event
- if( Common.ProcessModePaint )
- {
- Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
- }
-
- // Remove temporary cells from legend items
- foreach(LegendItem legendItem in this.legendItems)
- {
- if(legendItem.clearTempCells)
- {
- legendItem.clearTempCells = false;
- legendItem.Cells.Clear();
- }
- }
- }
- #endregion
- #region Legend properties
- /// <summary>
- /// Gets or sets the name of the legend.
- /// </summary>
- [
- SRCategory("CategoryAttributeMisc"),
- Bindable(true),
- SRDescription("DescriptionAttributeLegend_Name"),
- NotifyParentPropertyAttribute(true)
- ]
- public override string Name
- {
- get
- {
- return base.Name;
- }
- set
- {
- base.Name = value;
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the name of the chart area where the legend
- /// should be docked.
- /// </summary>
- [
- SRCategory("CategoryAttributeDocking"),
- Bindable(true),
- DefaultValue(Constants.NotSetValue),
- SRDescription("DescriptionAttributeLegend_DockToChartArea"),
- TypeConverter(typeof(LegendAreaNameConverter)),
- NotifyParentPropertyAttribute(true)
- ]
- public string DockedToChartArea
- {
- get
- {
- return _dockedToChartArea;
- }
- set
- {
- if(value != _dockedToChartArea)
- {
- if (String.IsNullOrEmpty(value))
- {
- _dockedToChartArea = Constants.NotSetValue;
- }
- else
- {
- if (Chart != null && Chart.ChartAreas != null)
- {
- Chart.ChartAreas.VerifyNameReference(value);
- }
- _dockedToChartArea = value;
- }
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets a property which indicates whether
- /// the legend is docked inside the chart area.
- /// This property is only available when DockedToChartArea is set.
- /// </summary>
- [
- SRCategory("CategoryAttributeDocking"),
- Bindable(true),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLegend_DockInsideChartArea"),
- NotifyParentPropertyAttribute(true)
- ]
- public bool IsDockedInsideChartArea
- {
- get
- {
- return _isDockedInsideChartArea;
- }
- set
- {
- if(value != _isDockedInsideChartArea)
- {
- _isDockedInsideChartArea = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the position of the legend.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeLegend_Position"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ElementPositionConverter)),
- SerializationVisibilityAttribute(SerializationVisibility.Element)
- ]
- public ElementPosition Position
- {
- get
- {
- // Serialize only position values if Auto set to false
- if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
- {
- if(_position.Auto)
- {
- return new ElementPosition();
- }
- else
- {
- ElementPosition newPosition = new ElementPosition();
- newPosition.Auto = false;
- newPosition.SetPositionNoAuto(_position.X, _position.Y, _position.Width, _position.Height);
- return newPosition;
- }
- }
- return _position;
- }
- set
- {
- _position = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Determoines if this position should be serialized.
- /// </summary>
- /// <returns></returns>
- internal bool ShouldSerializePosition()
- {
- return !this.Position.Auto;
- }
- /// <summary>
- /// Gets or sets a property which indicates whether
- /// all legend items are equally spaced.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(false),
- SRDescription("DescriptionAttributeLegend_EquallySpacedItems"),
- NotifyParentPropertyAttribute(true)
- ]
- public bool IsEquallySpacedItems
- {
- get
- {
- return _isEquallySpacedItems;
- }
- set
- {
- _isEquallySpacedItems = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the legend is enabled.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLegend_Enabled"),
- NotifyParentPropertyAttribute(true),
- ParenthesizePropertyNameAttribute(true)
- ]
- public bool Enabled
- {
- get
- {
- return _enabled;
- }
- set
- {
- _enabled = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a value that indicates if legend text is automatically sized.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLegend_AutoFitText"),
- NotifyParentPropertyAttribute(true)
- ]
- public bool IsTextAutoFit
- {
- get
- {
- return _isTextAutoFit;
- }
- set
- {
- _isTextAutoFit = value;
- if(_isTextAutoFit)
- {
- // Reset the font size to "8"
- // Use current font family name ans style if possible.
- if(_font != null)
- {
- _font = _fontCache.GetFont(_font.FontFamily, 8, _font.Style); ;
- }
- else
- {
- _font = _fontCache.DefaultFont;
- }
- }
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend style.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(LegendStyle.Table),
- SRDescription("DescriptionAttributeLegend_LegendStyle"),
- NotifyParentPropertyAttribute(true),
- ParenthesizePropertyNameAttribute(true)
- ]
- public LegendStyle LegendStyle
- {
- get
- {
- return _legendStyle;
- }
- set
- {
- _legendStyle = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the minimum font size that can be used by the legend text's auto-fitting algorithm.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(7),
- SRDescription("DescriptionAttributeLegend_AutoFitMinFontSize"),
- ]
- public int AutoFitMinFontSize
- {
- get
- {
- return this._autoFitMinFontSize;
- }
- set
- {
- // Font size cannot be less than 5
- if(value < 5)
- {
- throw (new InvalidOperationException(SR.ExceptionLegendAutoFitMinFontSizeInvalid));
- }
- this._autoFitMinFontSize = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the maximum size (in percentage) of the legend used in the automatic layout algorithm.
- /// </summary>
- /// <remarks>
- /// If the legend is docked to the left or right, this property determines the maximum width of the legend, measured as a percentage.
- /// If the legend is docked to the top or bottom, this property determines the maximum height of the legend, measured as a percentage.
- /// </remarks>
- [
- SRCategory("CategoryAttributeDocking"),
- DefaultValue(50f),
- SRDescription("DescriptionAttributeLegend_MaxAutoSize"),
- ]
- public float MaximumAutoSize
- {
- get
- {
- return this._maximumLegendAutoSize;
- }
- set
- {
- if(value < 0f || value > 100f)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMaximumAutoSizeInvalid));
- }
- this._maximumLegendAutoSize = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets a collection of legend columns.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- SRDescription("DescriptionAttributeLegend_CellColumns"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- #if DESIGNER
- Editor(typeof(LegendCellColumnCollectionEditor), typeof(UITypeEditor)),
- #endif
- ]
- public LegendCellColumnCollection CellColumns
- {
- get
- {
- return this._cellColumns;
- }
- }
- /// <summary>
- /// Gets the legend table style.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(LegendTableStyle.Auto),
- SRDescription("DescriptionAttributeLegend_TableStyle"),
- NotifyParentPropertyAttribute(true),
- ParenthesizePropertyNameAttribute(true)
- ]
- public LegendTableStyle TableStyle
- {
- get
- {
- return this._legendTableStyle;
- }
- set
- {
- this._legendTableStyle = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets the legend header separator style.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- DefaultValue(typeof(LegendSeparatorStyle), "None"),
- SRDescription("DescriptionAttributeLegend_HeaderSeparator"),
- ]
- public LegendSeparatorStyle HeaderSeparator
- {
- get
- {
- return this._headerSeparator;
- }
- set
- {
- if(value != this._headerSeparator)
- {
- this._headerSeparator = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the color of the legend header separator.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegend_HeaderSeparatorColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color HeaderSeparatorColor
- {
- get
- {
- return this._headerSeparatorColor;
- }
- set
- {
- if(value != this._headerSeparatorColor)
- {
- this._headerSeparatorColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the separator style of the legend table columns.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- DefaultValue(typeof(LegendSeparatorStyle), "None"),
- SRDescription("DescriptionAttributeLegend_ItemColumnSeparator"),
- ]
- public LegendSeparatorStyle ItemColumnSeparator
- {
- get
- {
- return this._itemColumnSeparator;
- }
- set
- {
- if(value != this._itemColumnSeparator)
- {
- this._itemColumnSeparator = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the color of the separator of the legend table columns.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegend_ItemColumnSeparatorColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ItemColumnSeparatorColor
- {
- get
- {
- return this._itemColumnSeparatorColor;
- }
- set
- {
- if(value != this._itemColumnSeparatorColor)
- {
- this._itemColumnSeparatorColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the legend table column spacing, as a percentage of the legend text font.
- /// </summary>
- [
- SRCategory("CategoryAttributeCellColumns"),
- DefaultValue(50),
- SRDescription("DescriptionAttributeLegend_ItemColumnSpacing"),
- ]
- public int ItemColumnSpacing
- {
- get
- {
- return this._itemColumnSpacing;
- }
- set
- {
- if(value != this._itemColumnSpacing)
- {
- if(value < 0)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendColumnSpacingInvalid));
- }
- this._itemColumnSpacing = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the legend background color.
- /// </summary>
- [
- DefaultValue(typeof(Color), ""),
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeBackColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BackColor
- {
- get
- {
- return _backColor;
- }
- set
- {
- _backColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend border color.
- /// </summary>
- [
- DefaultValue(typeof(Color), ""),
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeBorderColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BorderColor
- {
- get
- {
- return _borderColor;
- }
- set
- {
- _borderColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend border style.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartDashStyle.Solid),
- SRDescription("DescriptionAttributeBorderDashStyle"),
- NotifyParentPropertyAttribute(true)
- ]
- public ChartDashStyle BorderDashStyle
- {
- get
- {
- return _borderDashStyle;
- }
- set
- {
- _borderDashStyle = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend border width.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(1),
- SRDescription("DescriptionAttributeBorderWidth"),
- NotifyParentPropertyAttribute(true)
- ]
- public int BorderWidth
- {
- get
- {
- return _borderWidth;
- }
- set
- {
- if(value < 0)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendBorderWidthIsNegative));
- }
- _borderWidth = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
-
- /// <summary>
- /// Gets or sets the legend background image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(""),
- SRDescription("DescriptionAttributeBackImage"),
- #if DESIGNER
- Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
- #endif
- NotifyParentPropertyAttribute(true)
- ]
- public string BackImage
- {
- get
- {
- return _backImage;
- }
- set
- {
- _backImage = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend background image drawing mode.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartImageWrapMode.Tile),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeImageWrapMode")
- ]
- public ChartImageWrapMode BackImageWrapMode
- {
- get
- {
- return _backImageWrapMode;
- }
- set
- {
- _backImageWrapMode = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeImageTransparentColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BackImageTransparentColor
- {
- get
- {
- return _backImageTransparentColor;
- }
- set
- {
- _backImageTransparentColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the background image alignment used for the unscaled drawing mode.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartImageAlignmentStyle.TopLeft),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeBackImageAlign")
- ]
- public ChartImageAlignmentStyle BackImageAlignment
- {
- get
- {
- return _backImageAlignment;
- }
- set
- {
- _backImageAlignment = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets background gradient style of the legend.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(GradientStyle.None),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeBackGradientStyle"),
- #if DESIGNER
- Editor(typeof(GradientEditor), typeof(UITypeEditor))
- #endif
- ]
- public GradientStyle BackGradientStyle
- {
- get
- {
- return _backGradientStyle;
- }
- set
- {
- _backGradientStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the secondary background color.
- /// <seealso cref="BackColor"/>
- /// <seealso cref="BackHatchStyle"/>
- /// <seealso cref="BackGradientStyle"/>
- /// </summary>
- /// <value>
- /// A <see cref="Color"/> value used for the secondary color of background with
- /// hatching or gradient fill.
- /// </value>
- /// <remarks>
- /// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
- /// <see cref="BackGradientStyle"/> are used.
- /// </remarks>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeBackSecondaryColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BackSecondaryColor
- {
- get
- {
- return _backSecondaryColor;
- }
- set
- {
- _backSecondaryColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the background hatch style.
- /// <seealso cref="BackSecondaryColor"/>
- /// <seealso cref="BackColor"/>
- /// <seealso cref="BackGradientStyle"/>
- /// </summary>
- /// <value>
- /// A <see cref="ChartHatchStyle"/> value used for the background.
- /// </value>
- /// <remarks>
- /// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
- /// </remarks>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartHatchStyle.None),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeBackHatchStyle"),
- #if DESIGNER
- Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
- #endif
- ]
- public ChartHatchStyle BackHatchStyle
- {
- get
- {
- return _backHatchStyle;
- }
- set
- {
- _backHatchStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the font of the legend text.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
- SRDescription("DescriptionAttributeLegend_Font"),
- NotifyParentPropertyAttribute(true)
- ]
- public Font Font
- {
- get
- {
- return _font;
- }
- set
- {
- this.IsTextAutoFit = false;
- _font = value;
- this.Invalidate(false);
- }
- }
- /// <summary>
- /// Gets or sets the color of the legend text.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegendFontColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ForeColor
- {
- get
- {
- return _foreColor;
- }
- set
- {
- _foreColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the text alignment.
- /// </summary>
- [
- SRCategory("CategoryAttributeDocking"),
- Bindable(true),
- DefaultValue(StringAlignment.Near),
- SRDescription("DescriptionAttributeLegend_Alignment"),
- NotifyParentPropertyAttribute(true)
- ]
- public StringAlignment Alignment
- {
- get
- {
- return _legendAlignment;
- }
- set
- {
- _legendAlignment = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
-
- /// <summary>
- /// Gets or sets the property that specifies where the legend docks.
- /// </summary>
- [
- SRCategory("CategoryAttributeDocking"),
- Bindable(true),
- DefaultValue(Docking.Right),
- SRDescription("DescriptionAttributeLegend_Docking"),
- NotifyParentPropertyAttribute(true)
- ]
- public Docking Docking
- {
- get
- {
- return _legendDocking;
- }
- set
- {
- _legendDocking = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the offset between the legend and its shadow.
- /// <seealso cref="ShadowColor"/>
- /// </summary>
- /// <value>
- /// An integer value that represents the offset between the legend and its shadow.
- /// </value>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(0),
- SRDescription("DescriptionAttributeShadowOffset"),
- NotifyParentPropertyAttribute(true)
- ]
- public int ShadowOffset
- {
- get
- {
- return _shadowOffset;
- }
- set
- {
- _shadowOffset = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the color of a legend's shadow.
- /// <seealso cref="ShadowOffset"/>
- /// </summary>
- /// <value>
- /// A <see cref="Color"/> value used to draw a legend's shadow.
- /// </value>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), "128, 0, 0, 0"),
- SRDescription("DescriptionAttributeShadowColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ShadowColor
- {
- get
- {
- return _shadowColor;
- }
- set
- {
- _shadowColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the name of the chart area name inside which the legend is drawn.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Browsable(false),
- Bindable(false),
- DefaultValue(Constants.NotSetValue),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeLegend_InsideChartArea"),
- EditorBrowsableAttribute(EditorBrowsableState.Never),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- TypeConverter(typeof(LegendAreaNameConverter))
- ]
- public string InsideChartArea
- {
- get
- {
- if(this.Common != null &&
- this.Common.Chart != null &&
- this.Common.Chart.serializing)
- {
- return "NotSet";
- }
- return this.DockedToChartArea;
- }
- set
- {
- if(value.Length == 0)
- {
- this.DockedToChartArea = Constants.NotSetValue;
- }
- else
- {
- this.DockedToChartArea = value;
- }
- this.Invalidate(false);
- }
- }
- /// <summary>
- /// Gets the custom legend items.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeLegend_CustomItems"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- #if DESIGNER
- Editor(typeof(LegendItemCollectionEditor), typeof(UITypeEditor))
- #endif
- ]
- public LegendItemsCollection CustomItems
- {
- get
- {
- return _customLegends;
- }
- }
- /// <summary>
- /// Gets or sets a property that defines the preferred number of characters in a line of the legend text.
- /// </summary>
- /// <remarks>
- /// When legend text exceeds the value defined in the <b>TextWrapThreshold</b> property, it will be
- /// automatically wrapped on the next whitespace. Text will not be wrapped if there is no whitespace
- /// characters in the text. Set this property to zero to disable the feature.
- /// </remarks>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(25),
- SRDescription("DescriptionAttributeLegend_TextWrapThreshold"),
- ]
- public int TextWrapThreshold
- {
- get
- {
- return this._textWrapThreshold;
- }
- set
- {
- if(value != this._textWrapThreshold)
- {
- if(value < 0)
- {
- throw (new ArgumentException(SR.ExceptionTextThresholdIsNegative, "value"));
- }
- this._textWrapThreshold = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets a property that specifies the order that legend items are shown. This property only affects
- /// legend items automatically added for the chart series and has no effect on custom legend items.
- /// </summary>
- /// <remarks>
- /// When the <b>LegendItemOrder</b> property is set to <b>Auto</b>, the legend will automatically be reversed
- /// if StackedColumn, StackedColumn100, StackedArea or StackedArea100 chart types are used.
- /// </remarks>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(LegendItemOrder.Auto),
- SRDescription("DescriptionAttributeLegend_Reversed"),
- ]
- public LegendItemOrder LegendItemOrder
- {
- get
- {
- return this._legendItemOrder;
- }
- set
- {
- if(value != this._legendItemOrder)
- {
- this._legendItemOrder = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether
- /// legend rows should be drawn with interlaced background color.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(false),
- SRDescription("DescriptionAttributeLegend_InterlacedRows"),
- ]
- public bool InterlacedRows
- {
- get
- {
- return this._interlacedRows;
- }
- set
- {
- if(value != this._interlacedRows)
- {
- this._interlacedRows = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the legend interlaced row's background color. Only applicable if interlaced rows are used.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeLegend_InterlacedRowsColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color InterlacedRowsColor
- {
- get
- {
- return this._interlacedRowsColor;
- }
- set
- {
- if(value != this._interlacedRowsColor)
- {
- this._interlacedRowsColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- #endregion
- #region Legend Title Properties
- /// <summary>
- /// Gets or sets the title text of the legend.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(""),
- SRDescription("DescriptionAttributeLegend_Title"),
- ]
- public string Title
- {
- get
- {
- return this._title;
- }
- set
- {
- if(value != this._title)
- {
- this._title = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the text color of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegend_TitleColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color TitleForeColor
- {
- get
- {
- return this._titleForeColor;
- }
- set
- {
- if(value != this._titleForeColor)
- {
- this._titleForeColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the background color of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeTitleBackColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color TitleBackColor
- {
- get
- {
- return this._titleBackColor;
- }
- set
- {
- if(value != this._titleBackColor)
- {
- this._titleBackColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the font of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt, style=Bold"),
- SRDescription("DescriptionAttributeTitleFont"),
- ]
- public Font TitleFont
- {
- get
- {
- return this._titleFont;
- }
- set
- {
- if(value != this._titleFont)
- {
- this._titleFont = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the text alignment of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(StringAlignment), "Center"),
- SRDescription("DescriptionAttributeLegend_TitleAlignment"),
- ]
- public StringAlignment TitleAlignment
- {
- get
- {
- return this._titleAlignment;
- }
- set
- {
- if(value != this._titleAlignment)
- {
- this._titleAlignment = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the separator style of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(LegendSeparatorStyle), "None"),
- SRDescription("DescriptionAttributeLegend_TitleSeparator"),
- ]
- public LegendSeparatorStyle TitleSeparator
- {
- get
- {
- return this._titleSeparator;
- }
- set
- {
- if(value != this._titleSeparator)
- {
- this._titleSeparator = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the separator color of the legend title.
- /// </summary>
- [
- SRCategory("CategoryAttributeTitle"),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegend_TitleSeparatorColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color TitleSeparatorColor
- {
- get
- {
- return this._titleSeparatorColor;
- }
- set
- {
- if(value != this._titleSeparatorColor)
- {
- this._titleSeparatorColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- #endregion // Legend Title Properties
- #region Legent Title and Header Helper methods
- /// <summary>
- /// Gets legend title size in relative coordinates.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <param name="titleMaxSize">Maximum possible legend title size.</param>
- /// <returns>Legend yitle size.</returns>
- private Size GetTitleSize(ChartGraphics chartGraph, Size titleMaxSize)
- {
- Size titleSize = Size.Empty;
- if(this.Title.Length > 0)
- {
- // Adjust available space
- titleMaxSize.Width -= this.GetBorderSize() * 2 + this._offset.Width;
- // Measure title text size
- titleSize = chartGraph.MeasureStringAbs(
- this.Title.Replace("\\n", "\n"),
- this.TitleFont,
- titleMaxSize,
- StringFormat.GenericTypographic);
- // Add text spacing
- titleSize.Height += this._offset.Height;
- titleSize.Width += this._offset.Width;
- // Add space required for the title separator
- titleSize.Height += this.GetSeparatorSize(this.TitleSeparator).Height;
- }
- return titleSize;
- }
- /// <summary>
- /// Gets legend header size in relative coordinates.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <param name="legendColumn">Legend column to get the header for.</param>
- /// <returns>Legend yitle size.</returns>
- private Size GetHeaderSize(ChartGraphics chartGraph, LegendCellColumn legendColumn)
- {
- Size headerSize = Size.Empty;
- if(legendColumn.HeaderText.Length > 0)
- {
- // Measure title text size
- headerSize = chartGraph.MeasureStringAbs(
- legendColumn.HeaderText.Replace("\\n", "\n") + "I",
- legendColumn.HeaderFont);
- // Add text spacing
- headerSize.Height += this._offset.Height;
- headerSize.Width += this._offset.Width;
- // Add space required for the title separator
- headerSize.Height += this.GetSeparatorSize(this.HeaderSeparator).Height;
- }
- return headerSize;
- }
- /// <summary>
- /// Draw Legend header.
- /// </summary>
- /// <param name="chartGraph">Chart graphics to draw the header on.</param>
- private void DrawLegendHeader(ChartGraphics chartGraph)
- {
- // Check if header should be drawn
- if(!this._headerPosition.IsEmpty &&
- this._headerPosition.Width > 0 &&
- this._headerPosition.Height > 0)
- {
- int prevRightLocation = -1;
- bool redrawLegendBorder = false;
- // Get Legend position
- Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
- legendPosition.Y += /*this.offset.Height + */this.GetBorderSize();
- legendPosition.Height -= 2 * (this._offset.Height + this.GetBorderSize());
- legendPosition.X += this.GetBorderSize();
- legendPosition.Width -= 2 * this.GetBorderSize();
- if(this.GetBorderSize() > 0)
- {
- ++legendPosition.Height;
- ++legendPosition.Width;
- }
- // Check if at least 1 column header has non-empty background color
- bool headerBackFill = false;
- for(int subColumnIndex = 0; subColumnIndex < this.CellColumns.Count; subColumnIndex++ )
- {
- LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
- if(!legendColumn.HeaderBackColor.IsEmpty)
- {
- headerBackFill = true;
- }
- }
- // Iterate through all columns
- for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
- {
- int columnStart = 0;
- int columnWidth = 0;
- // Iterate through all sub-columns
- int numberOfSubColumns = this._subColumnSizes.GetLength(1);
- for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++ )
- {
- // Calculate position of the header
- Rectangle rect = this._headerPosition;
- if(_horizontalSpaceLeft > 0)
- {
- rect.X += (int)(this._horizontalSpaceLeft / 2f);
- }
- if(prevRightLocation != -1)
- {
- rect.X = prevRightLocation;
- }
- rect.Width = this._subColumnSizes[columnIndex, subColumnIndex];
- prevRightLocation = rect.Right;
- // Remember column start position and update width
- if(subColumnIndex == 0)
- {
- columnStart = rect.Left;
- }
- columnWidth += rect.Width;
- // Make sure header position do not go outside of the legend
- rect.Intersect(legendPosition);
- if(rect.Width > 0 && rect.Height > 0)
- {
- // Define fill rectangle
- Rectangle fillRect = rect;
- // Make sure header fill riches legend top border
- if(this._titlePosition.Height <= 0)
- {
- fillRect.Y -= this._offset.Height;
- fillRect.Height += this._offset.Height;
- }
- // Stretch header fill rectangle and separators when vertical
- // separator are used or if there is 1 column with header background
- if( (this._itemColumns == 1 && headerBackFill) ||
- this.ItemColumnSeparator != LegendSeparatorStyle.None)
- {
- // For the first cell in the first column stretch filling
- // to the left side of the legend
- if(columnIndex == 0 && subColumnIndex == 0)
- {
- int newX = legendPosition.X;
- columnWidth += columnStart - newX;
- columnStart = newX;
- fillRect.Width += fillRect.X - legendPosition.X;
- fillRect.X = newX;
- }
- // For the last cell in the last column stretch filling
- // to the right side of the legend
- if(columnIndex == (this._itemColumns - 1) &&
- subColumnIndex == (numberOfSubColumns - 1) )
- {
- columnWidth += legendPosition.Right - fillRect.Right + 1;
- fillRect.Width += legendPosition.Right - fillRect.Right + 1;
- }
- // For the first cell of any column except the first one
- // make sure we also fill the item column spacing
- if(columnIndex != 0 && subColumnIndex == 0)
- {
- columnWidth += this._itemColumnSpacingRel / 2;
- columnStart -= this._itemColumnSpacingRel / 2;
- fillRect.Width += this._itemColumnSpacingRel / 2;
- fillRect.X -= this._itemColumnSpacingRel / 2;
- }
- // For the last cell in all columns except the last one
- // make sure we also fill the item column spacing
- if(columnIndex != (this._itemColumns - 1) &&
- subColumnIndex == (numberOfSubColumns - 1) )
- {
- columnWidth += this._itemColumnSpacingRel / 2;
- fillRect.Width += this._itemColumnSpacingRel / 2;
- }
- }
- if(subColumnIndex < this.CellColumns.Count)
- {
- // Draw header background
- LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
- if(!legendColumn.HeaderBackColor.IsEmpty)
- {
- redrawLegendBorder = true;
- // Fill title background
- if(fillRect.Right > legendPosition.Right)
- {
- fillRect.Width -= (legendPosition.Right - fillRect.Right);
- }
- if(fillRect.X < legendPosition.X)
- {
- fillRect.X += legendPosition.X - fillRect.X;
- fillRect.Width -= (legendPosition.X - fillRect.X);
- }
- fillRect.Intersect(legendPosition);
- chartGraph.FillRectangleRel(
- chartGraph.GetRelativeRectangle(fillRect),
- legendColumn.HeaderBackColor,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.None,
- Color.Empty,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- Color.Empty,
- 0,
- PenAlignment.Inset);
- }
- // Draw header text
- using(SolidBrush textBrush = new SolidBrush(legendColumn.HeaderForeColor))
- {
- // Set text alignment
- using (StringFormat format = new StringFormat())
- {
- format.Alignment = legendColumn.HeaderAlignment;
- format.LineAlignment = StringAlignment.Center;
- format.FormatFlags = StringFormatFlags.LineLimit;
- format.Trimming = StringTrimming.EllipsisCharacter;
- // Draw string using relative coordinates
- chartGraph.DrawStringRel(
- legendColumn.HeaderText,
- legendColumn.HeaderFont,
- textBrush,
- chartGraph.GetRelativeRectangle(rect),
- format);
- }
- }
- }
- }
- }
- // Draw header separator for each column
- Rectangle separatorRect = this._headerPosition;
- separatorRect.X = columnStart;
- separatorRect.Width = columnWidth;
- if(this.HeaderSeparator == LegendSeparatorStyle.Line || this.HeaderSeparator == LegendSeparatorStyle.DoubleLine)
- {
- // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than
- // any other line. Reduce width to solve the issue.
- legendPosition.Width -= 1;
- }
- separatorRect.Intersect(legendPosition);
- this.DrawSeparator(chartGraph, this.HeaderSeparator, this.HeaderSeparatorColor, true, separatorRect);
- // Add spacing between columns
- prevRightLocation += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
- }
-
- // Draw legend border to solve any issues with header background overlapping
- if(redrawLegendBorder)
- {
- chartGraph.FillRectangleRel(
- chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.None,
- Color.Empty,
- BorderColor,
- this.GetBorderSize(),
- BorderDashStyle,
- Color.Empty,
- 0,
- PenAlignment.Inset);
- }
-
- // Add legend header hot region
- if( Common.ProcessModeRegions && !this._headerPosition.IsEmpty)
- {
- Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._headerPosition), this, ChartElementType.LegendHeader, true );
- }
- }
- }
- /// <summary>
- /// Draw Legend title.
- /// </summary>
- /// <param name="chartGraph">Chart graphics to draw the title on.</param>
- private void DrawLegendTitle(ChartGraphics chartGraph)
- {
- // Check if title text is specified and position recalculated
- if(this.Title.Length > 0 &&
- !this._titlePosition.IsEmpty)
- {
- // Get Legend position
- Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
- legendPosition.Y += this.GetBorderSize();
- legendPosition.Height -= 2 * this.GetBorderSize();
- legendPosition.X += this.GetBorderSize();
- legendPosition.Width -= 2 * this.GetBorderSize();
- if(this.GetBorderSize() > 0)
- {
- ++legendPosition.Height;
- ++legendPosition.Width;
- }
- // Draw title background
- if(!this.TitleBackColor.IsEmpty)
- {
- // Fill title background
- Rectangle fillRect = this._titlePosition;
- fillRect.Intersect(legendPosition);
- chartGraph.FillRectangleRel(
- chartGraph.GetRelativeRectangle(fillRect),
- this.TitleBackColor,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.None,
- Color.Empty,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- Color.Empty,
- 0,
- PenAlignment.Inset);
- }
- // Draw title text
- using(SolidBrush textBrush = new SolidBrush(this.TitleForeColor))
- {
- // Set text alignment
- StringFormat format = new StringFormat();
- format.Alignment = this.TitleAlignment;
- //format.LineAlignment = StringAlignment.Center;
- // Shift text rectangle by the top offset amount
- Rectangle rect = this._titlePosition;
- rect.Y += this._offset.Height;
- rect.X += this._offset.Width;
- rect.X += this.GetBorderSize();
- rect.Width -= this.GetBorderSize() * 2 + this._offset.Width;
- // Draw string using relative coordinates
- rect.Intersect(legendPosition);
- chartGraph.DrawStringRel(
- this.Title.Replace("\\n", "\n"),
- this.TitleFont,
- textBrush,
- chartGraph.GetRelativeRectangle(rect),
- format);
- }
- // Draw title separator
- Rectangle separatorPosition = this._titlePosition;
- if(this.TitleSeparator == LegendSeparatorStyle.Line || this.TitleSeparator == LegendSeparatorStyle.DoubleLine)
- {
- // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than
- // any other line. Reduce width to solve the issue.
- legendPosition.Width -= 1;
- }
- separatorPosition.Intersect(legendPosition);
- this.DrawSeparator(chartGraph, this.TitleSeparator, this.TitleSeparatorColor, true, separatorPosition);
- // Draw legend border to solve any issues with title background overlapping
- if(!this.TitleBackColor.IsEmpty ||
- this.TitleSeparator != LegendSeparatorStyle.None)
- {
- chartGraph.FillRectangleRel(
- chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.None,
- Color.Empty,
- BorderColor,
- this.GetBorderSize(),
- BorderDashStyle,
- Color.Empty,
- 0,
- PenAlignment.Inset);
- }
- }
- }
- /// <summary>
- /// Gets legend separator size in pixels
- /// </summary>
- /// <param name="separatorType">Separator type.</param>
- /// <returns>Separator size in relative coordinates.</returns>
- internal Size GetSeparatorSize(LegendSeparatorStyle separatorType)
- {
- Size size = Size.Empty;
- if(separatorType == LegendSeparatorStyle.None)
- {
- size = Size.Empty;
- }
- else if(separatorType == LegendSeparatorStyle.Line)
- {
- size = new Size(1, 1);
- }
- else if(separatorType == LegendSeparatorStyle.DashLine)
- {
- size = new Size(1, 1);
- }
- else if(separatorType == LegendSeparatorStyle.DotLine)
- {
- size = new Size(1, 1);
- }
- else if(separatorType == LegendSeparatorStyle.ThickLine)
- {
- size = new Size(2, 2);
- }
- else if(separatorType == LegendSeparatorStyle.DoubleLine)
- {
- size = new Size(3, 3);
- }
- else if(separatorType == LegendSeparatorStyle.GradientLine)
- {
- size = new Size(1, 1);
- }
- else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
- {
- size = new Size(2, 2);
- }
- else
- {
- throw (new InvalidOperationException(SR.ExceptionLegendSeparatorTypeUnknown(separatorType.ToString())));
- }
- // For the vertical part of the separator always add additiobal spacing
- size.Width += this._itemColumnSpacingRel;
- return size;
- }
- /// <summary>
- /// Draws specified legend separator.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <param name="separatorType">Separator type.</param>
- /// <param name="color">Separator color.</param>
- /// <param name="horizontal">Flag that determines if separator is vertical or horizontal.</param>
- /// <param name="position">Separator position.</param>
- private void DrawSeparator(
- ChartGraphics chartGraph,
- LegendSeparatorStyle separatorType,
- Color color,
- bool horizontal,
- Rectangle position)
- {
- // Temporary disable antialiasing
- SmoothingMode oldSmoothingMode = chartGraph.SmoothingMode;
- chartGraph.SmoothingMode = SmoothingMode.None;
- // Get line position in absolute coordinates
- RectangleF rect = position;
- if(!horizontal)
- {
- rect.X += (int)(_itemColumnSpacingRel / 2f);
- rect.Width -= _itemColumnSpacingRel;
- }
- if(separatorType == LegendSeparatorStyle.Line)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Left, rect.Bottom - 1),
- new PointF(rect.Right, rect.Bottom - 1) );
- }
- else
- {
- // Draw vertical line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Right - 1, rect.Top),
- new PointF(rect.Right - 1, rect.Bottom) );
- }
- }
- else if(separatorType == LegendSeparatorStyle.DashLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Dash,
- new PointF(rect.Left, rect.Bottom - 1),
- new PointF(rect.Right, rect.Bottom - 1) );
- }
- else
- {
- // Draw vertical line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Dash,
- new PointF(rect.Right - 1, rect.Top),
- new PointF(rect.Right - 1, rect.Bottom) );
- }
- }
- else if(separatorType == LegendSeparatorStyle.DotLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Dot,
- new PointF(rect.Left, rect.Bottom - 1),
- new PointF(rect.Right, rect.Bottom - 1) );
- }
- else
- {
- // Draw vertical line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Dot,
- new PointF(rect.Right - 1, rect.Top),
- new PointF(rect.Right - 1, rect.Bottom) );
- }
- }
- else if(separatorType == LegendSeparatorStyle.ThickLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.DrawLineAbs(
- color,
- 2,
- ChartDashStyle.Solid,
- new PointF(rect.Left, rect.Bottom - 1f),
- new PointF(rect.Right, rect.Bottom - 1f) );
- }
- else
- {
- // Draw vertical line separator
- chartGraph.DrawLineAbs(
- color,
- 2,
- ChartDashStyle.Solid,
- new PointF(rect.Right - 1f, rect.Top),
- new PointF(rect.Right - 1f, rect.Bottom) );
- }
- }
- else if(separatorType == LegendSeparatorStyle.DoubleLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Left, rect.Bottom - 3),
- new PointF(rect.Right, rect.Bottom - 3) );
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Left, rect.Bottom - 1),
- new PointF(rect.Right, rect.Bottom - 1) );
- }
- else
- {
- // Draw vertical line separator
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Right - 3, rect.Top),
- new PointF(rect.Right - 3, rect.Bottom) );
- chartGraph.DrawLineAbs(
- color,
- 1,
- ChartDashStyle.Solid,
- new PointF(rect.Right - 1, rect.Top),
- new PointF(rect.Right - 1, rect.Bottom) );
- }
- }
- else if(separatorType == LegendSeparatorStyle.GradientLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.FillRectangleAbs(
- new RectangleF(rect.Left, rect.Bottom - 1f, rect.Width, 0f),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.VerticalCenter,
- color,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- PenAlignment.Inset);
- }
- else
- {
- // Draw vertical line separator
- chartGraph.FillRectangleAbs(
- new RectangleF(rect.Right - 1f, rect.Top, 0f, rect.Height),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.HorizontalCenter,
- color,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- PenAlignment.Inset);
- }
- }
- else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
- {
- if(horizontal)
- {
- // Draw horizontal line separator
- chartGraph.FillRectangleAbs(
- new RectangleF(rect.Left, rect.Bottom - 2f, rect.Width, 1f),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.VerticalCenter,
- color,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- PenAlignment.Inset);
- }
- else
- {
- // Draw vertical line separator
- chartGraph.FillRectangleAbs(
- new RectangleF(rect.Right - 2f, rect.Top, 1f, rect.Height),
- Color.Transparent,
- ChartHatchStyle.None,
- string.Empty,
- ChartImageWrapMode.Tile,
- Color.Empty,
- ChartImageAlignmentStyle.Center,
- GradientStyle.HorizontalCenter,
- color,
- Color.Empty,
- 0,
- ChartDashStyle.NotSet,
- PenAlignment.Inset);
- }
- }
- // Restore smoothing
- chartGraph.SmoothingMode = oldSmoothingMode;
- }
- #endregion // Legent Title Helper methods
- #region Helper methods
- /// <summary>
- /// Get visible legend border size.
- /// </summary>
- /// <returns>Visible legend border size.</returns>
- private int GetBorderSize()
- {
- if(this.BorderWidth > 0 &&
- this.BorderDashStyle != ChartDashStyle.NotSet &&
- !this.BorderColor.IsEmpty &&
- this.BorderColor != Color.Transparent)
- {
- return this.BorderWidth;
- }
- return 0;
- }
- /// <summary>
- /// Helper method which returns current legend table style.
- /// </summary>
- /// <param name="chartGraph">Chart graphics.</param>
- /// <returns>Legend table style.</returns>
- private LegendTableStyle GetLegendTableStyle(ChartGraphics chartGraph)
- {
- LegendTableStyle style = this.TableStyle;
- if(this.TableStyle == LegendTableStyle.Auto)
- {
- if(this.Position.Auto)
- {
- // If legend is automatically positioned, use docking
- // do determine preffered table style
- if(this.Docking == Docking.Left ||
- this.Docking == Docking.Right)
- {
- return LegendTableStyle.Tall;
- }
- else
- {
- return LegendTableStyle.Wide;
- }
- }
- else
- {
- // If legend is custom positioned, use legend width and heiht
- // to determine the best table layout.
- SizeF legendPixelSize = chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()).Size;
- if(legendPixelSize.Width < legendPixelSize.Height)
- {
- return LegendTableStyle.Tall;
- }
- else
- {
- return LegendTableStyle.Wide;
- }
- }
- }
-
- return style;
- }
- /// <summary>
- /// Helper method that checks if legend is enabled.
- /// </summary>
- /// <returns>True if legend is enabled.</returns>
- internal bool IsEnabled()
- {
- if(this.Enabled)
- {
- // Check if legend is docked to the chart area
- if(this.DockedToChartArea.Length > 0 &&
- this.Common != null &&
- this.Common.ChartPicture != null)
- {
- if(this.Common.ChartPicture.ChartAreas.IndexOf(this.DockedToChartArea) >= 0)
- {
- // Do not show legend when it is docked to invisible chart area
- ChartArea area = this.Common.ChartPicture.ChartAreas[this.DockedToChartArea];
- if(!area.Visible)
- {
- return false;
- }
- }
- }
-
- return true;
- }
- return false;
- }
- /// <summary>
- /// Invalidate chart legend when one of the properties is changed
- /// </summary>
- /// <param name="invalidateLegendOnly">Indicates that only legend area should be invalidated.</param>
- [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the WinForms version of Chart")]
- internal void Invalidate(bool invalidateLegendOnly)
- {
- if(Chart != null && !Chart.disableInvalidates)
- {
- if(invalidateLegendOnly)
- {
- // Calculate the position of the legend
- Rectangle invalRect = Chart.ClientRectangle;
- if(this.Position.Width != 0 && this.Position.Height != 0 )
- {
- // Convert relative coordinates to absolute coordinates
- invalRect.X = (int)(this.Position.X * (this.Common.ChartPicture.Width - 1) / 100F);
- invalRect.Y = (int)(this.Position.Y * (this.Common.ChartPicture.Height - 1) / 100F);
- invalRect.Width = (int)(this.Position.Width * (this.Common.ChartPicture.Width - 1) / 100F);
- invalRect.Height = (int)(this.Position.Height * (this.Common.ChartPicture.Height - 1) / 100F);
- // Inflate rectangle size using border size and shadow size
- invalRect.Inflate(this.BorderWidth + this.ShadowOffset + 1, this.BorderWidth + this.ShadowOffset + 1);
- }
- // Invalidate legend rectangle only
- Chart.dirtyFlag = true;
- Chart.Invalidate(invalRect);
- }
- else
- {
- Invalidate();
- }
- }
- }
- #endregion
- #region IDisposable Members
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- //Free managed resources
- if (_fontCache != null)
- {
- _fontCache.Dispose();
- _fontCache = null;
- }
- if (legendItems != null)
- {
- legendItems.Dispose();
- legendItems = null;
- }
- if (_cellColumns != null)
- {
- _cellColumns.Dispose();
- _cellColumns = null;
- }
- if (_customLegends != null)
- {
- _customLegends.Dispose();
- _customLegends = null;
- }
- if (_position != null)
- {
- _position.Dispose();
- _position = null;
- }
- }
- }
- #endregion
- }
- /// <summary>
- /// The LegendCollection class is a strongly typed collection of legends.
- /// </summary>
- [
- SRDescription("DescriptionAttributeLegendCollection_LegendCollection"),
- ]
- public class LegendCollection : ChartNamedElementCollection<Legend>
- {
- #region Constructors
- /// <summary>
- /// LegendCollection constructor.
- /// </summary>
- /// <param name="chartPicture">Chart picture object.</param>
- internal LegendCollection(ChartPicture chartPicture)
- : base(chartPicture)
- {
- }
- #endregion
- #region Properties
- /// <summary>
- /// Gets the default legend name.
- /// </summary>
- internal string DefaultNameReference
- {
- get { return this.Count > 0 ? this[0].Name : String.Empty; }
- }
- #endregion
- #region Methods
- /// <summary>
- /// Creates a new Legend with the specified name and adds it to the collection.
- /// </summary>
- /// <param name="name">The new chart area name.</param>
- /// <returns>New legend</returns>
- public Legend Add(string name)
- {
- Legend legend = new Legend(name);
- this.Add(legend);
- return legend;
- }
- /// <summary>
- /// Recalculates legend position in the collection.
- /// </summary>
- /// <param name="chartGraph">Chart graphics used.</param>
- /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
- /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
- internal void CalcLegendPosition(
- ChartGraphics chartGraph,
- ref RectangleF chartAreasRectangle,
- float elementSpacing)
- {
- // Loop through all legends
- foreach(Legend legend in this)
- {
- // Calculate position of the legends docked to the chart picture
- if(legend.IsEnabled() &&
- legend.DockedToChartArea == Constants.NotSetValue &&
- legend.Position.Auto)
- {
- legend.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
- }
- }
- }
- /// <summary>
- /// Recalculates legend position in the collection for legends docked outside of chart area.
- /// </summary>
- /// <param name="chartGraph">Chart graphics used.</param>
- /// <param name="area">Area the legend is docked to.</param>
- /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
- /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
- internal void CalcOutsideLegendPosition(
- ChartGraphics chartGraph,
- ChartArea area,
- ref RectangleF chartAreasRectangle,
- float elementSpacing)
- {
- if(Common != null && Common.ChartPicture != null)
- {
- // Get elemets spacing
- float areaSpacing = Math.Min((chartAreasRectangle.Height/100F) * elementSpacing, (chartAreasRectangle.Width/100F) * elementSpacing);
- // Loop through all legends
- foreach(Legend legend in this)
- {
- // Check if all chart area names are valid
- if (legend.DockedToChartArea != Constants.NotSetValue && this.Chart.ChartAreas.IndexOf(legend.DockedToChartArea)<0)
- {
- throw (new ArgumentException(SR.ExceptionLegendDockedChartAreaIsMissing((string)legend.DockedToChartArea)));
- }
- // Process only legends docked to specified area
- if(legend.IsEnabled() &&
- legend.IsDockedInsideChartArea == false &&
- legend.DockedToChartArea == area.Name &&
- legend.Position.Auto)
- {
- // Calculate legend position
- legend.CalcLegendPosition(chartGraph,
- ref chartAreasRectangle,
- areaSpacing);
- // Adjust legend position
- RectangleF legendPosition = legend.Position.ToRectangleF();
- if(legend.Docking == Docking.Top)
- {
- legendPosition.Y -= areaSpacing;
- if(!area.Position.Auto)
- {
- legendPosition.Y -= legendPosition.Height;
- }
- }
- else if(legend.Docking == Docking.Bottom)
- {
- legendPosition.Y += areaSpacing;
- if(!area.Position.Auto)
- {
- legendPosition.Y = area.Position.Bottom + areaSpacing;
- }
- }
- if(legend.Docking == Docking.Left)
- {
- legendPosition.X -= areaSpacing;
- if(!area.Position.Auto)
- {
- legendPosition.X -= legendPosition.Width;
- }
- }
- if(legend.Docking == Docking.Right)
- {
- legendPosition.X += areaSpacing;
- if(!area.Position.Auto)
- {
- legendPosition.X = area.Position.Right + areaSpacing;
- }
- }
- legend.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
- }
- }
- }
- }
- /// <summary>
- /// Recalculates legend position inside chart area in the collection.
- /// </summary>
- /// <param name="chartGraph">Chart graphics used.</param>
- /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
- internal void CalcInsideLegendPosition(
- ChartGraphics chartGraph,
- float elementSpacing)
- {
- if(Common != null && Common.ChartPicture != null)
- {
- // Check if all chart area names are valid
- foreach(Legend legend in this)
- {
- if (legend.DockedToChartArea != Constants.NotSetValue)
- {
- try
- {
- ChartArea area = Common.ChartPicture.ChartAreas[legend.DockedToChartArea];
- }
- catch
- {
- throw(new ArgumentException( SR.ExceptionLegendDockedChartAreaIsMissing( (string)legend.DockedToChartArea ) ) );
- }
- }
- }
- // Loop through all chart areas
- foreach (ChartArea area in Common.ChartPicture.ChartAreas)
- {
- // Check if chart area is visible
- if(area.Visible)
- {
- // Get area position
- RectangleF legendPlottingRectangle = area.PlotAreaPosition.ToRectangleF();
- // Get elemets spacing
- float areaSpacing = Math.Min((legendPlottingRectangle.Height/100F) * elementSpacing, (legendPlottingRectangle.Width/100F) * elementSpacing);
- // Loop through all legends
- foreach(Legend legend in this)
- {
- if(legend.IsEnabled() &&
- legend.IsDockedInsideChartArea == true &&
- legend.DockedToChartArea == area.Name &&
- legend.Position.Auto)
- {
- // Calculate legend position
- legend.CalcLegendPosition(chartGraph,
- ref legendPlottingRectangle,
- areaSpacing);
- }
- }
- }
- }
- }
- }
- #endregion
- #region Event handlers
- internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
- {
- //If all the chart areas are removed and then the first one is added we don't want to dock the legends
- if (e.OldElement == null)
- return;
- foreach (Legend legend in this)
- if (legend.DockedToChartArea == e.OldName)
- legend.DockedToChartArea = e.NewName;
- }
- #endregion
- }
- /// <summary>
- /// The LegendItemsCollection class is a strongly typed collection of legend items.
- /// </summary>
- [
- SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
- ]
- public class LegendItemsCollection : ChartElementCollection<LegendItem>
- {
- #region Constructors
- /// <summary>
- /// LegendItemsCollection constructor
- /// </summary>
- internal LegendItemsCollection(Legend legend)
- : base(legend)
- {
- }
- #endregion
- #region Methods
- /// <summary>
- /// Adds a legend item into the collection.
- /// </summary>
- /// <param name="color">Legend item color.</param>
- /// <param name="text">Legend item text.</param>
- /// <returns>Index of newly added item.</returns>
- public int Add(Color color, string text)
- {
- LegendItem item = new LegendItem(text, color, "");
- Add(item);
- return Count - 1;
- }
- /// <summary>
- /// Insert a legend item into the collection.
- /// </summary>
- /// <param name="index">Index to insert at.</param>
- /// <param name="color">Legend item color.</param>
- /// <param name="text">Legend item text.</param>
- /// <returns>Index of newly added item.</returns>
- public void Insert(int index, Color color, string text)
- {
- LegendItem item = new LegendItem(text, color, "");
- this.Insert(index, item);
- }
- /// <summary>
- /// Adds a legend item into the collection.
- /// </summary>
- /// <param name="image">Legend item image.</param>
- /// <param name="text">Legend item text.</param>
- /// <returns>Index of newly added item.</returns>
- public int Add(string image, string text)
- {
- LegendItem item = new LegendItem(text, Color.Empty, image);
- Add(item);
- return Count-1;
- }
- /// <summary>
- /// Insert one legend item into the collection.
- /// </summary>
- /// <param name="index">Index to insert at.</param>
- /// <param name="image">Legend item image.</param>
- /// <param name="text">Legend item text.</param>
- /// <returns>Index of newly added item.</returns>
- public void Insert(int index, string image, string text)
- {
- LegendItem item = new LegendItem(text, Color.Empty, image);
- this.Insert(index, item);
- }
- /// <summary>
- /// Reverses the order of items in the collection.
- /// </summary>
- public void Reverse()
- {
- List<LegendItem> list = this.Items as List<LegendItem>;
- list.Reverse();
- Invalidate();
- }
- #endregion
- }
- /// <summary>
- /// The LegendItem class represents a single item (row) in the legend.
- /// It contains properties which describe visual appearance and
- /// content of the legend item.
- /// </summary>
- [
- SRDescription("DescriptionAttributeLegendItem_LegendItem"),
- DefaultProperty("Name")
- ]
- public class LegendItem : ChartNamedElement
- {
- #region Fields
- // Private data members, which store properties values
- private Color _color = Color.Empty;
- private string _image = "";
- private string _seriesName = "";
- private int _seriesPointIndex = -1;
- // Chart image map properties
- private string _toolTip = "";
-
- // Additional appearance properties
- internal LegendImageStyle style = LegendImageStyle.Rectangle;
- internal GradientStyle backGradientStyle = GradientStyle.None;
- internal Color backSecondaryColor = Color.Empty;
- internal Color backImageTransparentColor = Color.Empty;
- internal Color borderColor = Color.Black;
- internal int borderWidth = 1;
- internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid;
- internal ChartHatchStyle backHatchStyle = ChartHatchStyle.None;
- internal int shadowOffset = 0;
- internal Color shadowColor = Color.FromArgb(128, 0, 0, 0);
- internal ChartImageWrapMode backImageWrapMode = ChartImageWrapMode.Tile;
- internal ChartImageAlignmentStyle backImageAlign = ChartImageAlignmentStyle.TopLeft;
- // Marker properties
- internal MarkerStyle markerStyle = MarkerStyle.None;
- internal int markerSize = 5;
- internal string markerImage = "";
- internal Color markerImageTransparentColor = Color.Empty;
- internal Color markerColor = Color.Empty;
- internal Color markerBorderColor = Color.Empty;
- // True if legend item is enabled.
- private bool _enabled = true;
- // Series marker border width
- private int _markerBorderWidth = 1;
- // Collection of legend item cells
- private LegendCellCollection _cells = null;
- // Legend item visual separator
- private LegendSeparatorStyle _separatorType = LegendSeparatorStyle.None;
- // Legend item visual separator color
- private Color _separatorColor = Color.Black;
- // Indicates that temporary cells where added and thet have to be removed
- internal bool clearTempCells = false;
- #endregion
- #region Constructors
- /// <summary>
- /// LegendItem constructor
- /// </summary>
- public LegendItem()
- {
- // Create collection of legend item cells
- this._cells = new LegendCellCollection(this);
- }
- /// <summary>
- /// LegendItem constructor
- /// </summary>
- /// <param name="name">Item name.</param>
- /// <param name="color">Item color.</param>
- /// <param name="image">Item image.</param>
- public LegendItem(string name, Color color, string image) : base (name)
- {
- this._color = color;
- this._image = image;
- // Create collection of legend item cells
- this._cells = new LegendCellCollection(this);
- }
- #endregion
- #region Legend item properties
- /// <summary>
- /// Gets the Legend object which the item belongs to.
- /// </summary>
- [
- Bindable(false),
- Browsable(false),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- ]
- public Legend Legend
- {
- get
- {
- if (Parent != null)
- return Parent.Parent as Legend;
- else
- return null;
- }
- }
- /// <summary>
- /// Gets or sets the name of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeLegendItem_Name"),
- NotifyParentPropertyAttribute(true),
- ParenthesizePropertyNameAttribute(true)
- ]
- public override string Name
- {
- get
- {
- return base.Name;
- }
- set
- {
- base.Name = value;
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the color of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeLegendItem_Color"),
- DefaultValue(typeof(Color), ""),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color Color
- {
- get
- {
- return _color;
- }
- set
- {
- _color = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a string value that represents a URL to an image file, which will be used for the legend item's symbol.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeLegendItem_Image"),
- DefaultValue(""),
- #if DESIGNER
- Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
- #endif
- NotifyParentPropertyAttribute(true)
- ]
- public string Image
- {
- get
- {
- return _image;
- }
- set
- {
- _image = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the picture style of the legend item image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(LegendImageStyle), "Rectangle"),
- SRDescription("DescriptionAttributeLegendItem_Style"),
- ParenthesizePropertyNameAttribute(true)
- ]
- public LegendImageStyle ImageStyle
- {
- get
- {
- return style;
- }
- set
- {
- style = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the border color of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeBorderColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BorderColor
- {
- get
- {
- return borderColor;
- }
- set
- {
- borderColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the background hatch style of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartHatchStyle.None),
- SRDescription("DescriptionAttributeBackHatchStyle"),
- #if DESIGNER
- Editor(typeof(HatchStyleEditor), typeof(UITypeEditor))
- #endif
- ]
- public ChartHatchStyle BackHatchStyle
- {
- get
- {
- return backHatchStyle;
- }
- set
- {
- backHatchStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeImageTransparentColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BackImageTransparentColor
- {
- get
- {
- return backImageTransparentColor;
- }
- set
- {
- backImageTransparentColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets background gradient style of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(GradientStyle.None),
- SRDescription("DescriptionAttributeBackGradientStyle"),
- #if DESIGNER
- Editor(typeof(GradientEditor), typeof(UITypeEditor))
- #endif
- ]
- public GradientStyle BackGradientStyle
- {
- get
- {
- return backGradientStyle;
- }
- set
- {
- backGradientStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the secondary background color.
- /// <seealso cref="Color"/>
- /// <seealso cref="BackHatchStyle"/>
- /// <seealso cref="BackGradientStyle"/>
- /// </summary>
- /// <value>
- /// A <see cref="Color"/> value used for the secondary color of background with
- /// hatching or gradient fill.
- /// </value>
- /// <remarks>
- /// This color is used with <see cref="Color"/> when <see cref="BackHatchStyle"/> or
- /// <see cref="BackGradientStyle"/> are used.
- /// </remarks>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeBackSecondaryColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color BackSecondaryColor
- {
- get
- {
- return backSecondaryColor;
- }
- set
- {
- if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
- {
- throw (new ArgumentException(SR.ExceptionBackSecondaryColorIsTransparent));
- }
- backSecondaryColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the border width of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(1),
- SRDescription("DescriptionAttributeBorderWidth"),
- ]
- public int BorderWidth
- {
- get
- {
- return borderWidth;
- }
- set
- {
- if(value < 0)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsZero));
- }
- borderWidth = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the Legend item is enabled.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLegendItem_Enabled"),
- ParenthesizePropertyNameAttribute(true),
- ]
- public bool Enabled
- {
- get
- {
- return this._enabled;
- }
- set
- {
- this._enabled = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the marker border width of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- DefaultValue(1),
- SRDescription("DescriptionAttributeMarkerBorderWidth"),
- ]
- public int MarkerBorderWidth
- {
- get
- {
- return this._markerBorderWidth;
- }
- set
- {
- if(value < 0)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMarkerBorderWidthIsNegative));
- }
- this._markerBorderWidth = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the legend item border style.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(ChartDashStyle.Solid),
- SRDescription("DescriptionAttributeBorderDashStyle"),
- ]
- public ChartDashStyle BorderDashStyle
- {
- get
- {
- return borderDashStyle;
- }
- set
- {
- borderDashStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the offset between the legend item and its shadow.
- /// <seealso cref="ShadowColor"/>
- /// </summary>
- /// <value>
- /// An integer value that represents the offset between the legend item and its shadow.
- /// </value>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- SRDescription("DescriptionAttributeShadowOffset"),
- DefaultValue(0)
- ]
- public int ShadowOffset
- {
- get
- {
- return shadowOffset;
- }
- set
- {
- shadowOffset = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the color of a legend item's shadow.
- /// <seealso cref="ShadowOffset"/>
- /// </summary>
- /// <value>
- /// A <see cref="Color"/> value used to draw a legend item's shadow.
- /// </value>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), "128,0,0,0"),
- SRDescription("DescriptionAttributeShadowColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ShadowColor
- {
- get
- {
- return shadowColor;
- }
- set
- {
- shadowColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the marker style of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(MarkerStyle.None),
- SRDescription("DescriptionAttributeLegendItem_MarkerStyle"),
- #if DESIGNER
- Editor(typeof(MarkerStyleEditor), typeof(UITypeEditor)),
- #endif
- RefreshProperties(RefreshProperties.All)
- ]
- public MarkerStyle MarkerStyle
- {
- get
- {
- return markerStyle;
- }
- set
- {
- markerStyle = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the marker size of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(5),
- SRDescription("DescriptionAttributeLegendItem_MarkerSize"),
- RefreshProperties(RefreshProperties.All)
- ]
- public int MarkerSize
- {
- get
- {
- return markerSize;
- }
- set
- {
- markerSize = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the marker image of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(""),
- SRDescription("DescriptionAttributeMarkerImage"),
- #if DESIGNER
- Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
- #endif
- RefreshProperties(RefreshProperties.All)
- ]
- public string MarkerImage
- {
- get
- {
- return markerImage;
- }
- set
- {
- markerImage = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a color which will be replaced with a transparent color while drawing the marker image.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeImageTransparentColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
- #endif
- RefreshProperties(RefreshProperties.All)
- ]
- public Color MarkerImageTransparentColor
- {
- get
- {
- return markerImageTransparentColor;
- }
- set
- {
- markerImageTransparentColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
-
- /// <summary>
- /// Gets or sets the marker color of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeLegendItem_MarkerColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
- #endif
- RefreshProperties(RefreshProperties.All)
- ]
- public Color MarkerColor
- {
- get
- {
- return markerColor;
- }
- set
- {
- markerColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
-
- /// <summary>
- /// Gets or sets the marker border color of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeMarker"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeMarkerBorderColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor)),
- #endif
- RefreshProperties(RefreshProperties.All)
- ]
- public Color MarkerBorderColor
- {
- get
- {
- return markerBorderColor;
- }
- set
- {
- markerBorderColor = value;
- this.Invalidate(true);
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the series name of the legend item..
- /// </summary>
- [
- Browsable(false),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- SRDescription("DescriptionAttributeLegendItem_SeriesName"),
- DefaultValue("")
- ]
- public string SeriesName
- {
- get
- {
- return _seriesName;
- }
- set
- {
- _seriesName = value;
- }
- }
- /// <summary>
- /// Gets or sets the index of the legend item's associated DataPoint object.
- /// </summary>
- [
- Browsable(false),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- SRDescription("DescriptionAttributeLegendItem_SeriesPointIndex"),
- DefaultValue(-1)
- ]
- public int SeriesPointIndex
- {
- get
- {
- return _seriesPointIndex;
- }
- set
- {
- _seriesPointIndex = value;
- }
- }
- /// <summary>
- /// Gets or sets the separator style of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(typeof(LegendSeparatorStyle), "None"),
- SRDescription("DescriptionAttributeLegendItem_Separator"),
- ]
- public LegendSeparatorStyle SeparatorType
- {
- get
- {
- return this._separatorType;
- }
- set
- {
- if(value != this._separatorType)
- {
- this._separatorType = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// Gets or sets the separator color of the legend item.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeLegendItem_SeparatorColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color SeparatorColor
- {
- get
- {
- return this._separatorColor;
- }
- set
- {
- if(value != this._separatorColor)
- {
- this._separatorColor = value;
- this.Invalidate(false);
- CallOnModifing();
- }
- }
- }
- /// <summary>
- /// The LegendCellCollection class is a collection of legend item cells.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- SRDescription("DescriptionAttributeLegendItem_Cells"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- #if DESIGNER
- Editor(typeof(LegendCollectionEditor), typeof(UITypeEditor))
- #endif
- ]
- public LegendCellCollection Cells
- {
- get
- {
- return this._cells;
- }
- }
- #endregion
- #region IMapAreaAttributesutes Properties implementation
- /// <summary>
- /// Tooltip of the area.
- /// </summary>
- [
- SRCategory("CategoryAttributeMapArea"),
- Bindable(true),
- SRDescription("DescriptionAttributeToolTip"),
- DefaultValue("")
- ]
- public string ToolTip
- {
- set
- {
- _toolTip = value;
- if(Chart != null && Chart.selection != null)
- {
- Chart.selection.enabledChecked = false;
- }
- }
- get
- {
- return _toolTip;
- }
- }
- #endregion
- #region Helper methods
- /// <summary>
- /// Helper method adds default legend item cells based on the columns
- /// specified. If columns collection is empty we assume the presence of
- /// two columns: series marker and legend item text.
- /// </summary>
- /// <param name="legend">Legend this item belongs to.</param>
- internal void AddAutomaticCells(Legend legend)
- {
- // Check if cells defined
- if(this.Cells.Count == 0)
- {
- // Check if legend item was generated for the series
- if(this.SeriesName.Length > 0)
- {
- // If legend do not have any columns set add a series marker
- // and legend text cells
- if(legend.CellColumns.Count == 0)
- {
- // VSTS 96787 - Text Direction (RTL/LTR)
- if (legend.Common != null && legend.Common.ChartPicture.RightToLeft == RightToLeft.Yes)
- {
- this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
- this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
- }
- else
- {
- this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
- this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
- }
- }
- else
- {
- // Add cell for each of the columns
- foreach(LegendCellColumn legendColumn in legend.CellColumns)
- {
- this.Cells.Add(legendColumn.CreateNewCell());
- }
- }
- }
- else
- {
- // Add Marker plus text for everything else
- this.clearTempCells = true;
- this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
- this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
- }
- }
- }
- /// <summary>
- /// Sets legend item properties from the series
- /// </summary>
- /// <param name="series">Series object.</param>
- /// <param name="common">Common elements object.</param>
- internal void SetAttributes(CommonElements common, Series series)
- {
- // Get legend item picture style
- IChartType chartType = common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
- style = chartType.GetLegendImageStyle(series);
- // Set series name
- _seriesName = series.Name;
- // Get shadow properties
- shadowOffset = series.ShadowOffset;
- shadowColor = series.ShadowColor;
- // Check if series is drawn in 3D chart area
- bool area3D = common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
- // Get other properties
- SetAttributes((DataPointCustomProperties) series, area3D);
- }
- /// <summary>
- /// Sets legend item properties from the DataPointCustomProperties object.
- /// </summary>
- /// <param name="properties">DataPointCustomProperties object.</param>
- /// <param name="area3D">Element belongs to the 3D area.</param>
- internal void SetAttributes(DataPointCustomProperties properties, bool area3D)
- {
- borderColor = properties.BorderColor;
- borderWidth = properties.BorderWidth;
- borderDashStyle = properties.BorderDashStyle;
- markerStyle = properties.MarkerStyle;
- markerSize = properties.MarkerSize;
- markerImage = properties.MarkerImage;
- markerImageTransparentColor = properties.MarkerImageTransparentColor;
- markerColor = properties.MarkerColor;
- markerBorderColor = properties.MarkerBorderColor;
- this._markerBorderWidth = properties.MarkerBorderWidth;
-
- float dpi = 96;
- if(Common != null)
- dpi = Common.graph.Graphics.DpiX;
-
- int maxBorderWidth = (int)Math.Round((2 * dpi) / 96);
- if (this._markerBorderWidth > maxBorderWidth)
- {
- this._markerBorderWidth = maxBorderWidth;
- }
- if(properties.MarkerBorderWidth <= 0)
- {
- markerBorderColor = Color.Transparent;
- }
- // Improve readability of the line series marker by using at least 2 pixel wide lines
- if(this.style == LegendImageStyle.Line &&
- borderWidth <= (int)Math.Round(dpi / 96) )
- {
- borderWidth = maxBorderWidth;
- }
- if(!area3D)
- {
- backGradientStyle = properties.BackGradientStyle;
- backSecondaryColor = properties.BackSecondaryColor;
- backImageTransparentColor = properties.BackImageTransparentColor;
- backImageWrapMode = properties.BackImageWrapMode;
- backImageAlign = properties.BackImageAlignment;
- backHatchStyle = properties.BackHatchStyle;
- }
- }
- /// <summary>
- /// Invalidate chart (or just legend )when collection is changed
- /// </summary>
- [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the WinForms version of Chart")]
- private void Invalidate(bool invalidateLegendOnly)
- {
- if(Legend != null)
- {
- // Invalidate control
- Legend.Invalidate(invalidateLegendOnly);
- }
- }
- #endregion
- #region IDisposable Members
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_cells != null)
- {
- _cells.Dispose();
- _cells = null;
- }
- }
- base.Dispose(disposing);
- }
- #endregion
- }
- }
|