├── .gitignore ├── ChartJSWrapper ├── CW │ ├── Assets │ │ ├── Chart.js │ │ ├── Chart.min.js │ │ ├── cw.html │ │ ├── cw.js │ │ └── datasets.js │ ├── CW.h │ ├── CWBarChart.h │ ├── CWBarChart.m │ ├── CWBarChartData.h │ ├── CWBarChartData.m │ ├── CWBarChartOptions.h │ ├── CWBarChartOptions.m │ ├── CWBarDataSet.h │ ├── CWBarDataSet.m │ ├── CWBoolean.h │ ├── CWBoolean.m │ ├── CWChart.h │ ├── CWChart.m │ ├── CWColors.h │ ├── CWColors.m │ ├── CWData.h │ ├── CWData.m │ ├── CWDataSet.h │ ├── CWDataSet.m │ ├── CWDoughnutChart.h │ ├── CWDoughnutChart.m │ ├── CWGlobalOptions.h │ ├── CWGlobalOptions.m │ ├── CWLabelledData.h │ ├── CWLabelledData.m │ ├── CWLineChart.h │ ├── CWLineChart.m │ ├── CWLineChartData.h │ ├── CWLineChartData.m │ ├── CWLineChartOptions.h │ ├── CWLineChartOptions.m │ ├── CWObject.h │ ├── CWObject.m │ ├── CWPieChart.h │ ├── CWPieChart.m │ ├── CWPieChartOptions.h │ ├── CWPieChartOptions.m │ ├── CWPointDataSet.h │ ├── CWPointDataSet.m │ ├── CWPolarAreaChart.h │ ├── CWPolarAreaChart.m │ ├── CWPolarAreaChartOptions.h │ ├── CWPolarAreaChartOptions.m │ ├── CWRadarChart.h │ ├── CWRadarChart.m │ ├── CWRadarChartData.h │ ├── CWRadarChartData.m │ ├── CWRadarChartOptions.h │ ├── CWRadarChartOptions.m │ ├── CWSegmentData.h │ ├── CWSegmentData.m │ └── CWTypes.h ├── ChartJSWrapper-IOS │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── PullDownMenu │ │ ├── PulldownMenu.h │ │ └── PulldownMenu.m │ ├── ViewController.h │ ├── ViewController.m │ ├── img.png │ ├── main.m │ └── settings@2x.png ├── ChartJSWrapper.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── ChartJSWrapper │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── PullDownMenu │ ├── PulldownMenu.h │ └── PulldownMenu.m ├── LICENSE ├── README.md └── doc └── sample.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/Assets/Chart.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Chart.js 3 | * http://chartjs.org/ 4 | * Version: 1.0.2 5 | * 6 | * Copyright 2015 Nick Downie 7 | * Released under the MIT license 8 | * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md 9 | */ 10 | (function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(".")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),st?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),tthis.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;ip&&(p=t.x+s,n=i),t.x-sp&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'
    <% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<% for (var i=0; i
  • <%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)0&&ithis.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.ythis.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'
      <% for (var i=0; i
    • <%if(segments[i].label){%><%=segments[i].label%><%}%>
    • <%}%>
    '};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this); -------------------------------------------------------------------------------- /ChartJSWrapper/CW/Assets/cw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CWCharts 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/Assets/cw.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function addPointData(chartId, dataStr, label) { 4 | var chart = window[chartId]; 5 | var data = JSON.parse(dataStr); 6 | chart.addData(data,label); 7 | return 'OK' 8 | } 9 | 10 | function setPointValue(chartId, dataset, index, value) { 11 | var chart = window[chartId]; 12 | chart.datasets[dataset].points[index].value = value; 13 | return 'OK' 14 | } 15 | 16 | function removePointData(chartId) { 17 | var chart = window[chartId]; 18 | chart.removeData(); 19 | return 'OK' 20 | } 21 | 22 | function setBarValue(chartId, dataset, index, value) { 23 | var chart = window[chartId]; 24 | chart.datasets[dataset].bars[index].value = value; 25 | return 'OK' 26 | } 27 | 28 | function setSegmentValue(chartId, segment, value) { 29 | var chart = window[chartId]; 30 | chart.segments[segment].value = value; 31 | return 'OK' 32 | } 33 | 34 | function addSegmentData(chartId, segment, index) { 35 | var chart = window[chartId]; 36 | var data = JSON.parse(segment); 37 | chart.addData(data,index); 38 | return 'OK' 39 | } 40 | 41 | function removeSegmentData(chartId, index) { 42 | var chart = window[chartId]; 43 | chart.removeData(index); 44 | return 'OK' 45 | } 46 | 47 | function updateChart(chartId) { 48 | var chart = window[chartId]; 49 | chart.update(); 50 | return 'OK' 51 | } 52 | 53 | function deleteChart(chartId) { 54 | var chart = window[chartId]; 55 | chart.destroy(); 56 | var canvas = document.getElementById(chartId+'_canvas'); 57 | var div = document.getElementById(chartId+'_div'); 58 | div.removeChild(canvas); 59 | document.body.removeChild(div); 60 | delete window[chartId]; 61 | return 'OK'; 62 | } 63 | 64 | function createContext(chartId, chartWidth,chartHeight) { 65 | var div = document.createElement('div'); 66 | // document.body.appendChild(div); 67 | document.body.insertBefore(div,document.body.firstChild); 68 | div.id = chartId+'_div'; 69 | div.style.height='100%'; 70 | div.style.width='100%'; 71 | var canvas = document.createElement('canvas'); 72 | div.appendChild(canvas); 73 | canvas.id = chartId+'_canvas'; 74 | canvas.width = chartWidth; 75 | canvas.height = chartHeight; 76 | var ctx = canvas.getContext('2d'); 77 | return ctx; 78 | } 79 | 80 | function addLineChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 81 | var data = JSON.parse(chartData); 82 | var options = JSON.parse(chartOptions); 83 | 84 | var ctx = createContext(chartId,chartWidth,chartHeight); 85 | 86 | var chart = new Chart(ctx).Line(data,options); 87 | window[chartId] = chart; 88 | return 'OK'; 89 | } 90 | 91 | function addRadarChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 92 | var data = JSON.parse(chartData); 93 | var options = JSON.parse(chartOptions); 94 | 95 | var ctx = createContext(chartId,chartWidth,chartHeight); 96 | 97 | var chart = new Chart(ctx).Radar(data,options); 98 | window[chartId] = chart; 99 | return 'OK'; 100 | } 101 | 102 | function addBarChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 103 | var data = JSON.parse(chartData); 104 | var options = JSON.parse(chartOptions); 105 | 106 | var ctx = createContext(chartId,chartWidth,chartHeight); 107 | 108 | var chart = new Chart(ctx).Bar(data,options); 109 | window[chartId] = chart; 110 | return 'OK'; 111 | } 112 | 113 | function addPolarAreaChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 114 | var data = JSON.parse(chartData); 115 | var options = JSON.parse(chartOptions); 116 | 117 | var ctx = createContext(chartId,chartWidth,chartHeight); 118 | 119 | var chart = new Chart(ctx).PolarArea(data,options); 120 | window[chartId] = chart; 121 | return 'OK'; 122 | } 123 | 124 | function addPieChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 125 | var data = JSON.parse(chartData); 126 | var options = JSON.parse(chartOptions); 127 | 128 | var ctx = createContext(chartId,chartWidth,chartHeight); 129 | 130 | var chart = new Chart(ctx).Pie(data,options); 131 | window[chartId] = chart; 132 | return 'OK'; 133 | } 134 | 135 | function addDoughnutChart(chartId,chartWidth,chartHeight,chartData, chartOptions) { 136 | var data = JSON.parse(chartData); 137 | var options = JSON.parse(chartOptions); 138 | 139 | var ctx = createContext(chartId,chartWidth,chartHeight); 140 | 141 | var chart = new Chart(ctx).Doughnut(data,options); 142 | window[chartId] = chart; 143 | return 'OK'; 144 | } 145 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/Assets/datasets.js: -------------------------------------------------------------------------------- 1 | //var lineData = { 2 | // labels: ["January", "February", "March", "April", "May", "June", "July"], 3 | // datasets: [ 4 | // { 5 | // label: "My First dataset", 6 | // fillColor: "rgba(220,220,220,0.2)", 7 | // strokeColor: "rgba(220,220,220,1)", 8 | // pointColor: "rgba(220,220,220,1)", 9 | // pointStrokeColor: "#fff", 10 | // pointHighlightFill: "#fff", 11 | // pointHighlightStroke: "rgba(220,220,220,1)", 12 | // data: [65, 59, 80, 81, 56, 55, 40] 13 | // }, 14 | // { 15 | // label: "My Second dataset", 16 | // fillColor: "rgba(151,187,205,0.2)", 17 | // strokeColor: "rgba(151,187,205,1)", 18 | // pointColor: "rgba(151,187,205,1)", 19 | // pointStrokeColor: "#fff", 20 | // pointHighlightFill: "#fff", 21 | // pointHighlightStroke: "rgba(151,187,205,1)", 22 | // data: [28, 48, 40, 19, 86, 27, 90] 23 | // } 24 | // ] 25 | //}; 26 | // 27 | //var radarData = { 28 | // labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"], 29 | // datasets: [ 30 | // { 31 | // label: "My First dataset", 32 | // fillColor: "rgba(220,220,220,0.2)", 33 | // strokeColor: "rgba(220,220,220,1)", 34 | // pointColor: "rgba(220,220,220,1)", 35 | // pointStrokeColor: "#fff", 36 | // pointHighlightFill: "#fff", 37 | // pointHighlightStroke: "rgba(220,220,220,1)", 38 | // data: [65, 59, 90, 81, 56, 55, 40] 39 | // }, 40 | // { 41 | // label: "My Second dataset", 42 | // fillColor: "rgba(151,187,205,0.2)", 43 | // strokeColor: "rgba(151,187,205,1)", 44 | // pointColor: "rgba(151,187,205,1)", 45 | // pointStrokeColor: "#fff", 46 | // pointHighlightFill: "#fff", 47 | // pointHighlightStroke: "rgba(151,187,205,1)", 48 | // data: [28, 48, 40, 19, 96, 27, 100] 49 | // } 50 | // ] 51 | //}; 52 | // 53 | //var barData = { 54 | // labels: ["January", "February", "March", "April", "May", "June", "July"], 55 | // datasets: [ 56 | // { 57 | // label: "My First dataset", 58 | // fillColor: "rgba(220,220,220,0.5)", 59 | // strokeColor: "rgba(220,220,220,0.8)", 60 | // highlightFill: "rgba(220,220,220,0.75)", 61 | // highlightStroke: "rgba(220,220,220,1)", 62 | // data: [65, 59, 80, 81, 56, 55, 40] 63 | // }, 64 | // { 65 | // label: "My Second dataset", 66 | // fillColor: "rgba(151,187,205,0.5)", 67 | // strokeColor: "rgba(151,187,205,0.8)", 68 | // highlightFill: "rgba(151,187,205,0.75)", 69 | // highlightStroke: "rgba(151,187,205,1)", 70 | // data: [28, 48, 40, 19, 86, 27, 90] 71 | // } 72 | // ] 73 | //}; 74 | 75 | var polarData = [ 76 | { 77 | value: 300, 78 | color:"#F7464A", 79 | highlight: "#FF5A5E", 80 | label: "Red" 81 | }, 82 | { 83 | value: 50, 84 | color: "#46BFBD", 85 | highlight: "#5AD3D1", 86 | label: "Green" 87 | }, 88 | { 89 | value: 100, 90 | color: "#FDB45C", 91 | highlight: "#FFC870", 92 | label: "Yellow" 93 | }, 94 | { 95 | value: 40, 96 | color: "#949FB1", 97 | highlight: "#A8B3C5", 98 | label: "Grey" 99 | }, 100 | { 101 | value: 120, 102 | color: "#4D5360", 103 | highlight: "#616774", 104 | label: "Dark Grey" 105 | } 106 | ]; 107 | 108 | var pieData = [ 109 | { 110 | value: 300, 111 | color:"#F7464A", 112 | highlight: "#FF5A5E", 113 | label: "Red" 114 | }, 115 | { 116 | value: 50, 117 | color: "#46BFBD", 118 | highlight: "#5AD3D1", 119 | label: "Green" 120 | }, 121 | { 122 | value: 100, 123 | color: "#FDB45C", 124 | highlight: "#FFC870", 125 | label: "Yellow" 126 | } 127 | ]; 128 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CW.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWDataSets.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWDataSet.h" 10 | #import "CWObject.h" 11 | #import "CWBoolean.h" 12 | #import "CWPointDataSet.h" 13 | #import "CWLineChartData.h" 14 | #import "CWLineChartOptions.h" 15 | #import "CWLineChart.h" 16 | #import "CWRadarChartData.h" 17 | #import "CWRadarChartOptions.h" 18 | #import "CWRadarChart.h" 19 | #import "CWBarChartData.h" 20 | #import "CWBarChartOptions.h" 21 | #import "CWBarChart.h" 22 | #import "CWBarDataSet.h" 23 | #import "CWSegmentData.h" 24 | #import "CWPolarAreaChartOptions.h" 25 | #import "CWPolarAreaChart.h" 26 | #import "CWPieChartOptions.h" 27 | #import "CWPieChart.h" 28 | #import "CWDoughnutChart.h" 29 | #import "CWColors.h" 30 | 31 | //defaults write hu.gyand.ChartJSWrapper WebKitDeveloperExtras -bool true 32 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLineChart.h" 10 | #import "CWBarChartData.h" 11 | #import "CWBarChartOptions.h" 12 | @interface CWBarChart : CWLineChart 13 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(CWBarChartData*)data options:(CWBarChartOptions*) options; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWBarChart.h" 10 | @interface CWBarChart () 11 | @property (nonatomic, strong,readonly) CWBarChartData* data; 12 | @property (nonatomic, strong, readonly) CWBarChartOptions* options; 13 | @end 14 | 15 | @implementation CWBarChart 16 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(CWBarChartData*)data options:(CWBarChartOptions*) options { 17 | self = [super initWithWebView:webview name:name width:w height:h]; 18 | if(self) { 19 | _data = data; 20 | _options = options; 21 | if(!_options) { 22 | _options = [[CWBarChartOptions alloc] init]; 23 | } 24 | } 25 | return self; 26 | } 27 | 28 | - (void) addChart { 29 | NSString* dataJSON = [self.data JSON]; 30 | NSString* optJSON = [self.options JSON]; 31 | 32 | NSArray* params = @[self.name,@(self.width),@(self.height),dataJSON,optJSON]; 33 | 34 | [self callJavaScriptMethod:@"addBarChart" withArguments:params]; 35 | } 36 | 37 | - (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data { 38 | [_data setValue:val inDataset:dataset at:data]; 39 | NSArray* params = @[self.name,@(dataset),@(data),val]; 40 | 41 | [self callJavaScriptMethod:@"setBarValue" withArguments:params]; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChartData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChartData.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLabelledData.h" 10 | 11 | @interface CWBarChartData : CWLabelledData 12 | - (instancetype) initWithLabels:(NSArray*)labels andBarDataSet:(NSArray*)dataSet; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChartData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChartData.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWBarChartData.h" 10 | #import "CWBarDataSet.h" 11 | @implementation CWBarChartData 12 | - (instancetype) initWithLabels:(NSArray*)labels andBarDataSet:(NSArray*)dataSet { 13 | self = [super initWithLabels:labels andDataSet:dataSet]; 14 | if(self) { 15 | for(id data in dataSet) { 16 | if(![data isKindOfClass:[CWBarDataSet class]]) { 17 | NSLog(@"Invalid data in dataset"); 18 | return nil; 19 | } 20 | } 21 | } 22 | return self; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChartOptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChartOptions.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWGlobalOptions.h" 10 | 11 | @interface CWBarChartOptions : CWGlobalOptions 12 | //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value 13 | @property (nonatomic) CWBoolean* scaleBeginAtZero;// : true, 14 | 15 | //Boolean - Whether grid lines are shown across the chart 16 | @property (nonatomic) CWBoolean* scaleShowGridLines;// : true, 17 | 18 | //String - Colour of the grid lines 19 | @property (nonatomic,strong) CWColor* scaleGridLineColor;// : "rgba(0,0,0,.05)", 20 | 21 | //Number - Width of the grid lines 22 | @property (nonatomic,strong) NSNumber* scaleGridLineWidth;// : 1, 23 | 24 | //Boolean - Whether to show horizontal lines (except X axis) 25 | @property (nonatomic) CWBoolean* scaleShowHorizontalLines;//: true, 26 | 27 | //Boolean - Whether to show vertical lines (except Y axis) 28 | @property (nonatomic) CWBoolean* scaleShowVerticalLines;//: true, 29 | 30 | //Boolean - If there is a stroke on each bar 31 | @property (nonatomic) CWBoolean* barShowStroke;// : true, 32 | 33 | //Number - Pixel width of the bar stroke 34 | @property (nonatomic,strong) NSNumber* barStrokeWidth;// : 2, 35 | 36 | //Number - Spacing between each of the X value sets 37 | @property (nonatomic,strong) NSNumber* barValueSpacing;// : 5, 38 | 39 | //Number - Spacing between data sets within X values 40 | @property (nonatomic,strong) NSNumber* barDatasetSpacing;// : 1, 41 | 42 | //String - A legend template 43 | @property (nonatomic,strong) NSString* legendTemplate;// r : "
      -legend\"><% for (var i=0; i
    • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
    • <%}%>
    " 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarChartOptions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarChartOptions.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWBarChartOptions.h" 10 | 11 | @implementation CWBarChartOptions 12 | - (instancetype) init { 13 | return [super init]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarDataSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarDataSet.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWDataSet.h" 10 | 11 | @interface CWBarDataSet : CWDataSet 12 | @property (nonatomic, strong) CWColor* highlightFill;//: "rgba(220,220,220,0.75)", 13 | @property (nonatomic, strong) CWColor* highlightStroke;//: "rgba(220,220,220,1)", 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBarDataSet.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWBarDataSet.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWBarDataSet.h" 10 | 11 | @implementation CWBarDataSet 12 | - (instancetype) init { 13 | self = [super init]; 14 | return self; 15 | } 16 | @end 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBoolean.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWBoolean.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWObject.h" 10 | 11 | @interface CWBoolean : CWObject { 12 | BOOL val; 13 | } 14 | 15 | + (CWBoolean*) cwYES; 16 | + (CWBoolean*) cwNO; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWBoolean.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWBoolean.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWBoolean.h" 10 | 11 | @interface CWBoolean () 12 | - (instancetype) initWithBOOL:(BOOL) val; 13 | @end 14 | 15 | static CWBoolean* yes = nil; 16 | static CWBoolean* no = nil; 17 | 18 | @implementation CWBoolean 19 | 20 | - (instancetype) initWithBOOL:(BOOL) _val { 21 | self = [super init]; 22 | if(self) { 23 | val = _val; 24 | } 25 | return self; 26 | } 27 | 28 | - (id) asJSONObject { 29 | if(val) { 30 | return @"true"; 31 | } else { 32 | return @"false"; 33 | } 34 | } 35 | 36 | + (CWBoolean*) cwYES { 37 | if(!yes) { 38 | yes = [[CWBoolean alloc] initWithBOOL:YES]; 39 | } 40 | return yes; 41 | } 42 | 43 | + (CWBoolean*) cwNO { 44 | if(!no) { 45 | no = [[CWBoolean alloc] initWithBOOL:NO]; 46 | } 47 | return no; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWObject.h" 10 | #import 11 | 12 | @interface CWChart : CWObject 13 | @property (nonatomic, weak, readonly) CWWebView* webview; 14 | @property (nonatomic, strong, readonly) NSString* name; 15 | @property (nonatomic, readonly) NSInteger width; 16 | @property (nonatomic, readonly) NSInteger height; 17 | 18 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h; 19 | - (void) addChart; 20 | - (void) update; 21 | - (void) removeChart; 22 | - (void) callJavaScriptMethod:(NSString*)method withArguments:(NSArray*)args; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWChart.h" 10 | @interface CWChart () 11 | #if TARGET_OS_IPHONE 12 | #else 13 | @property (strong) id win; 14 | #endif 15 | @end 16 | 17 | @implementation CWChart 18 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h { 19 | self = [super init]; 20 | if(self) { 21 | _width = w; 22 | _height = h; 23 | _webview = webview; 24 | #if TARGET_OS_IPHONE 25 | #else 26 | _win = [_webview windowScriptObject]; 27 | #endif 28 | _name = [NSString stringWithString:name]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void) callJavaScriptMethod:(NSString*)method withArguments:(NSArray*)args { 34 | #if TARGET_OS_IPHONE 35 | NSString* js = [NSString stringWithFormat:@"%@(",method]; 36 | if(args) { 37 | NSString* params = @""; 38 | for(NSUInteger i = 0; i < args.count;i++) { 39 | if(i > 0) { 40 | params = [params stringByAppendingString:@","]; 41 | } 42 | NSObject* o = args[i]; 43 | params = [params stringByAppendingString:[NSString stringWithFormat:@"'%@'",o.description]]; 44 | } 45 | js = [js stringByAppendingString:params]; 46 | } 47 | js = [js stringByAppendingString:@")"]; 48 | // NSLog(@"JS to call: %@",js); 49 | 50 | [self.webview evaluateJavaScript:js completionHandler:^(id res, NSError *err) { 51 | if(err) { 52 | NSLog(@"Calling %@ results ERROR: %@",method, err.localizedDescription); 53 | } else { 54 | NSLog(@"Calling %@ results: %@",method, res); 55 | } 56 | }]; 57 | return; 58 | #else 59 | id res = [self.win callWebScriptMethod:method withArguments:args]; 60 | NSLog(@"Calling %@ results: %@",method, res); 61 | return; 62 | #endif 63 | } 64 | 65 | - (void) update { 66 | NSArray* params = @[self.name]; 67 | [self callJavaScriptMethod:@"updateChart" withArguments:params]; 68 | } 69 | 70 | - (void) removeChart { 71 | NSArray* params = @[self.name]; 72 | [self callJavaScriptMethod:@"deleteChart" withArguments:params]; 73 | } 74 | 75 | - (void) addChart { 76 | // NSString* dataJSON = [ls JSON]; 77 | // id win = [self.webview windowScriptObject]; 78 | // CWLineChartOptions* opt = [[CWLineChartOptions alloc] init]; 79 | // NSString* optJSON = [opt JSON]; 80 | // NSArray* params = @[@"myCanvas",@"600",@"250",dataJSON,optJSON]; 81 | // 82 | // id res = [win callWebScriptMethod:@"addLineChart" withArguments:params]; 83 | // 84 | // NSLog(@"Result is:%@",res); 85 | 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWColors.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWColors.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 23/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWTypes.h" 10 | 11 | extern NSString *const CWCTurquise; 12 | extern NSString *const CWCEmerald; 13 | extern NSString *const CWCPeterRiver; 14 | extern NSString *const CWCAmethyst; 15 | extern NSString *const CWCWetAsphalt; 16 | extern NSString *const CWCGreenSea; 17 | extern NSString *const CWCNephritis; 18 | extern NSString *const CWCBelizeHole; 19 | extern NSString *const CWCWisteria; 20 | extern NSString *const CWCMidnightBlue; 21 | extern NSString *const CWCSunFlower; 22 | extern NSString *const CWCCarrot; 23 | extern NSString *const CWCAlizarin; 24 | extern NSString *const CWCClouds; 25 | extern NSString *const CWCConcrete; 26 | extern NSString *const CWCOrange; 27 | extern NSString *const CWCPumpkin; 28 | extern NSString *const CWCPomegrante; 29 | extern NSString *const CWCSilver; 30 | extern NSString *const CWCAsbestos; 31 | 32 | @interface CWColors : NSObject 33 | @property (nonatomic, strong) NSDictionary* colors; 34 | - (CWColor*) pickColor; 35 | + (CWColors*) sharedColors; 36 | @end 37 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWColors.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWColors.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 23/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWColors.h" 10 | 11 | NSString *const CWCTurquise = @"turquise"; 12 | NSString *const CWCEmerald = @"emerald"; 13 | NSString *const CWCPeterRiver = @"peter river"; 14 | NSString *const CWCAmethyst = @"amethyst"; 15 | NSString *const CWCWetAsphalt = @"wet asphalt"; 16 | NSString *const CWCGreenSea = @"green sea"; 17 | NSString *const CWCNephritis = @"nephritis"; 18 | NSString *const CWCBelizeHole = @"belize hole"; 19 | NSString *const CWCWisteria = @"wisteria"; 20 | NSString *const CWCMidnightBlue = @"midnight blue"; 21 | NSString *const CWCSunFlower = @"sun flower"; 22 | NSString *const CWCCarrot = @"carrot"; 23 | NSString *const CWCAlizarin = @"alizarin"; 24 | NSString *const CWCClouds = @"clouds"; 25 | NSString *const CWCConcrete = @"concrete"; 26 | NSString *const CWCOrange = @"orange"; 27 | NSString *const CWCPumpkin = @"pumpkin"; 28 | NSString *const CWCPomegrante = @"pomegrante"; 29 | NSString *const CWCSilver = @"silver"; 30 | NSString *const CWCAsbestos = @"asbestos"; 31 | 32 | 33 | 34 | static CWColors* _sharedColors = nil; 35 | @interface CWColors () 36 | - (CWColor*) rgba:(NSString*) string; 37 | - (NSInteger) random:(NSInteger) max; 38 | @end 39 | 40 | @implementation CWColors 41 | 42 | - (NSInteger) random:(NSInteger) max { 43 | return (NSInteger)arc4random_uniform((u_int32_t)max); 44 | } 45 | 46 | - (CWColor*) pickColor { 47 | NSArray* keys = self.colors.allKeys; 48 | NSString* key = keys[[self random:keys.count]]; 49 | NSLog(@"Picking %@",key); 50 | return self.colors[key]; 51 | } 52 | 53 | + (CWColors*) sharedColors { 54 | if(!_sharedColors) { 55 | _sharedColors = [[CWColors alloc] init]; 56 | } 57 | return _sharedColors; 58 | } 59 | 60 | - (instancetype) init { 61 | self = [super init]; 62 | if(self) { 63 | NSMutableDictionary* __colors = [NSMutableDictionary dictionary]; 64 | __colors[@"turquise"] = [self rgba:@"26, 188, 156,1.0"]; 65 | __colors[@"emerald"] = [self rgba:@"46, 204, 113,1.0"]; 66 | __colors[@"peter river"] = [self rgba:@"52, 152, 219,1.0"]; 67 | __colors[@"amethyst"] = [self rgba:@"155, 89, 182,1.0"]; 68 | __colors[@"wet asphalt"] = [self rgba:@"52, 73, 94,1.0"]; 69 | __colors[@"green sea"] = [self rgba:@"22, 160, 133,1.0"]; 70 | __colors[@"nephritis"] = [self rgba:@"39, 174, 96,1.0"]; 71 | __colors[@"belize hole"] = [self rgba:@"41, 128, 185,1.0"]; 72 | __colors[@"wisteria"] = [self rgba:@"142, 68, 173,1.0"]; 73 | __colors[@"midnight blue"] = [self rgba:@"44, 62, 80,1.0"]; 74 | __colors[@"sun flower"] = [self rgba:@"241, 196, 15,1.0"]; 75 | __colors[@"carrot"] = [self rgba:@"230, 126, 34,1.0"]; 76 | __colors[@"alizarin"] = [self rgba:@"231, 76, 60,1.0"]; 77 | __colors[@"clouds"] = [self rgba:@"236, 240, 241,1.0"]; 78 | __colors[@"concrete"] = [self rgba:@"149, 165, 166,1.0"]; 79 | __colors[@"orange"] = [self rgba:@"243, 156, 18,1.0"]; 80 | __colors[@"pumpkin"] = [self rgba:@"211, 84, 0,1.0"]; 81 | __colors[@"pomegrante"] = [self rgba:@"192, 57, 43,1.0"]; 82 | __colors[@"silver"] = [self rgba:@"189, 195, 199,1.0"]; 83 | __colors[@"asbestos"] = [self rgba:@"127, 140, 141,1.0"]; 84 | _colors = __colors; 85 | } 86 | return self; 87 | } 88 | - (CWColor*) rgba:(NSString*) string { 89 | NSArray* components = [string componentsSeparatedByString:@","]; 90 | NSInteger r = [components[0] integerValue]; 91 | NSInteger g = [components[1] integerValue]; 92 | NSInteger b = [components[2] integerValue]; 93 | CGFloat a = [components[0] floatValue]; 94 | #if TARGET_OS_IPHONE 95 | CWColor* col = [CWColor colorWithRed:(CGFloat)r/255.0f green:(CGFloat)g/255.0f blue:(CGFloat)b/255.0f alpha:a]; 96 | #else 97 | CWColor* col = [CWColor colorWithDeviceRed:(CGFloat)r/255.0f green:(CGFloat)g/255.0f blue:(CGFloat)b/255.0f alpha:a]; 98 | #endif 99 | return col; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWData.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CWObject.h" 11 | @interface CWData : CWObject 12 | //- (NSString*) JSON; 13 | @end 14 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWData.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWData.h" 10 | 11 | @interface CWData () 12 | 13 | @end 14 | 15 | @implementation CWData 16 | //- (NSString*) JSON { 17 | // NSData *dataJSON = [NSJSONSerialization dataWithJSONObject:[self asJSONObject] options:NSJSONWritingPrettyPrinted error:nil]; 18 | // NSString *stringJSON = [[NSString alloc] initWithData:dataJSON encoding:NSUTF8StringEncoding]; 19 | // return stringJSON; 20 | //} 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWDataSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWDataSet.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWTypes.h" 10 | #import "CWObject.h" 11 | #import "CWBoolean.h" 12 | 13 | @interface CWDataSet : CWObject 14 | @property (nonatomic, strong) NSString* label; 15 | @property (nonatomic, strong) CWColor* fillColor; 16 | @property (nonatomic, strong) CWColor* strokeColor; 17 | @property (nonatomic, strong,readonly) NSArray* data;//: [65, 59, 80, 81, 56, 55, 40] 18 | 19 | - (instancetype) initWithData:(NSArray*)data; 20 | - (void) setValue:(NSNumber*)val at:(NSInteger)data; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWDataSet.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWDataSet.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWDataSet.h" 10 | 11 | @implementation CWDataSet 12 | //- (instancetype) init { 13 | // self = [super init]; 14 | // return self; 15 | //} 16 | 17 | - (instancetype) initWithData:(NSArray*)data { 18 | self = [super init]; 19 | if(self) { 20 | _data = [NSMutableArray arrayWithArray:data]; 21 | } 22 | return self; 23 | } 24 | 25 | - (void) setValue:(NSNumber*)val at:(NSInteger)data { 26 | NSMutableArray* arr = (NSMutableArray*)_data; 27 | [arr setObject:val atIndexedSubscript:data];// [data] = val; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWDoughnutChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWDonughtChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 23/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPieChart.h" 10 | 11 | @interface CWDoughnutChart : CWPieChart 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWDoughnutChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWDonughtChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 23/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWDoughnutChart.h" 10 | 11 | @implementation CWDoughnutChart 12 | - (void) addChart { 13 | id jsonData = [self convertToJSON:self.data]; 14 | NSString* dataJSON = [CWObject toJSONString:jsonData]; 15 | NSString* optJSON = [self.options JSON]; 16 | 17 | NSArray* params = @[self.name,@(self.width),@(self.height),dataJSON,optJSON]; 18 | 19 | [self callJavaScriptMethod:@"addDoughnutChart" withArguments:params]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWGlobalOptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWGlobalOptions.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWObject.h" 10 | #import "CWBoolean.h" 11 | 12 | @interface CWGlobalOptions : CWObject 13 | // Boolean - Whether to animate the chart 14 | @property (nonatomic) CWBoolean* animation;//: true, 15 | 16 | // Number - Number of animation steps 17 | @property (nonatomic,strong) NSNumber* animationSteps;//: 60, 18 | 19 | // String - Animation easing effect 20 | @property (nonatomic,strong) NSString* animationEasing;//: "easeOutQuart", 21 | 22 | // Boolean - If we should show the scale at all 23 | @property (nonatomic) CWBoolean* showScale;//: true, 24 | 25 | // Boolean - If we want to override with a hard coded scale 26 | @property (nonatomic) CWBoolean* scaleOverride;//: false, 27 | 28 | // ** Required if scaleOverride is true ** 29 | // Number - The number of steps in a hard coded scale 30 | @property (nonatomic,strong) NSNumber* scaleSteps;//: null, 31 | // Number - The value jump in the hard coded scale 32 | @property (nonatomic,strong) NSNumber* scaleStepWidth;//: null, 33 | // Number - The scale starting value 34 | @property (nonatomic,strong) NSNumber* scaleStartValue;//: null, 35 | 36 | // String - Colour of the scale line 37 | @property (nonatomic,strong) CWColor* scaleLineColor;//@property (nonatomic,strong) CWColor* : "rgba(0,0,0,.1)", 38 | 39 | // Number - Pixel width of the scale line 40 | @property (nonatomic,strong) NSNumber* scaleLineWidth;//: 1, 41 | 42 | // Boolean - Whether to show labels on the scale 43 | @property (nonatomic) CWBoolean* scaleShowLabels;//: true, 44 | 45 | // Interpolated JS string - can access value 46 | @property (nonatomic,strong) NSString* scaleLabel;//: "<%=value%>", 47 | 48 | // Boolean - Whether the scale should stick to integers, not floats even if drawing space is there 49 | @property (nonatomic) CWBoolean* scaleIntegersOnly;//: true, 50 | 51 | // Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value 52 | @property (nonatomic) CWBoolean* scaleBeginAtZero;//: false, 53 | 54 | // String - Scale label font declaration for the scale label 55 | @property (nonatomic,strong) NSString* scaleFontFamily;//: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", 56 | 57 | // Number - Scale label font size in pixels 58 | @property (nonatomic,strong) NSNumber* scaleFontSize;//: 12, 59 | 60 | // String - Scale label font weight style 61 | @property (nonatomic,strong) NSString* scaleFontStyle;//: "normal", 62 | 63 | // String - Scale label font colour 64 | @property (nonatomic,strong) CWColor* scaleFontColor;//: "#666", 65 | 66 | // Boolean - whether or not the chart should be responsive and resize when the browser does. 67 | @property (nonatomic) CWBoolean* responsive;//: false, 68 | 69 | // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container 70 | @property (nonatomic) CWBoolean* maintainAspectRatio;//: true, 71 | 72 | // Boolean - Determines whether to draw tooltips on the canvas or not 73 | @property (nonatomic) CWBoolean* showTooltips;//: true, 74 | 75 | // Function - Determines whether to execute the customTooltips function instead of drawing the built in tooltips (See [Advanced - External Tooltips](#advanced-usage-custom-tooltips)) 76 | @property (nonatomic) CWBoolean* customTooltips;//: false, 77 | 78 | // Array - Array of string names to attach tooltip events 79 | @property (nonatomic,strong) NSArray* tooltipEvents;//: ["mousemove", "touchstart", "touchmove"], 80 | 81 | // String - Tooltip background colour 82 | @property (nonatomic,strong) CWColor* tooltipFillColor;//: "rgba(0,0,0,0.8)", 83 | 84 | // String - Tooltip label font declaration for the scale label 85 | @property (nonatomic,strong) NSString* tooltipFontFamily;//: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", 86 | 87 | // Number - Tooltip label font size in pixels 88 | @property (nonatomic,strong) NSNumber* tooltipFontSize;//: 14, 89 | 90 | // String - Tooltip font weight style 91 | @property (nonatomic,strong) NSString* tooltipFontStyle;//: "normal", 92 | 93 | // String - Tooltip label font colour 94 | @property (nonatomic,strong) CWColor* tooltipFontColor;//: "#fff", 95 | 96 | // String - Tooltip title font declaration for the scale label 97 | @property (nonatomic,strong) NSString* tooltipTitleFontFamily;//: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", 98 | 99 | // Number - Tooltip title font size in pixels 100 | @property (nonatomic,strong) NSNumber* tooltipTitleFontSize;//: 14, 101 | 102 | // String - Tooltip title font weight style 103 | @property (nonatomic,strong) NSString* tooltipTitleFontStyle;//: "bold", 104 | 105 | // String - Tooltip title font colour 106 | @property (nonatomic,strong) CWColor* tooltipTitleFontColor;//: "#fff", 107 | 108 | // Number - pixel width of padding around tooltip text 109 | @property (nonatomic,strong) NSNumber* tooltipYPadding;//: 6, 110 | 111 | // Number - pixel width of padding around tooltip text 112 | @property (nonatomic,strong) NSNumber* tooltipXPadding;//: 6, 113 | 114 | // Number - Size of the caret on the tooltip 115 | @property (nonatomic,strong) NSNumber* tooltipCaretSize;//: 8, 116 | 117 | // Number - Pixel radius of the tooltip border 118 | @property (nonatomic,strong) NSNumber* tooltipCornerRadius;//: 6, 119 | 120 | // Number - Pixel offset from point x to tooltip edge 121 | @property (nonatomic,strong) NSNumber* tooltipXOffset;//: 10, 122 | 123 | // String - Template string for single tooltips 124 | @property (nonatomic,strong) NSString* tooltipTemplate;//: "<%if (label){%><%=label%>: <%}%><%= value %>", 125 | 126 | // String - Template string for multiple tooltips 127 | @property (nonatomic,strong) NSString* multiTooltipTemplate;//: "<%= value %>", 128 | 129 | // Function - Will fire on animation progression. 130 | //onAnimationProgress: function(){}, 131 | 132 | // Function - Will fire on animation completion. 133 | //onAnimationComplete: function(){} 134 | //} 135 | @end 136 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWGlobalOptions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWGlobalOptions.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWGlobalOptions.h" 10 | 11 | @implementation CWGlobalOptions 12 | - (instancetype) init { 13 | return [super init]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLabelledData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWLabelledData.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CWData.h" 11 | @interface CWLabelledData : CWData 12 | @property (nonatomic, strong,readonly) NSArray* labels; 13 | @property (nonatomic, strong,readonly) NSArray* datasets; 14 | 15 | - (instancetype) initWithLabels:(NSArray*)labels andDataSet:(NSArray*)dataSet; 16 | - (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLabelledData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWLabelledData.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLabelledData.h" 10 | #import "CWDataSet.h" 11 | 12 | @implementation CWLabelledData 13 | - (instancetype) init { 14 | self = [super init]; 15 | if(self) { 16 | _labels = [NSMutableArray array]; 17 | _datasets = [NSMutableArray array]; 18 | } 19 | return self; 20 | } 21 | 22 | - (instancetype) initWithLabels:(NSArray*)labels andDataSet:(NSArray*)dataSet { 23 | self = [super init]; 24 | if(self) { 25 | _labels = [NSMutableArray arrayWithArray:labels]; 26 | _datasets = [NSMutableArray arrayWithArray:dataSet]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data { 32 | CWDataSet* ds = self.datasets[dataset]; 33 | [ds setValue:val at:data]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWChart.h" 10 | #import "CWLineChartData.h" 11 | #import "CWLineChartOptions.h" 12 | 13 | @interface CWLineChart : CWChart 14 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(CWLineChartData*)data options:(CWLineChartOptions*) options; 15 | - (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data; 16 | - (void) addData:(NSArray*)values label:(NSString*)label; 17 | - (void) removeData; 18 | @end 19 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLineChart.h" 10 | 11 | @interface CWLineChart () 12 | @property (nonatomic, strong,readonly) CWLineChartData* data; 13 | @property (nonatomic, strong, readonly) CWLineChartOptions* options; 14 | @end 15 | 16 | @implementation CWLineChart 17 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(CWLineChartData*)data options:(CWLineChartOptions*) options { 18 | self = [super initWithWebView:webview name:name width:w height:h]; 19 | if(self) { 20 | _data = data; 21 | _options = options; 22 | if(!_options) { 23 | _options = [[CWLineChartOptions alloc] init]; 24 | } 25 | } 26 | return self; 27 | } 28 | 29 | - (void) addChart { 30 | NSString* dataJSON = [self.data JSON]; 31 | NSString* optJSON = [self.options JSON]; 32 | 33 | NSArray* params = @[self.name,@(self.width),@(self.height),dataJSON,optJSON]; 34 | 35 | [self callJavaScriptMethod:@"addLineChart" withArguments:params]; 36 | } 37 | 38 | - (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data { 39 | [_data setValue:val inDataset:dataset at:data]; 40 | NSArray* params = @[self.name,@(dataset),@(data),val]; 41 | 42 | [self callJavaScriptMethod:@"setPointValue" withArguments:params]; 43 | } 44 | 45 | - (void) addData:(NSArray*)values label:(NSString*)label { 46 | NSMutableArray* safeArray = [NSMutableArray arrayWithArray:values]; 47 | while (safeArray.count > self.data.datasets.count) { 48 | [safeArray removeLastObject]; 49 | }; 50 | id jsonValues = [self convertToJSON:safeArray]; 51 | NSString* valuesJSON = [CWObject toJSONString:jsonValues]; 52 | 53 | NSArray* params = @[self.name,valuesJSON,label]; 54 | [self callJavaScriptMethod:@"addPointData" withArguments:params]; 55 | } 56 | 57 | - (void) removeData { 58 | NSArray* params = @[self.name]; 59 | [self callJavaScriptMethod:@"removePointData" withArguments:params]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChartData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineData.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLabelledData.h" 10 | 11 | @interface CWLineChartData : CWLabelledData 12 | - (instancetype) initWithLabels:(NSArray*)labels andPointDataSet:(NSArray*)dataSet; 13 | @end 14 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChartData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineData.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLineChartData.h" 10 | #import "CWPointDataSet.h" 11 | 12 | @implementation CWLineChartData 13 | 14 | - (instancetype) initWithLabels:(NSArray*)labels andPointDataSet:(NSArray*)dataSet { 15 | self = [super initWithLabels:labels andDataSet:dataSet]; 16 | if(self) { 17 | for(id data in dataSet) { 18 | if(![data isKindOfClass:[CWPointDataSet class]]) { 19 | NSLog(@"Invalid data in dataset"); 20 | return nil; 21 | } 22 | } 23 | } 24 | return self; 25 | } 26 | 27 | //- (void) setValue:(NSNumber*)val inDataset:(NSInteger)dataset at:(NSInteger)data { 28 | // 29 | //} 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChartOptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineChartOptions.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWGlobalOptions.h" 10 | 11 | @interface CWLineChartOptions : CWGlobalOptions 12 | 13 | ///Boolean - Whether grid lines are shown across the chart 14 | @property (nonatomic) CWBoolean* scaleShowGridLines;// : true, 15 | 16 | //String - Colour of the grid lines 17 | @property (nonatomic,strong) CWColor* scaleGridLineColor;// : "rgba(0,0,0,.05)", 18 | 19 | //Number - Width of the grid lines 20 | @property (nonatomic,strong) NSNumber* scaleGridLineWidth;// : 1, 21 | 22 | //Boolean - Whether to show horizontal lines (except X axis) 23 | @property (nonatomic) CWBoolean* scaleShowHorizontalLines;//: true, 24 | 25 | //Boolean - Whether to show vertical lines (except Y axis) 26 | @property (nonatomic) CWBoolean* scaleShowVerticalLines;//: true, 27 | 28 | //Boolean - Whether the line is curved between points 29 | @property (nonatomic) CWBoolean* bezierCurve;// : true, 30 | 31 | //Number - Tension of the bezier curve between points 32 | @property (nonatomic,strong) NSNumber* bezierCurveTension;// : 0.4, 33 | 34 | //Boolean - Whether to show a dot for each point 35 | @property (nonatomic) CWBoolean* pointDot;// : true, 36 | 37 | //Number - Radius of each point dot in pixels 38 | @property (nonatomic,strong) NSNumber* pointDotRadius;// : 4, 39 | 40 | //Number - Pixel width of point dot stroke 41 | @property (nonatomic,strong) NSNumber* pointDotStrokeWidth;// : 1, 42 | 43 | //Number - amount extra to add to the radius to cater for hit detection outside the drawn point 44 | @property (nonatomic,strong) NSNumber* pointHitDetectionRadius;// : 20, 45 | 46 | //Boolean - Whether to show a stroke for datasets 47 | @property (nonatomic) CWBoolean* datasetStroke;// : true, 48 | 49 | //Number - Pixel width of dataset stroke 50 | @property (nonatomic,strong) NSNumber* datasetStrokeWidth;// : 2, 51 | 52 | //Boolean - Whether to fill the dataset with a colour 53 | @property (nonatomic) CWBoolean* datasetFill;// : true, 54 | 55 | //String - A legend template 56 | @property (nonatomic,strong) NSString* legendTemplate;// : "
      -legend\"><% for (var i=0; i
    • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
    • <%}%>
    " 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWLineChartOptions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWLineChartOptions.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWLineChartOptions.h" 10 | 11 | @implementation CWLineChartOptions 12 | - (instancetype) init { 13 | return [super init]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWObject.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWTypes.h" 10 | 11 | @interface CWObject : NSObject 12 | - (id) convertToJSON:(id)val; 13 | - (id) asJSONObject; 14 | - (NSString*) JSON; 15 | + (NSString*) toJSONString:(id)val; 16 | @end 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWObject.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWObject.h" 10 | #import 11 | 12 | @implementation CWObject 13 | 14 | - (void) propertiesOf:(Class)clazz tp:(NSMutableArray*) arr { 15 | if(clazz == [CWObject class]) return; 16 | unsigned int outCount; 17 | objc_property_t *properties = class_copyPropertyList(clazz, &outCount); 18 | for (int i = 0; i < outCount; i++) 19 | { 20 | objc_property_t property = properties[i]; 21 | const char *propName = property_getName(property); 22 | if(propName) 23 | { 24 | NSString *propertyName = @(propName); 25 | [arr addObject:propertyName]; 26 | } 27 | } 28 | free(properties); 29 | Class superClazz = class_getSuperclass(clazz); 30 | [self propertiesOf:superClazz tp:arr]; 31 | } 32 | 33 | - (NSArray*) properties { 34 | NSMutableArray *array = [NSMutableArray array]; 35 | [self propertiesOf:[self class] tp:array]; 36 | return array; 37 | } 38 | 39 | - (id) convertToJSON:(id)val { 40 | id ret = nil; 41 | if([val isKindOfClass:[CWObject class]]) { 42 | ret = [val asJSONObject]; 43 | } else if([val isKindOfClass:[NSArray class]]) { 44 | NSMutableArray* jsonProp = [NSMutableArray array]; 45 | for(id o in val) { 46 | [jsonProp addObject:[self convertToJSON:o]]; 47 | } 48 | ret = jsonProp; 49 | } else if([val isKindOfClass:[NSDictionary class]]) { 50 | NSDictionary* dict = val; 51 | NSMutableDictionary* jsonProp = [NSMutableDictionary dictionary]; 52 | 53 | for(id key in dict.allKeys) { 54 | id o = dict[key]; 55 | jsonProp[key] = [self convertToJSON:o]; 56 | } 57 | ret = jsonProp; 58 | } else if([val isKindOfClass:[CWColor class]]) { 59 | CWColor* _c = val; 60 | #if TARGET_OS_IPHONE 61 | CGFloat fr; 62 | CGFloat fg; 63 | CGFloat fb; 64 | CGFloat fa; 65 | [_c getRed:&fr green:&fg blue:&fb alpha:&fa]; 66 | int r = (fr*255.0f); 67 | int g = (fg*255.0f); 68 | int b = (fb*255.0f); 69 | CGFloat a = fa; 70 | #else 71 | CWColor* c = [_c colorUsingColorSpace:[NSColorSpace sRGBColorSpace]]; 72 | int r = (c.redComponent*255.0f); 73 | int g = (c.greenComponent*255.0f); 74 | int b = (c.blueComponent*255.0f); 75 | CGFloat a = (c.alphaComponent); 76 | #endif 77 | NSString* jsonColor = [NSString stringWithFormat:@"rgba(%d,%d,%d,%f)",r,g,b,a]; 78 | ret = jsonColor; 79 | } else { 80 | ret = val; 81 | } 82 | return ret; 83 | } 84 | 85 | - (id) asJSONObject { 86 | NSMutableDictionary* ret = [NSMutableDictionary dictionary]; 87 | for(NSString* prop in [self properties]) { 88 | id val = [self valueForKey:prop]; 89 | if(!val) continue; 90 | ret[prop] = [self convertToJSON:val]; 91 | } 92 | return ret; 93 | } 94 | 95 | + (NSString*) toJSONString:(id)val { 96 | // NSData *dataJSON = [NSJSONSerialization dataWithJSONObject:val options:NSJSONWritingPrettyPrinted error:nil]; 97 | NSData *dataJSON = [NSJSONSerialization dataWithJSONObject:val options:0 error:nil]; 98 | NSString *stringJSON = [[NSString alloc] initWithData:dataJSON encoding:NSUTF8StringEncoding]; 99 | return stringJSON; 100 | } 101 | 102 | - (NSString*) JSON { 103 | return [CWObject toJSONString:[self asJSONObject]]; 104 | // NSData *dataJSON = [NSJSONSerialization dataWithJSONObject:[self asJSONObject] options:NSJSONWritingPrettyPrinted error:nil]; 105 | // NSString *stringJSON = [[NSString alloc] initWithData:dataJSON encoding:NSUTF8StringEncoding]; 106 | // return stringJSON; 107 | } 108 | 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPieChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWPieChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPolarAreaChart.h" 10 | #import "CWPieChartOptions.h" 11 | @interface CWPieChart : CWPolarAreaChart 12 | @property (nonatomic, strong, readonly) CWPieChartOptions* options; 13 | @property (nonatomic, strong,readonly) NSArray* data; 14 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(NSArray*)data options:(CWPieChartOptions*) options; 15 | //- (void) setValue:(NSNumber*)val inSegment:(NSInteger)segment; 16 | @end 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPieChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWPieChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPieChart.h" 10 | 11 | @implementation CWPieChart 12 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(NSArray*)data options:(CWPieChartOptions*) options { 13 | self = [super initWithWebView:webview name:name width:w height:h]; 14 | if(self) { 15 | _data = [NSMutableArray arrayWithArray:data]; 16 | _options = options; 17 | if(!_options) { 18 | _options = [[CWPieChartOptions alloc] init]; 19 | } 20 | } 21 | return self; 22 | } 23 | 24 | - (void) addChart { 25 | id jsonData = [self convertToJSON:self.data]; 26 | NSString* dataJSON = [CWObject toJSONString:jsonData]; 27 | NSString* optJSON = [self.options JSON]; 28 | 29 | NSArray* params = @[self.name,@(self.width),@(self.height),dataJSON,optJSON]; 30 | 31 | [self callJavaScriptMethod:@"addPieChart" withArguments:params]; 32 | } 33 | 34 | //- (void) setValue:(NSNumber*)val inSegment:(NSInteger)segment { 35 | // NSMutableArray* arr = (NSMutableArray*)_data; 36 | // arr[segment] = val; 37 | // [_data setValue:val ]; 38 | // NSArray* params = @[self.name,@(segment),val]; 39 | // 40 | // id res = [self.win callWebScriptMethod:@"setSegmentValue" withArguments:params]; 41 | // 42 | // NSLog(@"Result setSegmentValue is:%@",res); 43 | //} 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPieChartOptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWPieChartOption.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWGlobalOptions.h" 10 | 11 | @interface CWPieChartOptions : CWGlobalOptions 12 | //Boolean - Whether we should show a stroke on each segment 13 | @property (nonatomic) CWBoolean* segmentShowStroke;// : true, 14 | 15 | //String - The colour of each segment stroke 16 | @property (nonatomic) CWColor* segmentStrokeColor;// : "#fff", 17 | 18 | //Number - The width of each segment stroke 19 | @property (nonatomic) NSNumber* segmentStrokeWidth;// : 2, 20 | 21 | //Number - The percentage of the chart that we cut out of the middle 22 | @property (nonatomic) NSNumber* percentageInnerCutout;// : 50, // This is 0 for Pie charts 23 | 24 | //Number - Amount of animation steps 25 | @property (nonatomic) NSNumber* animationSteps;// : 100, 26 | 27 | //String - Animation easing effect 28 | @property (nonatomic) NSString* animationEasing;// : "easeOutBounce", 29 | 30 | //Boolean - Whether we animate the rotation of the Doughnut 31 | @property (nonatomic) CWBoolean* animateRotate;// : true, 32 | 33 | //Boolean - Whether we animate scaling the Doughnut from the centre 34 | @property (nonatomic) CWBoolean* animateScale;// : false, 35 | 36 | //String - A legend template 37 | @property (nonatomic) NSString* legendTemplate;// : "
      -legend\"><% for (var i=0; i
    • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
    • <%}%>
    " 38 | @end 39 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPieChartOptions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWPieChartOption.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPieChartOptions.h" 10 | 11 | @implementation CWPieChartOptions 12 | - (instancetype) init { 13 | self = [super init]; 14 | return self; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPointDataSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWPointDataSet.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWDataSet.h" 10 | 11 | @interface CWPointDataSet : CWDataSet 12 | @property (nonatomic, strong) CWColor* pointColor;//: "rgba(220,220,220,1)", 13 | @property (nonatomic, strong) CWColor* pointStrokeColor;//: "#fff", 14 | @property (nonatomic, strong) CWColor* pointHighlightFill;//: "#fff", 15 | @property (nonatomic, strong) CWColor* pointHighlightStroke;//: "rgba(220,220,220,1)", 16 | 17 | //- (instancetype) initWithData:(NSArray*)data; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPointDataSet.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWPointDataSet.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 21/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPointDataSet.h" 10 | 11 | @implementation CWPointDataSet 12 | - (instancetype) init { 13 | self = [super init]; 14 | return self; 15 | } 16 | 17 | //- (instancetype) initWithData:(NSArray*)data { 18 | // self = [super init]; 19 | // if(self) { 20 | // _data = [NSArray arrayWithArray:data]; 21 | // } 22 | // return self; 23 | //} 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPolarAreaChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWPolarAreaChart.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWChart.h" 10 | #import "CWPolarAreaChartOptions.h" 11 | #import "CWSegmentData.h" 12 | @interface CWPolarAreaChart : CWChart 13 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(NSArray*)data options:(CWPolarAreaChartOptions*) options; 14 | - (void) setValue:(NSNumber*)val inSegment:(NSInteger)segment; 15 | //.addData( segmentData, index ) 16 | - (void) addData:(CWSegmentData*)data index:(NSNumber*)index; 17 | - (void) removeDataAt:(NSNumber*)index; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPolarAreaChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWPolarAreaChart.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWPolarAreaChart.h" 10 | 11 | @interface CWPolarAreaChart () 12 | @property (nonatomic, strong,readonly) NSArray* data; 13 | @property (nonatomic, strong, readonly) CWPolarAreaChartOptions* options; 14 | @end 15 | 16 | @implementation CWPolarAreaChart 17 | - (instancetype) initWithWebView:(CWWebView*)webview name:(NSString*)name width:(NSInteger)w height:(NSInteger)h data:(NSArray*)data options:(CWPolarAreaChartOptions*) options { 18 | self = [super initWithWebView:webview name:name width:w height:h]; 19 | if(self) { 20 | _data = [NSMutableArray arrayWithArray:data]; 21 | _options = options; 22 | if(!_options) { 23 | _options = [[CWPolarAreaChartOptions alloc] init]; 24 | } 25 | } 26 | return self; 27 | } 28 | 29 | - (void) addChart { 30 | id jsonData = [self convertToJSON:_data]; 31 | NSString* dataJSON = [CWObject toJSONString:jsonData]; 32 | NSString* optJSON = [self.options JSON]; 33 | // NSLog(@"Polar data:%@",dataJSON); 34 | 35 | NSArray* params = @[self.name,@(self.width),@(self.height),dataJSON,optJSON]; 36 | 37 | [self callJavaScriptMethod:@"addPolarAreaChart" withArguments:params]; 38 | } 39 | 40 | //myPolarAreaChart.segments[1].value = 10; 41 | - (void) setValue:(NSNumber*)val inSegment:(NSInteger)segment { 42 | NSMutableArray* arr = (NSMutableArray*)_data; 43 | arr[segment] = val; 44 | // [_data setValue:val ]; 45 | NSArray* params = @[self.name,@(segment),val]; 46 | 47 | [self callJavaScriptMethod:@"setSegmentValue" withArguments:params]; 48 | } 49 | 50 | - (void) addData:(CWSegmentData*)data index:(NSNumber*)index { 51 | id jsonData = [self convertToJSON:data]; 52 | NSString* dataJSON = [CWObject toJSONString:jsonData]; 53 | NSArray* params = @[self.name,dataJSON,index]; 54 | 55 | [self callJavaScriptMethod:@"addSegmentData" withArguments:params]; 56 | } 57 | 58 | - (void) removeDataAt:(NSNumber*)index { 59 | NSArray* params = @[self.name,index]; 60 | 61 | [self callJavaScriptMethod:@"removeSegmentData" withArguments:params]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWPolarAreaChartOptions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWPolarAreaChartOptions.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWGlobalOptions.h" 10 | 11 | @interface CWPolarAreaChartOptions : CWGlobalOptions 12 | //Boolean - Show a backdrop to the scale label 13 | @property (nonatomic) CWBoolean* scaleShowLabelBackdrop;// : true, 14 | 15 | //String - The colour of the label backdrop 16 | @property (nonatomic,strong) CWColor* scaleBackdropColor;// : "rgba(255,255,255,0.75)", 17 | 18 | // Boolean - Whether the scale should begin at zero 19 | @property (nonatomic) CWBoolean* scaleBeginAtZero;// : true, 20 | 21 | //Number - The backdrop padding above & below the label in pixels 22 | @property (nonatomic,strong) NSNumber* scaleBackdropPaddingY;// : 2, 23 | 24 | //Number - The backdrop padding to the side of the label in pixels 25 | @property (nonatomic,strong) NSNumber* scaleBackdropPaddingX;// : 2, 26 | 27 | //Boolean - Show line for each value in the scale 28 | @property (nonatomic) CWBoolean* scaleShowLine;// : true, 29 | 30 | //Boolean - Stroke a line around each segment in the chart 31 | @property (nonatomic) CWBoolean* segmentShowStroke;// : true, 32 | 33 | //String - The colour of the stroke on each segement. 34 | @property (nonatomic,strong) CWColor* segmentStrokeColor;// : "#fff", 35 | 36 | //Number - The width of the stroke value in pixels 37 | @property (nonatomic,strong) NSNumber* segmentStrokeWidth;// : 2, 38 | 39 | //Number - Amount of animation steps 40 | @property (nonatomic,strong) NSNumber* animationSteps;// : 100, 41 | 42 | //String - Animation easing effect. 43 | @property (nonatomic,strong) NSString* animationEasing;//@property (nonatomic,strong) NSString* : "easeOutBounce", 44 | 45 | //Boolean - Whether to animate the rotation of the chart 46 | @property (nonatomic) CWBoolean* animateRotate;// : true, 47 | 48 | //Boolean - Whether to animate scaling the chart from the centre 49 | @property (nonatomic) CWBoolean* animateScale;// : false, 50 | 51 | //String - A legend template 52 | @property (nonatomic,strong) NSString* legendTemplate;// : "
      -legend\"><% for (var i=0; i
    • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
    • <%}%>
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>" 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWRadarChartOptions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWRadarChartOptions.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWRadarChartOptions.h" 10 | 11 | @implementation CWRadarChartOptions 12 | - (instancetype) init { 13 | return [super init]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWSegmentData.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWSegmentData.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWData.h" 10 | 11 | @interface CWSegmentData : CWData 12 | @property (nonatomic,strong) NSNumber* value;//: 300, 13 | @property (nonatomic, strong) CWColor* color;//:"#F7464A", 14 | @property (nonatomic, strong) CWColor* highlight;//: "#FF5A5E", 15 | @property (nonatomic, strong) NSString* label;//: "Red" 16 | @end 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWSegmentData.m: -------------------------------------------------------------------------------- 1 | // 2 | // CWSegmentData.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 22/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "CWSegmentData.h" 10 | 11 | @implementation CWSegmentData 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ChartJSWrapper/CW/CWTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // CWTypes.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | 14 | #import 15 | #define CWColor UIColor 16 | #define CWWebView WKWebView 17 | #else 18 | 19 | #import 20 | #define CWColor NSColor 21 | #define CWWebView WebView 22 | 23 | #endif -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ChartJSWrapper-IOS 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ChartJSWrapper-IOS 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | hu.gyand.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarStyle 34 | UIStatusBarStyleLightContent 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/PullDownMenu/PulldownMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // PulldownMenu.h 3 | // 4 | // Created by Bernard Gatt 5 | // 6 | 7 | #import 8 | 9 | @protocol PulldownMenuDelegate 10 | -(void)menuItemSelected:(NSIndexPath *)indexPath; 11 | -(void)pullDownAnimated:(BOOL)open; 12 | @end 13 | 14 | @interface PulldownMenu : UIView { 15 | UITableView *menuList; 16 | NSMutableArray *menuItems; 17 | 18 | UIView *handle; 19 | UIView *masterView; 20 | UIPanGestureRecognizer *navigationDragGestureRecognizer; 21 | UIPanGestureRecognizer *handleDragGestureRecognizer; 22 | UINavigationController *masterNavigationController; 23 | UIDeviceOrientation currentOrientation; 24 | 25 | float topMargin; 26 | float tableHeight; 27 | } 28 | 29 | @property (nonatomic, assign) id delegate; 30 | @property (nonatomic, retain) UITableView *menuList; 31 | @property (nonatomic, retain) UIView *handle; 32 | 33 | /* Appearance Properties */ 34 | @property (nonatomic) float handleHeight; 35 | @property (nonatomic) float animationDuration; 36 | @property (nonatomic) float topMarginPortrait; 37 | @property (nonatomic) float topMarginLandscape; 38 | @property (nonatomic) UIColor *cellColor; 39 | @property (nonatomic) UIColor *cellSelectedColor; 40 | @property (nonatomic) UIColor *cellTextColor; 41 | @property (nonatomic) UITableViewCellSelectionStyle cellSelectionStyle; 42 | @property (nonatomic) UIFont *cellFont; 43 | @property (nonatomic) float cellHeight; 44 | @property (nonatomic) BOOL fullyOpen; 45 | 46 | - (id)initWithNavigationController:(UINavigationController *)navigationController; 47 | - (id)initWithView:(UIView *)view; 48 | - (void)insertButton:(NSString *)title; 49 | - (void)loadMenu; 50 | - (void)animateDropDown; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/PullDownMenu/PulldownMenu.m: -------------------------------------------------------------------------------- 1 | // 2 | // PulldownMenu.m 3 | // 4 | // Created by Bernard Gatt 5 | // 6 | 7 | #import "PulldownMenu.h" 8 | 9 | @implementation PulldownMenu 10 | 11 | @synthesize menuList, 12 | handle, 13 | cellHeight, 14 | handleHeight, 15 | animationDuration, 16 | topMarginLandscape, 17 | topMarginPortrait, 18 | cellColor, 19 | cellFont, 20 | cellTextColor, 21 | cellSelectedColor, 22 | cellSelectionStyle, 23 | fullyOpen, 24 | delegate; 25 | 26 | - (id)init 27 | { 28 | self = [super init]; 29 | 30 | menuItems = [[NSMutableArray alloc] init]; 31 | 32 | // Setting defaults 33 | cellHeight = 60.0f; 34 | handleHeight = 15.0f; 35 | animationDuration = 0.3f; 36 | topMarginPortrait = 0; 37 | topMarginLandscape = 0; 38 | cellColor = [UIColor grayColor]; 39 | cellSelectedColor = [UIColor blackColor]; 40 | cellFont = [UIFont fontWithName:@"GillSans-Bold" size:19.0f]; 41 | cellTextColor = [UIColor whiteColor]; 42 | cellSelectionStyle = UITableViewCellSelectionStyleDefault; 43 | 44 | return self; 45 | } 46 | 47 | - (id)initWithNavigationController:(UINavigationController *)navigationController 48 | { 49 | self = [self init]; 50 | 51 | if (self) 52 | { 53 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 54 | [[NSNotificationCenter defaultCenter] addObserver: self 55 | selector: @selector(deviceOrientationDidChange:) 56 | name: UIDeviceOrientationDidChangeNotification 57 | object: nil]; 58 | 59 | masterNavigationController = navigationController; 60 | 61 | navigationDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 62 | navigationDragGestureRecognizer.minimumNumberOfTouches = 1; 63 | navigationDragGestureRecognizer.maximumNumberOfTouches = 1; 64 | 65 | handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 66 | handleDragGestureRecognizer.minimumNumberOfTouches = 1; 67 | handleDragGestureRecognizer.maximumNumberOfTouches = 1; 68 | 69 | [masterNavigationController.navigationBar addGestureRecognizer:navigationDragGestureRecognizer]; 70 | 71 | masterView = masterNavigationController.view; 72 | } 73 | 74 | return self; 75 | } 76 | 77 | - (id)initWithView:(UIView *)view 78 | { 79 | self = [self init]; 80 | 81 | if (self) 82 | { 83 | topMargin = 0; 84 | masterView = view; 85 | } 86 | 87 | return self; 88 | } 89 | 90 | - (void)loadMenu 91 | { 92 | tableHeight = ([menuItems count] * cellHeight); 93 | 94 | [self updateValues]; 95 | 96 | [self setFrame:CGRectMake(0, 0, 0, tableHeight+handleHeight)]; 97 | 98 | fullyOpen = NO; 99 | 100 | menuList = [[UITableView alloc] init]; 101 | [menuList setRowHeight:cellHeight]; 102 | [menuList setDataSource:self]; 103 | [menuList setDelegate:self]; 104 | [self addSubview:menuList]; 105 | 106 | handle = [[UIView alloc] init]; 107 | [handle setBackgroundColor:[UIColor blackColor]]; 108 | 109 | [self addSubview:handle]; 110 | 111 | handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 112 | handleDragGestureRecognizer.minimumNumberOfTouches = 1; 113 | handleDragGestureRecognizer.maximumNumberOfTouches = 1; 114 | [handle addGestureRecognizer:handleDragGestureRecognizer]; 115 | 116 | [self setTranslatesAutoresizingMaskIntoConstraints:NO]; 117 | [handle setTranslatesAutoresizingMaskIntoConstraints:NO]; 118 | [menuList setTranslatesAutoresizingMaskIntoConstraints:NO]; 119 | 120 | [self createConstraints]; 121 | } 122 | 123 | - (void)insertButton:(NSString *)title 124 | { 125 | [menuItems addObject:title]; 126 | } 127 | 128 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 129 | { 130 | [self.delegate menuItemSelected:indexPath]; 131 | } 132 | 133 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 134 | return 1; 135 | } 136 | 137 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 138 | { 139 | return [menuItems count]; 140 | } 141 | 142 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 143 | { 144 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"menuListCell"]; 145 | 146 | if (cell == nil) { 147 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"menuListCell"]; 148 | } 149 | 150 | cell.backgroundColor = cellColor; 151 | 152 | UIView *cellSelectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame]; 153 | cellSelectedBackgroundView.backgroundColor = cellSelectedColor; 154 | cell.selectedBackgroundView = cellSelectedBackgroundView; 155 | cell.selectionStyle = cellSelectionStyle; 156 | 157 | [cell.textLabel setTextColor:cellTextColor]; 158 | cell.textLabel.font = cellFont; 159 | [cell.textLabel setText:[menuItems objectAtIndex:indexPath.item]]; 160 | 161 | return cell; 162 | } 163 | 164 | - (void)dragMenu:(UIPanGestureRecognizer *)sender 165 | { 166 | if ([sender state] == UIGestureRecognizerStateChanged) 167 | { 168 | CGPoint gesturePosition = [sender translationInView:masterNavigationController.navigationBar]; 169 | CGPoint newPosition = gesturePosition; 170 | 171 | newPosition.x = self.frame.size.width / 2; 172 | 173 | if (fullyOpen) 174 | { 175 | if (newPosition.y < 0) 176 | { 177 | newPosition.y += ((self.frame.size.height / 2) + topMargin); 178 | 179 | [self setCenter:newPosition]; 180 | } 181 | } 182 | else 183 | { 184 | newPosition.y += -((self.frame.size.height / 2) - topMargin); 185 | 186 | if (newPosition.y <= ((self.frame.size.height / 2) + topMargin)) 187 | { 188 | [self setCenter:newPosition]; 189 | } 190 | } 191 | } 192 | else if ([sender state] == UIGestureRecognizerStateEnded) 193 | { 194 | [self animateDropDown]; 195 | } 196 | } 197 | 198 | - (void)animateDropDown 199 | { 200 | 201 | [UIView animateWithDuration: animationDuration 202 | delay: 0.0 203 | options: UIViewAnimationOptionCurveEaseOut 204 | animations:^{ 205 | if (fullyOpen) 206 | { 207 | 208 | self.center = CGPointMake(self.frame.size.width / 2, -((self.frame.size.height / 2) + topMargin)); 209 | fullyOpen = NO; 210 | } 211 | else 212 | { 213 | self.center = CGPointMake(self.frame.size.width / 2, ((self.frame.size.height / 2) + topMargin)); 214 | fullyOpen = YES; 215 | } 216 | } 217 | completion:^(BOOL finished){ 218 | [delegate pullDownAnimated:fullyOpen]; 219 | }]; 220 | } 221 | 222 | - (void)createConstraints 223 | { 224 | 225 | NSLayoutConstraint *pullDownTopPositionConstraint = [NSLayoutConstraint 226 | constraintWithItem:self 227 | attribute:NSLayoutAttributeTop 228 | relatedBy:NSLayoutRelationEqual 229 | toItem:masterView 230 | attribute:NSLayoutAttributeTop 231 | multiplier:1.0 232 | constant:-self.frame.size.height]; 233 | 234 | NSLayoutConstraint *pullDownCenterXPositionConstraint = [NSLayoutConstraint 235 | constraintWithItem:self 236 | attribute:NSLayoutAttributeCenterX 237 | relatedBy:NSLayoutRelationEqual 238 | toItem:masterView 239 | attribute:NSLayoutAttributeCenterX 240 | multiplier:1.0 241 | constant:0]; 242 | 243 | NSLayoutConstraint *pullDownWidthConstraint = [NSLayoutConstraint 244 | constraintWithItem:self 245 | attribute:NSLayoutAttributeWidth 246 | relatedBy:NSLayoutRelationEqual 247 | toItem:masterView 248 | attribute:NSLayoutAttributeWidth 249 | multiplier:1.0 250 | constant:0]; 251 | 252 | NSLayoutConstraint *pullDownHeightMaxConstraint = [NSLayoutConstraint 253 | constraintWithItem:self 254 | attribute:NSLayoutAttributeHeight 255 | relatedBy:NSLayoutRelationLessThanOrEqual 256 | toItem:masterView 257 | attribute:NSLayoutAttributeHeight 258 | multiplier:0.5 259 | constant:0]; 260 | 261 | pullDownHeightMaxConstraint.priority = 1000; 262 | 263 | NSLayoutConstraint *pullDownHeightConstraint = [NSLayoutConstraint 264 | constraintWithItem:self 265 | attribute:NSLayoutAttributeHeight 266 | relatedBy:0 267 | toItem:nil 268 | attribute:NSLayoutAttributeNotAnAttribute 269 | multiplier:1.0 270 | constant:tableHeight+handleHeight]; 271 | 272 | pullDownHeightConstraint.priority = 900; 273 | 274 | NSLayoutConstraint *pullHandleWidthConstraint = [NSLayoutConstraint 275 | constraintWithItem:handle 276 | attribute:NSLayoutAttributeWidth 277 | relatedBy:NSLayoutRelationEqual 278 | toItem:masterView 279 | attribute:NSLayoutAttributeWidth 280 | multiplier:1.0 281 | constant:0]; 282 | 283 | NSLayoutConstraint *pullHandleHeightConstraint = [NSLayoutConstraint 284 | constraintWithItem:handle 285 | attribute:NSLayoutAttributeHeight 286 | relatedBy:0 287 | toItem:nil 288 | attribute:NSLayoutAttributeNotAnAttribute 289 | multiplier:1.0 290 | constant:handleHeight]; 291 | 292 | NSLayoutConstraint *pullHandleBottomPositionConstraint = [NSLayoutConstraint 293 | constraintWithItem:handle 294 | attribute:NSLayoutAttributeBottom 295 | relatedBy:NSLayoutRelationEqual 296 | toItem:self 297 | attribute:NSLayoutAttributeBottom 298 | multiplier:1.0 299 | constant:0]; 300 | 301 | NSLayoutConstraint *pullHandleCenterPositionConstraint = [NSLayoutConstraint 302 | constraintWithItem:handle 303 | attribute:NSLayoutAttributeCenterX 304 | relatedBy:0 305 | toItem:self 306 | attribute:NSLayoutAttributeCenterX 307 | multiplier:1.0 308 | constant:0]; 309 | 310 | NSLayoutConstraint *menuListHeightMaxConstraint = [NSLayoutConstraint 311 | constraintWithItem:menuList 312 | attribute:NSLayoutAttributeHeight 313 | relatedBy:NSLayoutRelationLessThanOrEqual 314 | toItem:masterView 315 | attribute:NSLayoutAttributeHeight 316 | multiplier:1.0 317 | constant:-topMargin]; 318 | 319 | NSLayoutConstraint *menuListHeightConstraint = [NSLayoutConstraint 320 | constraintWithItem:menuList 321 | attribute:NSLayoutAttributeHeight 322 | relatedBy:NSLayoutRelationEqual 323 | toItem:self 324 | attribute:NSLayoutAttributeHeight 325 | multiplier:1.0 326 | constant:-handleHeight]; 327 | 328 | NSLayoutConstraint *menuListWidthConstraint = [NSLayoutConstraint 329 | constraintWithItem:menuList 330 | attribute:NSLayoutAttributeWidth 331 | relatedBy:NSLayoutRelationEqual 332 | toItem:self 333 | attribute:NSLayoutAttributeWidth 334 | multiplier:1.0 335 | constant:0]; 336 | 337 | NSLayoutConstraint *menuListCenterXPositionConstraint = [NSLayoutConstraint 338 | constraintWithItem:menuList 339 | attribute:NSLayoutAttributeCenterX 340 | relatedBy:NSLayoutRelationEqual 341 | toItem:self 342 | attribute:NSLayoutAttributeCenterX 343 | multiplier:1.0 344 | constant:0]; 345 | 346 | NSLayoutConstraint *menuListTopPositionConstraint = [NSLayoutConstraint 347 | constraintWithItem:menuList 348 | attribute:NSLayoutAttributeTop 349 | relatedBy:NSLayoutRelationEqual 350 | toItem:self 351 | attribute:NSLayoutAttributeTop 352 | multiplier:1.0 353 | constant:0]; 354 | 355 | [masterView addConstraint: pullDownTopPositionConstraint]; 356 | [masterView addConstraint: pullDownCenterXPositionConstraint]; 357 | [masterView addConstraint: pullDownWidthConstraint]; 358 | [masterView addConstraint: pullDownHeightConstraint]; 359 | [masterView addConstraint: pullDownHeightMaxConstraint]; 360 | 361 | [masterView addConstraint: pullHandleHeightConstraint]; 362 | [masterView addConstraint: pullHandleWidthConstraint]; 363 | [masterView addConstraint: pullHandleBottomPositionConstraint]; 364 | [masterView addConstraint: pullHandleCenterPositionConstraint]; 365 | 366 | [masterView addConstraint: menuListHeightMaxConstraint]; 367 | [masterView addConstraint: menuListHeightConstraint]; 368 | [masterView addConstraint: menuListWidthConstraint]; 369 | [masterView addConstraint: menuListCenterXPositionConstraint]; 370 | [masterView addConstraint: menuListTopPositionConstraint]; 371 | 372 | } 373 | 374 | - (void)deviceOrientationDidChange:(NSNotification *)notification 375 | { 376 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 377 | 378 | if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || currentOrientation == orientation) { 379 | return; 380 | } 381 | 382 | currentOrientation = orientation; 383 | 384 | [self performSelector:@selector(orientationChanged) withObject:nil afterDelay:0]; 385 | } 386 | 387 | - (void)orientationChanged 388 | { 389 | [self updateValues]; 390 | 391 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 392 | if ((UIDeviceOrientationIsPortrait(currentOrientation) && UIDeviceOrientationIsPortrait(orientation)) || 393 | (UIDeviceOrientationIsLandscape(currentOrientation) && UIDeviceOrientationIsLandscape(orientation))) { 394 | 395 | currentOrientation = orientation; 396 | 397 | if (fullyOpen) 398 | { 399 | [self animateDropDown]; 400 | } 401 | 402 | return; 403 | } 404 | } 405 | 406 | - (void)updateValues 407 | { 408 | topMargin = 0; 409 | 410 | BOOL isStatusBarShowing = ![[UIApplication sharedApplication] isStatusBarHidden]; 411 | 412 | if (UIInterfaceOrientationIsLandscape(self.window.rootViewController.interfaceOrientation)) { 413 | if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.width; } 414 | topMargin += topMarginLandscape; 415 | } 416 | else 417 | { 418 | if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.height; } 419 | topMargin += topMarginPortrait; 420 | } 421 | 422 | if (masterNavigationController != nil) 423 | { 424 | topMargin += masterNavigationController.navigationBar.frame.size.height; 425 | } 426 | } 427 | 428 | @end 429 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ChartJSWrapper-IOS 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PulldownMenu.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ChartJSWrapper-IOS 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "CW.h" 11 | 12 | @interface ViewController () 13 | @property (weak, nonatomic) IBOutlet UIView *wview; 14 | @property (strong, nonatomic) WKWebView *webview; 15 | @property (strong) CWLineChart* lineChart; 16 | @property (strong) CWBarChart* barChart; 17 | @property (strong) CWPieChart* pieChart; 18 | @property (strong) PulldownMenu* pulldownMenu; 19 | 20 | - (IBAction)openMenu:(id)sender; 21 | 22 | - (void) createMenu; 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (NSInteger) random:(NSInteger) max { 28 | return (NSInteger)arc4random_uniform((u_int32_t)max); 29 | } 30 | 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | [self createMenu]; 34 | 35 | WKWebView* webview = [[WKWebView alloc] initWithFrame:self.wview.bounds]; 36 | [webview setTranslatesAutoresizingMaskIntoConstraints:NO]; 37 | [self.wview addSubview:webview]; 38 | 39 | NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(webview); 40 | [self.wview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[webview]|" options:0 metrics:nil views:viewsDictionary]]; 41 | [self.wview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webview]|" options:0 metrics:nil views:viewsDictionary]]; 42 | 43 | 44 | self.webview = webview; 45 | NSString *resourcesPath = [[NSBundle mainBundle] resourcePath]; 46 | NSString *htmlPath = [resourcesPath stringByAppendingString:@"/cw.html"]; 47 | [self.webview loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]]; 48 | } 49 | 50 | 51 | -(void)pullDownAnimated:(BOOL)open 52 | { 53 | if (open) 54 | { 55 | NSLog(@"Pull down menu open!"); 56 | } 57 | else 58 | { 59 | NSLog(@"Pull down menu closed!"); 60 | } 61 | } 62 | 63 | - (void) createMenu { 64 | self.pulldownMenu = [[PulldownMenu alloc] initWithView:self.view]; 65 | self.pulldownMenu.cellHeight = 25; 66 | self.pulldownMenu.cellFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0f]; 67 | [self.view addSubview:self.pulldownMenu]; 68 | 69 | [self.pulldownMenu insertButton:@"Line"]; 70 | [self.pulldownMenu insertButton:@"Radar"]; 71 | [self.pulldownMenu insertButton:@"Bar"]; 72 | [self.pulldownMenu insertButton:@"Polar Area"]; 73 | [self.pulldownMenu insertButton:@"Pie"]; 74 | [self.pulldownMenu insertButton:@"Doughnut"]; 75 | [self.pulldownMenu insertButton:@"Remove from/ Add to Pie"]; 76 | [self.pulldownMenu insertButton:@"Change Pie"]; 77 | [self.pulldownMenu insertButton:@"Change Bar"]; 78 | [self.pulldownMenu insertButton:@"Change Line"]; 79 | [self.pulldownMenu insertButton:@"Remove from/ Add to Line"]; 80 | 81 | self.pulldownMenu.delegate = self; 82 | 83 | [self.pulldownMenu loadMenu]; 84 | 85 | } 86 | - (void)didReceiveMemoryWarning { 87 | [super didReceiveMemoryWarning]; 88 | // Dispose of any resources that can be recreated. 89 | } 90 | 91 | - (IBAction)openMenu:(id)sender { 92 | [self.pulldownMenu animateDropDown]; 93 | } 94 | 95 | -(void)menuItemSelected:(NSIndexPath *)indexPath 96 | { 97 | [self.pulldownMenu animateDropDown]; 98 | switch(indexPath.item) { 99 | case 0: 100 | [self addLine]; 101 | break; 102 | case 1: 103 | [self addRadar]; 104 | break; 105 | case 2: 106 | [self addBar]; 107 | break; 108 | case 3: 109 | [self addPolarArea]; 110 | break; 111 | case 4: 112 | [self addPie]; 113 | break; 114 | case 5: 115 | [self addDoughnut]; 116 | break; 117 | case 6: 118 | [self delAddPie]; 119 | break; 120 | case 7: 121 | [self changePie]; 122 | break; 123 | case 8: 124 | [self changeBar]; 125 | break; 126 | case 9: 127 | [self changeLine]; 128 | break; 129 | case 10: 130 | [self delAddLine]; 131 | break; 132 | } 133 | } 134 | 135 | #pragma mark - 136 | #pragma mark Chart Calls 137 | 138 | - (void)addLine { 139 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 140 | NSMutableArray* datasets = [NSMutableArray array]; 141 | for(NSInteger i = 1; i < 4; i++) { 142 | CWPointDataSet* ds = [[CWPointDataSet alloc] initWithData:@[@([self random:100]),@([self random:100]),@([self random:100]),@([self random:100])]]; 143 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 144 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 145 | CWColor* c2 = [c1 colorWithAlphaComponent:0.5f]; 146 | ds.fillColor = c2; 147 | ds.strokeColor = c1; 148 | [datasets addObject:ds]; 149 | } 150 | 151 | CWLineChartData* lcd = [[CWLineChartData alloc] initWithLabels:labels andDataSet:datasets]; 152 | self.lineChart = [[CWLineChart alloc] initWithWebView:self.webview name:@"LineChart1" width:300 height:200 data:lcd options:nil]; 153 | [self.lineChart addChart]; 154 | } 155 | 156 | - (void)delAddLine { 157 | [self.lineChart removeData]; 158 | [self.lineChart addData:@[@([self random:100]),@([self random:100]),@([self random:100]),@([self random:100])] label:@"W"]; 159 | } 160 | 161 | - (void)changeLine { 162 | for(NSInteger i = 1; i < 4; i++) { 163 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:0]; 164 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:1]; 165 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:2]; 166 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:3]; 167 | } 168 | [self.lineChart update]; 169 | } 170 | 171 | - (void)addBar { 172 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 173 | NSMutableArray* datasets = [NSMutableArray array]; 174 | for(NSInteger i = 1; i < 4; i++) { 175 | CWBarDataSet* ds = [[CWBarDataSet alloc] initWithData:@[@([self random:100]+50),@([self random:100]+50),@([self random:100]+50),@([self random:100]+50)]]; 176 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 177 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 178 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 179 | ds.fillColor = c2; 180 | ds.strokeColor = c1; 181 | [datasets addObject:ds]; 182 | } 183 | // id win = [self.webview windowScriptObject]; 184 | 185 | CWBarChartData* bcd = [[CWBarChartData alloc] initWithLabels:labels andDataSet:datasets]; 186 | CWBarChart* bc = [[CWBarChart alloc] initWithWebView:self.webview name:@"BarChart1" width:300 height:200 data:bcd options:nil]; 187 | [bc addChart]; 188 | self.barChart = bc; 189 | } 190 | 191 | - (void)addPolarArea { 192 | NSMutableArray* data = [NSMutableArray array]; 193 | for(NSInteger i = 1; i < 11; i++) { 194 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 195 | segment.value = @([self random:100]+50); 196 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 197 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 198 | segment.color = c2; 199 | segment.highlight = c1; 200 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 201 | [data addObject:segment]; 202 | } 203 | // id win = [self.webview windowScriptObject]; 204 | CWPolarAreaChart* pac = [[CWPolarAreaChart alloc] initWithWebView:self.webview name:@"PAC1" width:300 height:300 data:data options:nil]; 205 | [pac addChart]; 206 | } 207 | 208 | - (void)addPie { 209 | NSMutableArray* data = [NSMutableArray array]; 210 | for(NSInteger i = 1; i < 11; i++) { 211 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 212 | segment.value = @([self random:100]+50); 213 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 214 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 215 | segment.color = c2; 216 | segment.highlight = c1; 217 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 218 | [data addObject:segment]; 219 | } 220 | // id win = [self.webview windowScriptObject]; 221 | CWPieChart* pc = [[CWPieChart alloc] initWithWebView:self.webview name:@"PIE1" width:300 height:300 data:data options:nil]; 222 | [pc addChart]; 223 | self.pieChart = pc; 224 | } 225 | 226 | - (void)addDoughnut { 227 | NSMutableArray* data = [NSMutableArray array]; 228 | for(NSInteger i = 1; i < 11; i++) { 229 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 230 | segment.value = @([self random:100]+50); 231 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 232 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 233 | segment.color = c2; 234 | segment.highlight = c1; 235 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 236 | [data addObject:segment]; 237 | } 238 | // id win = [self.webview windowScriptObject]; 239 | CWDoughnutChart* pc = [[CWDoughnutChart alloc] initWithWebView:self.webview name:@"Doughnut1" width:300 height:300 data:data options:nil]; 240 | [pc addChart]; 241 | } 242 | 243 | - (void)changePie { 244 | for(NSInteger i = 1; i < 11; i++) { 245 | [self.pieChart setValue:@([self random:100]+50) inSegment:i-1]; 246 | } 247 | [self.pieChart update]; 248 | } 249 | 250 | - (void)changeBar { 251 | for(NSInteger i = 1; i < 4; i++) { 252 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:0]; 253 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:1]; 254 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:2]; 255 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:3]; 256 | } 257 | [self.barChart update]; 258 | } 259 | 260 | - (void)delAddPie { 261 | [self.pieChart removeDataAt:@(1)]; 262 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 263 | segment.value = @([self random:100]+50); 264 | CWColor* c = [[CWColor lightGrayColor] colorWithAlphaComponent:0.8f]; 265 | segment.color = c; 266 | segment.highlight = [CWColor grayColor]; 267 | segment.label = @"NEW SEGMENT"; 268 | [self.pieChart addData:segment index:@(3)]; 269 | } 270 | 271 | - (void)addRadar { 272 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 273 | NSMutableArray* datasets = [NSMutableArray array]; 274 | for(NSInteger i = 1; i < 4; i++) { 275 | CWPointDataSet* ds = [[CWPointDataSet alloc] initWithData:@[@([self random:100]+50),@([self random:100]+50),@([self random:100]+50),@([self random:100]+50)]]; 276 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 277 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 278 | CWColor* c2 = [c1 colorWithAlphaComponent:0.5f]; 279 | ds.fillColor = c2; 280 | ds.strokeColor = c1; 281 | [datasets addObject:ds]; 282 | } 283 | 284 | CWRadarChartData* rcd = [[CWRadarChartData alloc] initWithLabels:labels andDataSet:datasets]; 285 | CWRadarChart* rc = [[CWRadarChart alloc] initWithWebView:self.webview name:@"RadarChart1" width:300 height:300 data:rcd options:nil]; 286 | [rc addChart]; 287 | } 288 | 289 | 290 | @end 291 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyetvan-andras/Chart.js-ObjC-Wrapper/3c20bb53dbf0d17d636699d0e4155bd73840600a/ChartJSWrapper/ChartJSWrapper-IOS/img.png -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ChartJSWrapper-IOS 4 | // 5 | // Created by András Gyetván on 24/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper-IOS/settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyetvan-andras/Chart.js-ObjC-Wrapper/3c20bb53dbf0d17d636699d0e4155bd73840600a/ChartJSWrapper/ChartJSWrapper-IOS/settings@2x.png -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface AppDelegate : NSObject 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "CW.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @property (weak) IBOutlet NSWindow *window; 15 | @property (weak) IBOutlet WebView *webview; 16 | - (IBAction)addRadar:(id)sender; 17 | - (IBAction)addLine:(id)sender; 18 | - (IBAction)removeLine:(id)sender; 19 | - (IBAction)changeLine:(id)sender; 20 | - (IBAction)addBar:(id)sender; 21 | - (IBAction)addPolarArea:(id)sender; 22 | - (IBAction)addPie:(id)sender; 23 | - (IBAction)addDoughnut:(id)sender; 24 | 25 | - (IBAction)changePie:(id)sender; 26 | - (IBAction)changeBar:(id)sender; 27 | - (IBAction)delAddPie:(id)sender; 28 | 29 | @property (nonatomic, strong) CWLineChart* lineChart; 30 | @property (nonatomic, strong) CWPieChart* pieChart; 31 | @property (nonatomic, strong) CWBarChart* barChart; 32 | 33 | @end 34 | 35 | @implementation AppDelegate 36 | 37 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 38 | NSString *resourcesPath = [[NSBundle mainBundle] resourcePath]; 39 | NSString *htmlPath = [resourcesPath stringByAppendingString:@"/cw.html"]; 40 | [[self.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]]; 41 | } 42 | 43 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 44 | // Insert code here to tear down your application 45 | } 46 | 47 | - (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { 48 | return YES; 49 | } 50 | 51 | - (NSInteger) random:(NSInteger) max { 52 | return (NSInteger)arc4random_uniform((u_int32_t)max); 53 | } 54 | 55 | - (IBAction)addLine:(id)sender { 56 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 57 | NSMutableArray* datasets = [NSMutableArray array]; 58 | for(NSInteger i = 1; i < 4; i++) { 59 | CWPointDataSet* ds = [[CWPointDataSet alloc] initWithData:@[@([self random:100]),@([self random:100]),@([self random:100]),@([self random:100])]]; 60 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 61 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 62 | CWColor* c2 = [c1 colorWithAlphaComponent:0.5f]; 63 | ds.fillColor = c2; 64 | ds.strokeColor = c1; 65 | [datasets addObject:ds]; 66 | } 67 | // id win = [self.webview windowScriptObject]; 68 | 69 | CWLineChartData* lcd = [[CWLineChartData alloc] initWithLabels:labels andDataSet:datasets]; 70 | self.lineChart = [[CWLineChart alloc] initWithWebView:self.webview name:@"LineChart1" width:600 height:300 data:lcd options:nil]; 71 | [self.lineChart addChart]; 72 | } 73 | 74 | - (IBAction)removeLine:(id)sender { 75 | [self.lineChart removeData]; 76 | [self.lineChart addData:@[@([self random:100]),@([self random:100])/*,@([self random:100]),@([self random:100])*/] label:@"W"]; 77 | } 78 | 79 | - (IBAction)changeLine:(id)sender { 80 | for(NSInteger i = 1; i < 4; i++) { 81 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:0]; 82 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:1]; 83 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:2]; 84 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:3]; 85 | } 86 | [self.lineChart update]; 87 | } 88 | 89 | - (IBAction)addBar:(id)sender { 90 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 91 | NSMutableArray* datasets = [NSMutableArray array]; 92 | for(NSInteger i = 1; i < 4; i++) { 93 | CWBarDataSet* ds = [[CWBarDataSet alloc] initWithData:@[@([self random:100]+50),@([self random:100]+50),@([self random:100]+50),@([self random:100]+50)]]; 94 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 95 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 96 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 97 | ds.fillColor = c2; 98 | ds.strokeColor = c1; 99 | [datasets addObject:ds]; 100 | } 101 | // id win = [self.webview windowScriptObject]; 102 | 103 | CWBarChartData* bcd = [[CWBarChartData alloc] initWithLabels:labels andDataSet:datasets]; 104 | CWBarChart* bc = [[CWBarChart alloc] initWithWebView:self.webview name:@"BarChart1" width:600 height:300 data:bcd options:nil]; 105 | [bc addChart]; 106 | self.barChart = bc; 107 | } 108 | 109 | - (IBAction)addPolarArea:(id)sender { 110 | NSMutableArray* data = [NSMutableArray array]; 111 | for(NSInteger i = 1; i < 11; i++) { 112 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 113 | segment.value = @([self random:100]+50); 114 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 115 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 116 | segment.color = c2; 117 | segment.highlight = c1; 118 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 119 | [data addObject:segment]; 120 | } 121 | // id win = [self.webview windowScriptObject]; 122 | CWPolarAreaChart* pac = [[CWPolarAreaChart alloc] initWithWebView:self.webview name:@"PAC1" width:600 height:300 data:data options:nil]; 123 | [pac addChart]; 124 | } 125 | 126 | - (IBAction)addPie:(id)sender { 127 | NSMutableArray* data = [NSMutableArray array]; 128 | for(NSInteger i = 1; i < 11; i++) { 129 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 130 | segment.value = @([self random:100]+50); 131 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 132 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 133 | segment.color = c2; 134 | segment.highlight = c1; 135 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 136 | [data addObject:segment]; 137 | } 138 | // id win = [self.webview windowScriptObject]; 139 | CWPieChart* pc = [[CWPieChart alloc] initWithWebView:self.webview name:@"PIE1" width:600 height:300 data:data options:nil]; 140 | [pc addChart]; 141 | self.pieChart = pc; 142 | } 143 | 144 | - (IBAction)addDoughnut:(id)sender { 145 | NSMutableArray* data = [NSMutableArray array]; 146 | for(NSInteger i = 1; i < 11; i++) { 147 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 148 | segment.value = @([self random:100]+50); 149 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 150 | CWColor* c2 = [c1 colorWithAlphaComponent:0.8f]; 151 | segment.color = c2; 152 | segment.highlight = c1; 153 | segment.label = [NSString stringWithFormat:@"Label %ld",i]; 154 | [data addObject:segment]; 155 | } 156 | // id win = [self.webview windowScriptObject]; 157 | CWDoughnutChart* pc = [[CWDoughnutChart alloc] initWithWebView:self.webview name:@"Doughnut1" width:600 height:300 data:data options:nil]; 158 | [pc addChart]; 159 | } 160 | 161 | - (IBAction)changePie:(id)sender { 162 | for(NSInteger i = 1; i < 11; i++) { 163 | [self.pieChart setValue:@([self random:100]+50) inSegment:i-1]; 164 | } 165 | [self.pieChart update]; 166 | } 167 | 168 | - (IBAction)changeBar:(id)sender { 169 | for(NSInteger i = 1; i < 4; i++) { 170 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:0]; 171 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:1]; 172 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:2]; 173 | [self.barChart setValue:@([self random:100]+50) inDataset:i-1 at:3]; 174 | } 175 | [self.barChart update]; 176 | } 177 | 178 | - (IBAction)delAddPie:(id)sender { 179 | [self.pieChart removeDataAt:@(1)]; 180 | CWSegmentData* segment = [[CWSegmentData alloc] init]; 181 | segment.value = @([self random:100]+50); 182 | CWColor* c = [[CWColor lightGrayColor] colorWithAlphaComponent:0.8f]; 183 | segment.color = c; 184 | segment.highlight = [CWColor grayColor]; 185 | segment.label = @"NEW SEGMENT"; 186 | [self.pieChart addData:segment index:@(3)]; 187 | // [self.lineChart addData:@[@([self random:100]),@([self random:100])/*,@([self random:100]),@([self random:100])*/] label:@"W"]; 188 | } 189 | 190 | - (IBAction)addRadar:(id)sender { 191 | NSArray* labels = [NSMutableArray arrayWithArray:@[@"A",@"B",@"C",@"D"]]; 192 | NSMutableArray* datasets = [NSMutableArray array]; 193 | for(NSInteger i = 1; i < 4; i++) { 194 | CWPointDataSet* ds = [[CWPointDataSet alloc] initWithData:@[@([self random:100]+50),@([self random:100]+50),@([self random:100]+50),@([self random:100]+50)]]; 195 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 196 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 197 | CWColor* c2 = [c1 colorWithAlphaComponent:0.5f]; 198 | ds.fillColor = c2; 199 | ds.strokeColor = c1; 200 | [datasets addObject:ds]; 201 | } 202 | // id win = [self.webview windowScriptObject]; 203 | 204 | CWRadarChartData* rcd = [[CWRadarChartData alloc] initWithLabels:labels andDataSet:datasets]; 205 | CWRadarChart* rc = [[CWRadarChart alloc] initWithWebView:self.webview name:@"RadarChart1" width:600 height:300 data:rcd options:nil]; 206 | [rc addChart]; 207 | } 208 | 209 | @end 210 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | hu.gyand.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2015 Gyetván András. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /ChartJSWrapper/ChartJSWrapper/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ChartJSWrapper 4 | // 5 | // Created by András Gyetván on 20/03/15. 6 | // Copyright (c) 2015 Gyetván András. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /ChartJSWrapper/PullDownMenu/PulldownMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // PulldownMenu.h 3 | // 4 | // Created by Bernard Gatt 5 | // 6 | 7 | #import 8 | 9 | @protocol PulldownMenuDelegate 10 | -(void)menuItemSelected:(NSIndexPath *)indexPath; 11 | -(void)pullDownAnimated:(BOOL)open; 12 | @end 13 | 14 | @interface PulldownMenu : UIView { 15 | UITableView *menuList; 16 | NSMutableArray *menuItems; 17 | 18 | UIView *handle; 19 | UIView *masterView; 20 | UIPanGestureRecognizer *navigationDragGestureRecognizer; 21 | UIPanGestureRecognizer *handleDragGestureRecognizer; 22 | UINavigationController *masterNavigationController; 23 | UIDeviceOrientation currentOrientation; 24 | 25 | float topMargin; 26 | float tableHeight; 27 | } 28 | 29 | @property (nonatomic, assign) id delegate; 30 | @property (nonatomic, retain) UITableView *menuList; 31 | @property (nonatomic, retain) UIView *handle; 32 | 33 | /* Appearance Properties */ 34 | @property (nonatomic) float handleHeight; 35 | @property (nonatomic) float animationDuration; 36 | @property (nonatomic) float topMarginPortrait; 37 | @property (nonatomic) float topMarginLandscape; 38 | @property (nonatomic) UIColor *cellColor; 39 | @property (nonatomic) UIColor *cellSelectedColor; 40 | @property (nonatomic) UIColor *cellTextColor; 41 | @property (nonatomic) UITableViewCellSelectionStyle cellSelectionStyle; 42 | @property (nonatomic) UIFont *cellFont; 43 | @property (nonatomic) float cellHeight; 44 | @property (nonatomic) BOOL fullyOpen; 45 | 46 | - (id)initWithNavigationController:(UINavigationController *)navigationController; 47 | - (id)initWithView:(UIView *)view; 48 | - (void)insertButton:(NSString *)title; 49 | - (void)loadMenu; 50 | - (void)animateDropDown; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /ChartJSWrapper/PullDownMenu/PulldownMenu.m: -------------------------------------------------------------------------------- 1 | // 2 | // PulldownMenu.m 3 | // 4 | // Created by Bernard Gatt 5 | // 6 | 7 | #import "PulldownMenu.h" 8 | 9 | @implementation PulldownMenu 10 | 11 | @synthesize menuList, 12 | handle, 13 | cellHeight, 14 | handleHeight, 15 | animationDuration, 16 | topMarginLandscape, 17 | topMarginPortrait, 18 | cellColor, 19 | cellFont, 20 | cellTextColor, 21 | cellSelectedColor, 22 | cellSelectionStyle, 23 | fullyOpen, 24 | delegate; 25 | 26 | - (id)init 27 | { 28 | self = [super init]; 29 | 30 | menuItems = [[NSMutableArray alloc] init]; 31 | 32 | // Setting defaults 33 | cellHeight = 60.0f; 34 | handleHeight = 15.0f; 35 | animationDuration = 0.3f; 36 | topMarginPortrait = 0; 37 | topMarginLandscape = 0; 38 | cellColor = [UIColor grayColor]; 39 | cellSelectedColor = [UIColor blackColor]; 40 | cellFont = [UIFont fontWithName:@"GillSans-Bold" size:19.0f]; 41 | cellTextColor = [UIColor whiteColor]; 42 | cellSelectionStyle = UITableViewCellSelectionStyleDefault; 43 | 44 | return self; 45 | } 46 | 47 | - (id)initWithNavigationController:(UINavigationController *)navigationController 48 | { 49 | self = [self init]; 50 | 51 | if (self) 52 | { 53 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 54 | [[NSNotificationCenter defaultCenter] addObserver: self 55 | selector: @selector(deviceOrientationDidChange:) 56 | name: UIDeviceOrientationDidChangeNotification 57 | object: nil]; 58 | 59 | masterNavigationController = navigationController; 60 | 61 | navigationDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 62 | navigationDragGestureRecognizer.minimumNumberOfTouches = 1; 63 | navigationDragGestureRecognizer.maximumNumberOfTouches = 1; 64 | 65 | handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 66 | handleDragGestureRecognizer.minimumNumberOfTouches = 1; 67 | handleDragGestureRecognizer.maximumNumberOfTouches = 1; 68 | 69 | [masterNavigationController.navigationBar addGestureRecognizer:navigationDragGestureRecognizer]; 70 | 71 | masterView = masterNavigationController.view; 72 | } 73 | 74 | return self; 75 | } 76 | 77 | - (id)initWithView:(UIView *)view 78 | { 79 | self = [self init]; 80 | 81 | if (self) 82 | { 83 | topMargin = 0; 84 | masterView = view; 85 | } 86 | 87 | return self; 88 | } 89 | 90 | - (void)loadMenu 91 | { 92 | tableHeight = ([menuItems count] * cellHeight); 93 | 94 | [self updateValues]; 95 | 96 | [self setFrame:CGRectMake(0, 0, 0, tableHeight+handleHeight)]; 97 | 98 | fullyOpen = NO; 99 | 100 | menuList = [[UITableView alloc] init]; 101 | [menuList setRowHeight:cellHeight]; 102 | [menuList setDataSource:self]; 103 | [menuList setDelegate:self]; 104 | [self addSubview:menuList]; 105 | 106 | handle = [[UIView alloc] init]; 107 | [handle setBackgroundColor:[UIColor blackColor]]; 108 | 109 | [self addSubview:handle]; 110 | 111 | handleDragGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragMenu:)]; 112 | handleDragGestureRecognizer.minimumNumberOfTouches = 1; 113 | handleDragGestureRecognizer.maximumNumberOfTouches = 1; 114 | [handle addGestureRecognizer:handleDragGestureRecognizer]; 115 | 116 | [self setTranslatesAutoresizingMaskIntoConstraints:NO]; 117 | [handle setTranslatesAutoresizingMaskIntoConstraints:NO]; 118 | [menuList setTranslatesAutoresizingMaskIntoConstraints:NO]; 119 | 120 | [self createConstraints]; 121 | } 122 | 123 | - (void)insertButton:(NSString *)title 124 | { 125 | [menuItems addObject:title]; 126 | } 127 | 128 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 129 | { 130 | [self.delegate menuItemSelected:indexPath]; 131 | } 132 | 133 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 134 | return 1; 135 | } 136 | 137 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 138 | { 139 | return [menuItems count]; 140 | } 141 | 142 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 143 | { 144 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"menuListCell"]; 145 | 146 | if (cell == nil) { 147 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"menuListCell"]; 148 | } 149 | 150 | cell.backgroundColor = cellColor; 151 | 152 | UIView *cellSelectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame]; 153 | cellSelectedBackgroundView.backgroundColor = cellSelectedColor; 154 | cell.selectedBackgroundView = cellSelectedBackgroundView; 155 | cell.selectionStyle = cellSelectionStyle; 156 | 157 | [cell.textLabel setTextColor:cellTextColor]; 158 | cell.textLabel.font = cellFont; 159 | [cell.textLabel setText:[menuItems objectAtIndex:indexPath.item]]; 160 | 161 | return cell; 162 | } 163 | 164 | - (void)dragMenu:(UIPanGestureRecognizer *)sender 165 | { 166 | if ([sender state] == UIGestureRecognizerStateChanged) 167 | { 168 | CGPoint gesturePosition = [sender translationInView:masterNavigationController.navigationBar]; 169 | CGPoint newPosition = gesturePosition; 170 | 171 | newPosition.x = self.frame.size.width / 2; 172 | 173 | if (fullyOpen) 174 | { 175 | if (newPosition.y < 0) 176 | { 177 | newPosition.y += ((self.frame.size.height / 2) + topMargin); 178 | 179 | [self setCenter:newPosition]; 180 | } 181 | } 182 | else 183 | { 184 | newPosition.y += -((self.frame.size.height / 2) - topMargin); 185 | 186 | if (newPosition.y <= ((self.frame.size.height / 2) + topMargin)) 187 | { 188 | [self setCenter:newPosition]; 189 | } 190 | } 191 | } 192 | else if ([sender state] == UIGestureRecognizerStateEnded) 193 | { 194 | [self animateDropDown]; 195 | } 196 | } 197 | 198 | - (void)animateDropDown 199 | { 200 | 201 | [UIView animateWithDuration: animationDuration 202 | delay: 0.0 203 | options: UIViewAnimationOptionCurveEaseOut 204 | animations:^{ 205 | if (fullyOpen) 206 | { 207 | 208 | self.center = CGPointMake(self.frame.size.width / 2, -((self.frame.size.height / 2) + topMargin)); 209 | fullyOpen = NO; 210 | } 211 | else 212 | { 213 | self.center = CGPointMake(self.frame.size.width / 2, ((self.frame.size.height / 2) + topMargin)); 214 | fullyOpen = YES; 215 | } 216 | } 217 | completion:^(BOOL finished){ 218 | [delegate pullDownAnimated:fullyOpen]; 219 | }]; 220 | } 221 | 222 | - (void)createConstraints 223 | { 224 | 225 | NSLayoutConstraint *pullDownTopPositionConstraint = [NSLayoutConstraint 226 | constraintWithItem:self 227 | attribute:NSLayoutAttributeTop 228 | relatedBy:NSLayoutRelationEqual 229 | toItem:masterView 230 | attribute:NSLayoutAttributeTop 231 | multiplier:1.0 232 | constant:-self.frame.size.height]; 233 | 234 | NSLayoutConstraint *pullDownCenterXPositionConstraint = [NSLayoutConstraint 235 | constraintWithItem:self 236 | attribute:NSLayoutAttributeCenterX 237 | relatedBy:NSLayoutRelationEqual 238 | toItem:masterView 239 | attribute:NSLayoutAttributeCenterX 240 | multiplier:1.0 241 | constant:0]; 242 | 243 | NSLayoutConstraint *pullDownWidthConstraint = [NSLayoutConstraint 244 | constraintWithItem:self 245 | attribute:NSLayoutAttributeWidth 246 | relatedBy:NSLayoutRelationEqual 247 | toItem:masterView 248 | attribute:NSLayoutAttributeWidth 249 | multiplier:1.0 250 | constant:0]; 251 | 252 | NSLayoutConstraint *pullDownHeightMaxConstraint = [NSLayoutConstraint 253 | constraintWithItem:self 254 | attribute:NSLayoutAttributeHeight 255 | relatedBy:NSLayoutRelationLessThanOrEqual 256 | toItem:masterView 257 | attribute:NSLayoutAttributeHeight 258 | multiplier:0.5 259 | constant:0]; 260 | 261 | pullDownHeightMaxConstraint.priority = 1000; 262 | 263 | NSLayoutConstraint *pullDownHeightConstraint = [NSLayoutConstraint 264 | constraintWithItem:self 265 | attribute:NSLayoutAttributeHeight 266 | relatedBy:0 267 | toItem:nil 268 | attribute:NSLayoutAttributeNotAnAttribute 269 | multiplier:1.0 270 | constant:tableHeight+handleHeight]; 271 | 272 | pullDownHeightConstraint.priority = 900; 273 | 274 | NSLayoutConstraint *pullHandleWidthConstraint = [NSLayoutConstraint 275 | constraintWithItem:handle 276 | attribute:NSLayoutAttributeWidth 277 | relatedBy:NSLayoutRelationEqual 278 | toItem:masterView 279 | attribute:NSLayoutAttributeWidth 280 | multiplier:1.0 281 | constant:0]; 282 | 283 | NSLayoutConstraint *pullHandleHeightConstraint = [NSLayoutConstraint 284 | constraintWithItem:handle 285 | attribute:NSLayoutAttributeHeight 286 | relatedBy:0 287 | toItem:nil 288 | attribute:NSLayoutAttributeNotAnAttribute 289 | multiplier:1.0 290 | constant:handleHeight]; 291 | 292 | NSLayoutConstraint *pullHandleBottomPositionConstraint = [NSLayoutConstraint 293 | constraintWithItem:handle 294 | attribute:NSLayoutAttributeBottom 295 | relatedBy:NSLayoutRelationEqual 296 | toItem:self 297 | attribute:NSLayoutAttributeBottom 298 | multiplier:1.0 299 | constant:0]; 300 | 301 | NSLayoutConstraint *pullHandleCenterPositionConstraint = [NSLayoutConstraint 302 | constraintWithItem:handle 303 | attribute:NSLayoutAttributeCenterX 304 | relatedBy:0 305 | toItem:self 306 | attribute:NSLayoutAttributeCenterX 307 | multiplier:1.0 308 | constant:0]; 309 | 310 | NSLayoutConstraint *menuListHeightMaxConstraint = [NSLayoutConstraint 311 | constraintWithItem:menuList 312 | attribute:NSLayoutAttributeHeight 313 | relatedBy:NSLayoutRelationLessThanOrEqual 314 | toItem:masterView 315 | attribute:NSLayoutAttributeHeight 316 | multiplier:1.0 317 | constant:-topMargin]; 318 | 319 | NSLayoutConstraint *menuListHeightConstraint = [NSLayoutConstraint 320 | constraintWithItem:menuList 321 | attribute:NSLayoutAttributeHeight 322 | relatedBy:NSLayoutRelationEqual 323 | toItem:self 324 | attribute:NSLayoutAttributeHeight 325 | multiplier:1.0 326 | constant:-handleHeight]; 327 | 328 | NSLayoutConstraint *menuListWidthConstraint = [NSLayoutConstraint 329 | constraintWithItem:menuList 330 | attribute:NSLayoutAttributeWidth 331 | relatedBy:NSLayoutRelationEqual 332 | toItem:self 333 | attribute:NSLayoutAttributeWidth 334 | multiplier:1.0 335 | constant:0]; 336 | 337 | NSLayoutConstraint *menuListCenterXPositionConstraint = [NSLayoutConstraint 338 | constraintWithItem:menuList 339 | attribute:NSLayoutAttributeCenterX 340 | relatedBy:NSLayoutRelationEqual 341 | toItem:self 342 | attribute:NSLayoutAttributeCenterX 343 | multiplier:1.0 344 | constant:0]; 345 | 346 | NSLayoutConstraint *menuListTopPositionConstraint = [NSLayoutConstraint 347 | constraintWithItem:menuList 348 | attribute:NSLayoutAttributeTop 349 | relatedBy:NSLayoutRelationEqual 350 | toItem:self 351 | attribute:NSLayoutAttributeTop 352 | multiplier:1.0 353 | constant:0]; 354 | 355 | [masterView addConstraint: pullDownTopPositionConstraint]; 356 | [masterView addConstraint: pullDownCenterXPositionConstraint]; 357 | [masterView addConstraint: pullDownWidthConstraint]; 358 | [masterView addConstraint: pullDownHeightConstraint]; 359 | [masterView addConstraint: pullDownHeightMaxConstraint]; 360 | 361 | [masterView addConstraint: pullHandleHeightConstraint]; 362 | [masterView addConstraint: pullHandleWidthConstraint]; 363 | [masterView addConstraint: pullHandleBottomPositionConstraint]; 364 | [masterView addConstraint: pullHandleCenterPositionConstraint]; 365 | 366 | [masterView addConstraint: menuListHeightMaxConstraint]; 367 | [masterView addConstraint: menuListHeightConstraint]; 368 | [masterView addConstraint: menuListWidthConstraint]; 369 | [masterView addConstraint: menuListCenterXPositionConstraint]; 370 | [masterView addConstraint: menuListTopPositionConstraint]; 371 | 372 | } 373 | 374 | - (void)deviceOrientationDidChange:(NSNotification *)notification 375 | { 376 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 377 | 378 | if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || currentOrientation == orientation) { 379 | return; 380 | } 381 | 382 | currentOrientation = orientation; 383 | 384 | [self performSelector:@selector(orientationChanged) withObject:nil afterDelay:0]; 385 | } 386 | 387 | - (void)orientationChanged 388 | { 389 | [self updateValues]; 390 | 391 | UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; 392 | if ((UIDeviceOrientationIsPortrait(currentOrientation) && UIDeviceOrientationIsPortrait(orientation)) || 393 | (UIDeviceOrientationIsLandscape(currentOrientation) && UIDeviceOrientationIsLandscape(orientation))) { 394 | 395 | currentOrientation = orientation; 396 | 397 | if (fullyOpen) 398 | { 399 | [self animateDropDown]; 400 | } 401 | 402 | return; 403 | } 404 | } 405 | 406 | - (void)updateValues 407 | { 408 | topMargin = 0; 409 | 410 | BOOL isStatusBarShowing = ![[UIApplication sharedApplication] isStatusBarHidden]; 411 | 412 | if (UIInterfaceOrientationIsLandscape(self.window.rootViewController.interfaceOrientation)) { 413 | if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.width; } 414 | topMargin += topMarginLandscape; 415 | } 416 | else 417 | { 418 | if (isStatusBarShowing) { topMargin = [UIApplication.sharedApplication statusBarFrame].size.height; } 419 | topMargin += topMarginPortrait; 420 | } 421 | 422 | if (masterNavigationController != nil) 423 | { 424 | topMargin += masterNavigationController.navigationBar.frame.size.height; 425 | } 426 | } 427 | 428 | @end 429 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Gyetván András 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chart.js-ObjC-Wrapper 2 | An Objective-C wrapper around Chart.js. 3 | 4 |

    5 | Sample 6 |

    7 | Chart.js wrapper 8 |

    9 |

    10 | 11 | # Description 12 | This package can be used in conjunction with WKWebView/WebView to add [Chart.js](http://www.chartjs.org) charts to a native iOS/OSX application. 13 | 14 | 15 | # Usage 16 | ## Project preparation 17 | 1. add WebKit framework to you app 18 | 2. add all the files in CW folder to your project 19 | 3. include CW.h 20 | 21 | Chart.js wrapper needs a webview to use to execute java script functions and display the chart. You need to prepare the webview to include Char.js script and cw.js which provides java script functions to the wrapper. 22 | 23 | ### iOS 24 | You need to add a WKWebView to your ui and load the cw.html. 25 | ```objective-c 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | [self createMenu]; 29 | 30 | WKWebView* webview = [[WKWebView alloc] initWithFrame:self.wview.bounds]; 31 | 32 | // ... add code here to insert webview to UI - for an example see the sample app 33 | 34 | self.webview = webview; 35 | NSString *resourcesPath = [[NSBundle mainBundle] resourcePath]; 36 | NSString *htmlPath = [resourcesPath stringByAppendingString:@"/cw.html"]; 37 | [self.webview loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]]; 38 | } 39 | ``` 40 | ### OSX 41 | On OSX you can add a WebView to your app in IB. You need to add an outlet reference to this WebView and load cw.html 42 | ```objective-c 43 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 44 | NSString *resourcesPath = [[NSBundle mainBundle] resourcePath]; 45 | NSString *htmlPath = [resourcesPath stringByAppendingString:@"/cw.html"]; 46 | [[self.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]]; 47 | } 48 | ``` 49 | ## Using wrapper classes 50 | The wrapper supports all the chart types provided by Chart.js by separated classes: 51 | - Line : ```CWLineChart/CWLineChartData/CWLineChartOptions/CWPointDataSet``` 52 | - Radar : ```CWRadarChart/CWRadarChartData/CWRadarChartOptions/CWPointDataSet``` 53 | - Bar : ```CWBarChart/CWBarChartData/CWBarChartOptions/CWBarDataSet``` 54 | - Polar Area : ```CWPolarAreaChart/CWSegmentData/CWPolarAreaChartOptions``` 55 | - Pie : ```CWPieChart/CWSegmentData/CWPieChartOptions``` 56 | - Doughnut : ```CWDoughnutChart/CWSegmentData/CWPieChartOptions``` 57 | 58 | All these classes are representations of Chart.js classes (prototypes). The property and method names are the same as in the Chart.js. 59 | 60 | In the chart options there are two differences: 61 | 62 | 1. the colors are represented by NSColor/UIColor instead of CSS color string (```rgba(123,43,56,0.8)```) 63 | 2. in order to create proper JSON from the objects the boolean values are represented by a CWBoolean. You can use cwYES/cwNO. 64 | 65 | ### Examples 66 | Add a LineChart 67 | ```objective-c 68 | - (void)addLine { 69 | NSArray* labels = @[@"A",@"B",@"C",@"D"]; 70 | NSMutableArray* datasets = [NSMutableArray array]; 71 | for(NSInteger i = 1; i < 4; i++) { 72 | CWPointDataSet* ds = [[CWPointDataSet alloc] initWithData:@[@([self random:100]),@([self random:100]),@([self random:100]),@([self random:100])]]; 73 | ds.label = [NSString stringWithFormat:@"Label %ld",i]; 74 | CWColor* c1 = [[CWColors sharedColors] pickColor]; 75 | CWColor* c2 = [c1 colorWithAlphaComponent:0.5f]; 76 | ds.fillColor = c2; 77 | ds.strokeColor = c1; 78 | [datasets addObject:ds]; 79 | } 80 | 81 | CWLineChartData* lcd = [[CWLineChartData alloc] initWithLabels:labels andDataSet:datasets]; 82 | self.lineChart = [[CWLineChart alloc] initWithWebView:self.webview name:@"LineChart1" width:300 height:200 data:lcd options:nil]; 83 | [self.lineChart addChart]; 84 | } 85 | ``` 86 | Delete the first point set from the line chart data, then append a new point set to it. 87 | ```objective-c 88 | - (void)delAddLine { 89 | [self.lineChart removeData]; 90 | [self.lineChart addData:@[@([self random:100]),@([self random:100]),@([self random:100]),@([self random:100])] label:@"W"]; 91 | } 92 | ``` 93 | Change all the points in the line chart. 94 | ```objective-c 95 | - (void)changeLine { 96 | for(NSInteger i = 1; i < 4; i++) { 97 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:0]; 98 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:1]; 99 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:2]; 100 | [self.lineChart setValue:@([self random:100]) inDataset:i-1 at:3]; 101 | } 102 | [self.lineChart update]; 103 | } 104 | ``` 105 | # CWColors library 106 | The project contains a small color library to access [Flat UI Colors](http://flatuicolors.com) 107 | 108 | You can pick random colors by ```[[CWColors sharedColors] pickColor]``` or access colors by name ```[CWColors sharedColors].colors[CWCAsbestos];``` with the following constants: 109 | ```objective-c 110 | extern NSString *const CWCTurquise; 111 | extern NSString *const CWCEmerald; 112 | extern NSString *const CWCPeterRiver; 113 | extern NSString *const CWCAmethyst; 114 | extern NSString *const CWCWetAsphalt; 115 | extern NSString *const CWCGreenSea; 116 | extern NSString *const CWCNephritis; 117 | extern NSString *const CWCBelizeHole; 118 | extern NSString *const CWCWisteria; 119 | extern NSString *const CWCMidnightBlue; 120 | extern NSString *const CWCSunFlower; 121 | extern NSString *const CWCCarrot; 122 | extern NSString *const CWCAlizarin; 123 | extern NSString *const CWCClouds; 124 | extern NSString *const CWCConcrete; 125 | extern NSString *const CWCOrange; 126 | extern NSString *const CWCPumpkin; 127 | extern NSString *const CWCPomegrante; 128 | extern NSString *const CWCSilver; 129 | extern NSString *const CWCAsbestos; 130 | ``` 131 | This small library contains 20 colors only, if you are interested in a more comprehensive color library, which contains more than 1200 colors, you should look at [Rainbow](https://github.com/NorthernRealities/Rainbow) 132 | 133 | # Sample Application 134 | The sample application shows the basic usage of the wrapper. 135 | 136 | # Acknowledgement 137 | 1. The iOS sample application uses [iOSPullDownMenu](https://github.com/BernardGatt/iOSPullDownMenu) 138 | 2. The color library contains color from [Flat UI Colors](http://flatuicolors.com) 139 | 140 | # License 141 | MIT 142 | 143 | -------------------------------------------------------------------------------- /doc/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyetvan-andras/Chart.js-ObjC-Wrapper/3c20bb53dbf0d17d636699d0e4155bd73840600a/doc/sample.png --------------------------------------------------------------------------------