Anda dapat membuat halaman dokumentasi untuk buat pada modul Scribunto ini.
Penyunting dapat melakukan uji coba pada halaman bak pasir (buat | cermin) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
Penyunting dapat melakukan uji coba pada halaman bak pasir (buat | cermin) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
--[[ keywords are used for languages: they are the names of the actual parameters of the template ]] localkeywords={ barChart='bar chart', pieChart='pie chart', width='width', height='height', stack='stack', colors='colors', group='group', xlegend='x legends', yticks='y tick marks', tooltip='tooltip', accumulateTooltip='tooltip value accumulation', links='links', defcolor='default color', scalePerGroup='scale per group', unitsPrefix='units prefix', unitsSuffix='units suffix', groupNames='group names', hideGroupLegends='hide group legends', slices='slices', slice='slice', radius='radius', percent='percent', }-- here is what you want to translate localdefColors=mw.loadData("Module:Chart/Default colors") localhideGroupLegends localfunctionnulOrWhitespace(s) returnnotsormw.text.trim(s)=='' end localfunctioncreateGroupList(tab,legends,cols) if#legends>1andnothideGroupLegendsthen table.insert(tab,mw.text.tag('div')) locallist={} localspanStyle="padding:0 1em;color:inherit;background-color:%s;border:1px solid %s;margin-right:1em;-webkit-print-color-adjust:exact;" forgi=1,#legendsdo localspan=mw.text.tag('span',{style=string.format(spanStyle,cols[gi],cols[gi])},' ')..' '..legends[gi] table.insert(list,mw.text.tag('li',{},span)) end table.insert(tab, mw.text.tag('ul', {style="list-style:none;column-width:12em;"}, table.concat(list,'\n') ) ) table.insert(tab,'</div>') end end localfunctionpieChart(frame) localres,imslices,args={},{},frame.args localradius localvalues,colors,names,legends,links={},{},{},{},{} localdelimiter=args.delimiteror':' locallang=mw.getContentLanguage() localfunctiongetArg(s,def,subst,with) localresult=args[keywords[s]]ordefor'' ifsubstandwiththenresult=string.gsub(result,subst,with)end returnresult end localfunctionanalyzeParams() localfunctionaddSlice(i,slice) localvalue,name,color,link=unpack(mw.text.split(slice,'%s*'..delimiter..'%s*')) values[i]=tonumber(lang:parseFormattedNumber(value)) orerror(string.format('Slice %d: "%s", first item("%s") could not be parsed as a number',i,valueor'',slice)) colors[i]=notnulOrWhitespace(color)andcolorordefColors[i*2] names[i]=nameor'' links[i]=link end radius=getArg('radius',150) hideGroupLegends=notnulOrWhitespace(args[keywords.hideGroupLegends]) localslicesStr=getArg('slices') localprefix=getArg('unitsPrefix','','_',' ') localsuffix=getArg('unitsSuffix','','_',' ') localpercent=args[keywords.percent] localsum=0 locali=0 forsliceinstring.gmatch(slicesStror'',"%b()")do i=i+1 addSlice(i,string.match(slice,'^%(%s*(.-)%s*%)$')) end fork,vinpairs(args)do localind=string.match(k,'^'..keywords.slice..'%s+(%d+)$') ifindthenaddSlice(tonumber(ind),v)end end for_,valinipairs(values)dosum=sum+valend fori,valueinipairs(values)do localaddprec=percentandstring.format(' (%0.1f%%)',value/sum*100)or'' legends[i]=string.format('%s: %s%s%s%s',names[i],prefix,lang:formatNum(value),suffix,addprec) links[i]=mw.text.trim(links[i]orstring.format('[[#noSuchAnchor|%s]]',legends[i])) end end localfunctionaddRes(...) for_,vinpairs({...})do table.insert(res,v) end end localfunctioncreateImageMap() addRes('{{#tag:imagemap|','File:Circle frame.svg{{!}}'..(radius*2)..'px') addRes(unpack(imslices)) addRes('desc none','}}') end localfunctiondrawSlice(i,q,start) localcolor=colors[i] localangle=start*2*math.pi localsin,cos=math.abs(math.sin(angle)),math.abs(math.cos(angle)) localwsin,wcos=sin*radius,cos*radius locals1,s2,w1,w2,w3,w4,border ifq==1then border='left' w1,w2,w3,w4=0,0,wsin,wcos s1,s2='bottom','left' elseifq==2then border='bottom' w1,w2,w3,w4=0,wcos,wsin,0 s1,s2='bottom','right' elseifq==3then border='right' w1,w2,w3,w4=wsin,wcos,0,0 s1,s2='top','right' else border='top' w1,w2,w3,w4=wsin,0,0,wcos s1,s2='top','left' end localstyle=string.format('border:solid transparent;position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx',s1,radius,s2,radius,radius,radius) ifstart<=(q-1)*0.25then style=string.format('%s;border:0;background-color:%s',style,color) else style=string.format('%s;border-width:%spx %spx %spx %spx;border-%s-color:%s',style,w1,w2,w3,w4,border,color) end addRes(mw.text.tag('div',{style=style},'')) end localfunctioncreateSlices() localfunctioncoordsOfAngle(angle) return(100+math.floor(100*math.cos(angle)))..' '..(100-math.floor(100*math.sin(angle))) end localsum,start=0,0 for_,valueinipairs(values)dosum=sum+valueend fori,valueinipairs(values)do localpoly={'poly 100 100'} localstartC,endC=start/sum,(start+value)/sum localstartQ,endQ=math.floor(startC*4+1),math.floor(endC*4+1) forq=startQ,math.min(endQ,4)dodrawSlice(i,q,startC)end forangle=startC*2*math.pi,endC*2*math.pi,0.02do table.insert(poly,coordsOfAngle(angle)) end table.insert(poly,coordsOfAngle(endC*2*math.pi)..' 100 100 '..links[i]) table.insert(imslices,table.concat(poly,' ')) start=start+values[i] end end analyzeParams() if#values==0thenerror("no slices found - can't draw pie chart")end addRes(mw.text.tag('div',{class='chart noresize',style=string.format('margin-top:0.5em;max-width:%spx;',radius*2)})) addRes(mw.text.tag('div',{style=string.format('position:relative;min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;',radius*2,radius*2,radius*2)})) createSlices() addRes(mw.text.tag('div',{style=string.format('position:absolute;min-width:%spx;min-height:%spx;overflow:hidden;',radius*2,radius*2)})) createImageMap() addRes('</div>')-- close "position:relative" div that contains slices and imagemap. addRes('</div>')-- close "position:relative" div that contains slices and imagemap. createGroupList(res,legends,colors)-- legends addRes('</div>')-- close containing div returnframe:preprocess(table.concat(res,'\n')) end localfunctionbarChart(frame) localres={} localargs=frame.args-- can be changed to frame:getParent().args localvalues,xlegends,colors,tooltips,yscales={},{},{},{},{} localgroupNames,unitsSuffix,unitsPrefix,links={},{},{},{} localwidth,height,yticks,stack,delimiter=500,350,-1,false,args.delimiteror':' localchartWidth,chartHeight,defcolor,scalePerGroup,accumulateTooltip localnumGroups,numValues localscaleWidth localfunctionvalidate() localfunctionasGroups(name,tab,toDuplicate,emptyOK) if#tab==0andnotemptyOKthen error("must supply values for "..keywords[name]) end if#tab==1andtoDuplicatethen fori=2,numGroupsdotab[i]=tab[1]end end if#tab>0and#tab~=numGroupsthen error(keywords[name]..' harus berisi jumlah item yang sama dengan jumlah grup, tetapi berisi '..#tab..' items and there are '..numGroups..' groups') end end -- do all sorts of validation here, so we can assume all params are good from now on. -- among other things, replace numerical values with mw.language:parseFormattedNumber() result chartHeight=height-80 numGroups=#values numValues=#values[1] defcolor=defcoloror'blue' colors[1]=colors[1]ordefcolor scaleWidth=scalePerGroupand80*numGroupsor100 chartWidth=width-scaleWidth asGroups('unitsPrefix',unitsPrefix,true,true) asGroups('unitsSuffix',unitsSuffix,true,true) asGroups('colors',colors,true,true) asGroups('groupNames',groupNames,false,false) ifstackandscalePerGroupthen error(string.format('Illegal settings: %s and %s are incompatible.',keywords.stack,keywords.scalePerGroup)) end forgi=2,numGroupsdo if#values[gi]~=numValuesthenerror(keywords.group.." "..gi.." does not have same number of values as "..keywords.group.." 1")end end if#xlegends~=numValuesthenerror('Illegal number of '..keywords.xlegend..'. Seharusnya persis '..numValues..' bukan '..#xlegends)end end localfunctionextractParams() localfunctiontestone(keyword,key,val,tab) locali=keyword==keyand0orkey:match(keyword.."%s+(%d+)") ifnotithenreturnend i=tonumber(i)orerror("Expect numerical index for key "..keyword.." instead of '"..key.."'") ifi>0thentab[i]={}end forsinmw.text.gsplit(val,'%s*'..delimiter..'%s*')do table.insert(i==0andtabortab[i],s) end returntrue end fork,vinpairs(args)do ifk==keywords.widththen width=tonumber(v) ifnotwidthorwidth<200then error('Nilai lebar tidak diperbolehkan (harus berupa angka, dan minimal 200): '..v) end elseifk==keywords.heightthen height=tonumber(v) ifnotheightorheight<200then error('Nilai tinggi tidak diperbolehkan (harus berupa angka, dan minimal 200): '..v) end elseifk==keywords.stackthenstack=true elseifk==keywords.yticksthenyticks=tonumber(v)or-1 elseifk==keywords.scalePerGroupthenscalePerGroup=true elseifk==keywords.defcolorthendefcolor=v elseifk==keywords.accumulateTooltipthenaccumulateTooltip=notnulOrWhitespace(v) elseifk==keywords.hideGroupLegendsthenhideGroupLegends=notnulOrWhitespace(v) else forkeyword,tabinpairs({ group=values, xlegend=xlegends, colors=colors, tooltip=tooltips, unitsPrefix=unitsPrefix, unitsSuffix=unitsSuffix, groupNames=groupNames, links=links, })do iftestone(keywords[keyword],k,v,tab) thenbreak end end end end end localfunctionroundup(x)-- returns the next round number: eg., for 30 to 39.999 will return 40, for 3000 to 3999.99 wil return 4000. for 10 - 14.999 will return 15. localordermag=10^math.floor(math.log10(x)) localnormalized=x/ordermag localtop=normalized>=1.5and(math.floor(normalized+1))or1.5 returnordermag*top,top,ordermag end localfunctioncalcHeightLimits()-- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet. ifstackthen localsums={} for_,groupinpairs(values)do fori,valinipairs(group)dosums[i]=(sums[i]or0)+valend end localsum=math.max(unpack(sums)) fori=1,#valuesdoyscales[i]=sumend else fori,groupinipairs(values)doyscales[i]=math.max(unpack(group))end end fori,scaleinipairs(yscales)doyscales[i]=roundup(scale*0.9999)end ifnotscalePerGroupthenfori=1,#valuesdoyscales[i]=math.max(unpack(yscales))endend end localfunctiontooltip(gi,i,val) iftooltipsandtooltips[gi]andnotnulOrWhitespace(tooltips[gi][i])thenreturntooltips[gi][i],trueend localgroupName=mw.text.killMarkers(notnulOrWhitespace(groupNames[gi])andgroupNames[gi]..': 'or'') localprefix=unitsPrefix[gi]orunitsPrefix[1]or'' localsuffix=unitsSuffix[gi]orunitsSuffix[1]or'' returnstring.gsub(groupName..prefix..mw.getContentLanguage():formatNum(tonumber(val)or0)..suffix,'_',' '),false end localfunctioncalcHeights(gi,i,val) localbarHeight=math.max(2,math.floor(val/yscales[gi]*chartHeight+0.5))-- add half to make it "round" instead of "trunc", min height to 2 to avoid negative bar sizes localtop,base=chartHeight-barHeight,0 ifstackthen forj=1,gi-1do iftonumber(values[j][i])>0then base=base+math.max(2,math.floor(values[j][i]/yscales[gi]*chartHeight+0.5))-- sum the "i" value of all the groups below our group, gi, and keep the same calculation for each bar end end end returnbarHeight,top-base end localfunctiongroupBounds(i) localsetWidth=math.floor(chartWidth/numValues) localsetOffset=(i-1)*setWidth returnsetOffset,setWidth end localfunctioncalcx(gi,i) localsetOffset,setWidth=groupBounds(i) ifstackornumGroups==1then localbarWidth=math.min(38,math.floor(0.8*setWidth)) returnsetOffset+(setWidth-barWidth)/2,barWidth end setWidth=0.85*setWidth localbarWidth=math.floor(0.75*setWidth/numGroups) localleft=setOffset+math.floor((gi-1)/numGroups*setWidth) returnleft,barWidth end localfunctiondrawbar(gi,i,val,ttval) ifval=='0'thenreturnend-- do not show single line (borders....) if value is 0, or rather, '0'. see talkpage localcolor,tooltip,custom=colors[gi]ordefcoloror'blue',tooltip(gi,i,ttvalorval) localleft,barWidth=calcx(gi,i) localbarHeight,top=calcHeights(gi,i,val) -- borders so it shows up when printing localstyle=string.format("position:absolute;left:%spx;top:%spx;height:%spx;min-width:%spx;max-width:%spx;color:inherit;background-color:%s;-webkit-print-color-adjust:exact;border:1px solid %s;border-bottom:none;overflow:hidden;", left,top,barHeight-1,barWidth-2,barWidth-2,color,color) locallink=links[gi]andlinks[gi][i]or'' localimg=notnulOrWhitespace(link)andstring.format('[[Berkas:Transparent.png|1000px|link=%s|%s]]',link,customandtooltipor'')or'' table.insert(res,mw.text.tag('div',{style=style,title=tooltip,},img)) end localfunctiondrawYScale() localfunctiondrawSingle(gi,color,width,yticks,single) localyscale=yscales[gi] local_,top,ordermag=roundup(yscale*0.999) localnumnotches=yticks>=0andyticksor (top<=1.5andtop*4 ortop<4andtop*2 ortop) localvalStyleStr= singleand'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;padding:0 2px' or'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;left:3px;background-color:%s;color:white;font-weight:bold;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;padding:0 2px' localnotchStyleStr='position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;' fori=1,numnotchesdo localval=i/numnotches*yscale localy=chartHeight-calcHeights(gi,1,val) localdiv=mw.text.tag('div',{style=string.format(valStyleStr,width-10,y-10,color)},mw.getContentLanguage():formatNum(tonumber(val)or0)) table.insert(res,div) div=mw.text.tag('div',{style=string.format(notchStyleStr,y,width-4,color)},'') table.insert(res,div) end end ifscalePerGroupthen localcolWidth=80 localcolStyle="position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s" forgi=1,numGroupsdo localleft=(gi-1)*colWidth localcolor=colors[gi]ordefcolor table.insert(res,mw.text.tag('div',{style=string.format(colStyle,chartHeight,colWidth,left,color,color)})) drawSingle(gi,color,colWidth,yticks) table.insert(res,'</div>') end else drawSingle(1,'black',scaleWidth,yticks,true) end end localfunctiondrawXlegends() localsetOffset,setWidth locallegendDivStyleFormat="position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;" localtickDivstyleFormat="position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;" fori=1,numValuesdo ifnotnulOrWhitespace(xlegends[i])then setOffset,setWidth=groupBounds(i) -- setWidth = 0.85 * setWidth table.insert(res,mw.text.tag('div',{style=string.format(legendDivStyleFormat,setOffset+1,setWidth-2,setWidth-2)},xlegends[i]or'')) table.insert(res,mw.text.tag('div',{style=string.format(tickDivstyleFormat,setOffset+setWidth/2)},'')) end end end localfunctiondrawChart() table.insert(res,mw.text.tag('div',{class='chart noresize',style=string.format('padding-top:10px;margin-top:1em;max-width:%spx;',width)})) table.insert(res,mw.text.tag('div',{style=string.format("position:relative;min-height:%spx;min-width:%spx;max-width:%spx;",height,width,width)})) table.insert(res,mw.text.tag('div',{style=string.format("float:right;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;border-left:1px black solid;border-bottom:1px black solid;",chartHeight,chartWidth,chartWidth)})) localacum=stackandaccumulateTooltipand{} forgi,groupinpairs(values)do fori,valinipairs(group)do ifacumthenacum[i]=(acum[i]or0)+valend drawbar(gi,i,val,acumandacum[i]) end end table.insert(res,'</div>') table.insert(res,mw.text.tag('div',{style=string.format("position:absolute;height:%spx;min-width:%spx;max-width:%spx;",chartHeight,scaleWidth,scaleWidth,scaleWidth)})) drawYScale() table.insert(res,'</div>') table.insert(res,mw.text.tag('div',{style=string.format("position:absolute;top:%spx;left:%spx;width:%spx;",chartHeight,scaleWidth,chartWidth)})) drawXlegends() table.insert(res,'</div>') table.insert(res,'</div>') createGroupList(res,groupNames,colors) table.insert(res,'</div>') end extractParams() validate() calcHeightLimits() drawChart() returntable.concat(res,"\n") end return{ ['bar-chart']=barChart, [keywords.barChart]=barChart, [keywords.pieChart]=pieChart, }