= 0; i--) {
649 | if (this.eventListeners.hasOwnProperty(haltEventListeners[i])) {
650 | delete this.eventListeners[haltEventListeners[i]]
651 | }
652 | }
653 | }
654 | }
655 |
656 | // Bind eventListeners
657 | for (var event in this.eventListeners) {
658 | // Attach event to eventsListenerElement or SVG if not available
659 | (this.options.eventsListenerElement || this.svg)
660 | .addEventListener(event, this.eventListeners[event], false)
661 | }
662 |
663 | // Zoom using mouse wheel
664 | if (this.options.mouseWheelZoomEnabled) {
665 | this.options.mouseWheelZoomEnabled = false // set to false as enable will set it back to true
666 | this.enableMouseWheelZoom()
667 | }
668 | }
669 |
670 | /**
671 | * Enable ability to zoom using mouse wheel
672 | */
673 | SvgPanZoom.prototype.enableMouseWheelZoom = function() {
674 | if (!this.options.mouseWheelZoomEnabled) {
675 | var that = this
676 |
677 | // Mouse wheel listener
678 | this.wheelListener = function(evt) {
679 | return that.handleMouseWheel(evt);
680 | }
681 |
682 | // Bind wheelListener
683 | Wheel.on(this.options.eventsListenerElement || this.svg, this.wheelListener, false)
684 |
685 | this.options.mouseWheelZoomEnabled = true
686 | }
687 | }
688 |
689 | /**
690 | * Disable ability to zoom using mouse wheel
691 | */
692 | SvgPanZoom.prototype.disableMouseWheelZoom = function() {
693 | if (this.options.mouseWheelZoomEnabled) {
694 | Wheel.off(this.options.eventsListenerElement || this.svg, this.wheelListener, false)
695 | this.options.mouseWheelZoomEnabled = false
696 | }
697 | }
698 |
699 | /**
700 | * Handle mouse wheel event
701 | *
702 | * @param {Event} evt
703 | */
704 | SvgPanZoom.prototype.handleMouseWheel = function(evt) {
705 | if (!this.options.zoomEnabled || this.state !== 'none') {
706 | return;
707 | }
708 |
709 | if (this.options.preventMouseEventsDefault){
710 | if (evt.preventDefault) {
711 | evt.preventDefault();
712 | } else {
713 | evt.returnValue = false;
714 | }
715 | }
716 |
717 | // Default delta in case that deltaY is not available
718 | var delta = evt.deltaY || 1
719 | , timeDelta = Date.now() - this.lastMouseWheelEventTime
720 | , divider = 3 + Math.max(0, 30 - timeDelta)
721 |
722 | // Update cache
723 | this.lastMouseWheelEventTime = Date.now()
724 |
725 | // Make empirical adjustments for browsers that give deltaY in pixels (deltaMode=0)
726 | if ('deltaMode' in evt && evt.deltaMode === 0 && evt.wheelDelta) {
727 | delta = evt.deltaY === 0 ? 0 : Math.abs(evt.wheelDelta) / evt.deltaY
728 | }
729 |
730 | delta = -0.3 < delta && delta < 0.3 ? delta : (delta > 0 ? 1 : -1) * Math.log(Math.abs(delta) + 10) / divider
731 |
732 | var inversedScreenCTM = this.svg.getScreenCTM().inverse()
733 | , relativeMousePoint = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(inversedScreenCTM)
734 | , zoom = Math.pow(1 + this.options.zoomScaleSensitivity, (-1) * delta); // multiplying by neg. 1 so as to make zoom in/out behavior match Google maps behavior
735 |
736 | this.zoomAtPoint(zoom, relativeMousePoint)
737 | }
738 |
739 | /**
740 | * Zoom in at a SVG point
741 | *
742 | * @param {SVGPoint} point
743 | * @param {Float} zoomScale Number representing how much to zoom
744 | * @param {Boolean} zoomAbsolute Default false. If true, zoomScale is treated as an absolute value.
745 | * Otherwise, zoomScale is treated as a multiplied (e.g. 1.10 would zoom in 10%)
746 | */
747 | SvgPanZoom.prototype.zoomAtPoint = function(zoomScale, point, zoomAbsolute) {
748 | var originalState = this.viewport.getOriginalState()
749 |
750 | if (!zoomAbsolute) {
751 | // Fit zoomScale in set bounds
752 | if (this.getZoom() * zoomScale < this.options.minZoom * originalState.zoom) {
753 | zoomScale = (this.options.minZoom * originalState.zoom) / this.getZoom()
754 | } else if (this.getZoom() * zoomScale > this.options.maxZoom * originalState.zoom) {
755 | zoomScale = (this.options.maxZoom * originalState.zoom) / this.getZoom()
756 | }
757 | } else {
758 | // Fit zoomScale in set bounds
759 | zoomScale = Math.max(this.options.minZoom * originalState.zoom, Math.min(this.options.maxZoom * originalState.zoom, zoomScale))
760 | // Find relative scale to achieve desired scale
761 | zoomScale = zoomScale/this.getZoom()
762 | }
763 |
764 | var oldCTM = this.viewport.getCTM()
765 | , relativePoint = point.matrixTransform(oldCTM.inverse())
766 | , modifier = this.svg.createSVGMatrix().translate(relativePoint.x, relativePoint.y).scale(zoomScale).translate(-relativePoint.x, -relativePoint.y)
767 | , newCTM = oldCTM.multiply(modifier)
768 |
769 | if (newCTM.a !== oldCTM.a) {
770 | this.viewport.setCTM(newCTM)
771 | }
772 | }
773 |
774 | /**
775 | * Zoom at center point
776 | *
777 | * @param {Float} scale
778 | * @param {Boolean} absolute Marks zoom scale as relative or absolute
779 | */
780 | SvgPanZoom.prototype.zoom = function(scale, absolute) {
781 | this.zoomAtPoint(scale, SvgUtils.getSvgCenterPoint(this.svg, this.width, this.height), absolute)
782 | }
783 |
784 | /**
785 | * Zoom used by public instance
786 | *
787 | * @param {Float} scale
788 | * @param {Boolean} absolute Marks zoom scale as relative or absolute
789 | */
790 | SvgPanZoom.prototype.publicZoom = function(scale, absolute) {
791 | if (absolute) {
792 | scale = this.computeFromRelativeZoom(scale)
793 | }
794 |
795 | this.zoom(scale, absolute)
796 | }
797 |
798 | /**
799 | * Zoom at point used by public instance
800 | *
801 | * @param {Float} scale
802 | * @param {SVGPoint|Object} point An object that has x and y attributes
803 | * @param {Boolean} absolute Marks zoom scale as relative or absolute
804 | */
805 | SvgPanZoom.prototype.publicZoomAtPoint = function(scale, point, absolute) {
806 | if (absolute) {
807 | // Transform zoom into a relative value
808 | scale = this.computeFromRelativeZoom(scale)
809 | }
810 |
811 | // If not a SVGPoint but has x and y then create a SVGPoint
812 | if (Utils.getType(point) !== 'SVGPoint') {
813 | if('x' in point && 'y' in point) {
814 | point = SvgUtils.createSVGPoint(this.svg, point.x, point.y)
815 | } else {
816 | throw new Error('Given point is invalid')
817 | }
818 | }
819 |
820 | this.zoomAtPoint(scale, point, absolute)
821 | }
822 |
823 | /**
824 | * Get zoom scale
825 | *
826 | * @return {Float} zoom scale
827 | */
828 | SvgPanZoom.prototype.getZoom = function() {
829 | return this.viewport.getZoom()
830 | }
831 |
832 | /**
833 | * Get zoom scale for public usage
834 | *
835 | * @return {Float} zoom scale
836 | */
837 | SvgPanZoom.prototype.getRelativeZoom = function() {
838 | return this.viewport.getRelativeZoom()
839 | }
840 |
841 | /**
842 | * Compute actual zoom from public zoom
843 | *
844 | * @param {Float} zoom
845 | * @return {Float} zoom scale
846 | */
847 | SvgPanZoom.prototype.computeFromRelativeZoom = function(zoom) {
848 | return zoom * this.viewport.getOriginalState().zoom
849 | }
850 |
851 | /**
852 | * Set zoom to initial state
853 | */
854 | SvgPanZoom.prototype.resetZoom = function() {
855 | var originalState = this.viewport.getOriginalState()
856 |
857 | this.zoom(originalState.zoom, true);
858 | }
859 |
860 | /**
861 | * Set pan to initial state
862 | */
863 | SvgPanZoom.prototype.resetPan = function() {
864 | this.pan(this.viewport.getOriginalState());
865 | }
866 |
867 | /**
868 | * Set pan and zoom to initial state
869 | */
870 | SvgPanZoom.prototype.reset = function() {
871 | this.resetZoom()
872 | this.resetPan()
873 | }
874 |
875 | /**
876 | * Handle double click event
877 | * See handleMouseDown() for alternate detection method
878 | *
879 | * @param {Event} evt
880 | */
881 | SvgPanZoom.prototype.handleDblClick = function(evt) {
882 | if (this.options.preventMouseEventsDefault) {
883 | if (evt.preventDefault) {
884 | evt.preventDefault()
885 | } else {
886 | evt.returnValue = false
887 | }
888 | }
889 |
890 | // Check if target was a control button
891 | if (this.options.controlIconsEnabled) {
892 | var targetClass = evt.target.getAttribute('class') || ''
893 | if (targetClass.indexOf('svg-pan-zoom-control') > -1) {
894 | return false
895 | }
896 | }
897 |
898 | var zoomFactor
899 |
900 | if (evt.shiftKey) {
901 | zoomFactor = 1/((1 + this.options.zoomScaleSensitivity) * 2) // zoom out when shift key pressed
902 | } else {
903 | zoomFactor = (1 + this.options.zoomScaleSensitivity) * 2
904 | }
905 |
906 | var point = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(this.svg.getScreenCTM().inverse())
907 | this.zoomAtPoint(zoomFactor, point)
908 | }
909 |
910 | /**
911 | * Handle click event
912 | *
913 | * @param {Event} evt
914 | */
915 | SvgPanZoom.prototype.handleMouseDown = function(evt, prevEvt) {
916 | if (this.options.preventMouseEventsDefault) {
917 | if (evt.preventDefault) {
918 | evt.preventDefault()
919 | } else {
920 | evt.returnValue = false
921 | }
922 | }
923 |
924 | Utils.mouseAndTouchNormalize(evt, this.svg)
925 |
926 | // Double click detection; more consistent than ondblclick
927 | if (this.options.dblClickZoomEnabled && Utils.isDblClick(evt, prevEvt)){
928 | this.handleDblClick(evt)
929 | } else {
930 | // Pan mode
931 | this.state = 'pan'
932 | this.firstEventCTM = this.viewport.getCTM()
933 | this.stateOrigin = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(this.firstEventCTM.inverse())
934 | }
935 | }
936 |
937 | /**
938 | * Handle mouse move event
939 | *
940 | * @param {Event} evt
941 | */
942 | SvgPanZoom.prototype.handleMouseMove = function(evt) {
943 | if (this.options.preventMouseEventsDefault) {
944 | if (evt.preventDefault) {
945 | evt.preventDefault()
946 | } else {
947 | evt.returnValue = false
948 | }
949 | }
950 |
951 | if (this.state === 'pan' && this.options.panEnabled) {
952 | // Pan mode
953 | var point = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(this.firstEventCTM.inverse())
954 | , viewportCTM = this.firstEventCTM.translate(point.x - this.stateOrigin.x, point.y - this.stateOrigin.y)
955 |
956 | this.viewport.setCTM(viewportCTM)
957 | }
958 | }
959 |
960 | /**
961 | * Handle mouse button release event
962 | *
963 | * @param {Event} evt
964 | */
965 | SvgPanZoom.prototype.handleMouseUp = function(evt) {
966 | if (this.options.preventMouseEventsDefault) {
967 | if (evt.preventDefault) {
968 | evt.preventDefault()
969 | } else {
970 | evt.returnValue = false
971 | }
972 | }
973 |
974 | if (this.state === 'pan') {
975 | // Quit pan mode
976 | this.state = 'none'
977 | }
978 | }
979 |
980 | /**
981 | * Adjust viewport size (only) so it will fit in SVG
982 | * Does not center image
983 | */
984 | SvgPanZoom.prototype.fit = function() {
985 | var viewBox = this.viewport.getViewBox()
986 | , newScale = Math.min(this.width/viewBox.width, this.height/viewBox.height)
987 |
988 | this.zoom(newScale, true)
989 | }
990 |
991 | /**
992 | * Adjust viewport size (only) so it will contain the SVG
993 | * Does not center image
994 | */
995 | SvgPanZoom.prototype.contain = function() {
996 | var viewBox = this.viewport.getViewBox()
997 | , newScale = Math.max(this.width/viewBox.width, this.height/viewBox.height)
998 |
999 | this.zoom(newScale, true)
1000 | }
1001 |
1002 | /**
1003 | * Adjust viewport pan (only) so it will be centered in SVG
1004 | * Does not zoom/fit/contain image
1005 | */
1006 | SvgPanZoom.prototype.center = function() {
1007 | var viewBox = this.viewport.getViewBox()
1008 | , offsetX = (this.width - (viewBox.width + viewBox.x * 2) * this.getZoom()) * 0.5
1009 | , offsetY = (this.height - (viewBox.height + viewBox.y * 2) * this.getZoom()) * 0.5
1010 |
1011 | this.getPublicInstance().pan({x: offsetX, y: offsetY})
1012 | }
1013 |
1014 | /**
1015 | * Update content cached BorderBox
1016 | * Use when viewport contents change
1017 | */
1018 | SvgPanZoom.prototype.updateBBox = function() {
1019 | this.viewport.simpleViewBoxCache()
1020 | }
1021 |
1022 | /**
1023 | * Pan to a rendered position
1024 | *
1025 | * @param {Object} point {x: 0, y: 0}
1026 | */
1027 | SvgPanZoom.prototype.pan = function(point) {
1028 | var viewportCTM = this.viewport.getCTM()
1029 | viewportCTM.e = point.x
1030 | viewportCTM.f = point.y
1031 | this.viewport.setCTM(viewportCTM)
1032 | }
1033 |
1034 | /**
1035 | * Relatively pan the graph by a specified rendered position vector
1036 | *
1037 | * @param {Object} point {x: 0, y: 0}
1038 | */
1039 | SvgPanZoom.prototype.panBy = function(point) {
1040 | var viewportCTM = this.viewport.getCTM()
1041 | viewportCTM.e += point.x
1042 | viewportCTM.f += point.y
1043 | this.viewport.setCTM(viewportCTM)
1044 | }
1045 |
1046 | /**
1047 | * Get pan vector
1048 | *
1049 | * @return {Object} {x: 0, y: 0}
1050 | */
1051 | SvgPanZoom.prototype.getPan = function() {
1052 | var state = this.viewport.getState()
1053 |
1054 | return {x: state.x, y: state.y}
1055 | }
1056 |
1057 | /**
1058 | * Recalculates cached svg dimensions and controls position
1059 | */
1060 | SvgPanZoom.prototype.resize = function() {
1061 | // Get dimensions
1062 | var boundingClientRectNormalized = SvgUtils.getBoundingClientRectNormalized(this.svg)
1063 | this.width = boundingClientRectNormalized.width
1064 | this.height = boundingClientRectNormalized.height
1065 |
1066 | // Recalculate original state
1067 | var viewport = this.viewport
1068 | viewport.options.width = this.width
1069 | viewport.options.height = this.height
1070 | viewport.processCTM()
1071 |
1072 | // Reposition control icons by re-enabling them
1073 | if (this.options.controlIconsEnabled) {
1074 | this.getPublicInstance().disableControlIcons()
1075 | this.getPublicInstance().enableControlIcons()
1076 | }
1077 | }
1078 |
1079 | /**
1080 | * Unbind mouse events, free callbacks and destroy public instance
1081 | */
1082 | SvgPanZoom.prototype.destroy = function() {
1083 | var that = this
1084 |
1085 | // Free callbacks
1086 | this.beforeZoom = null
1087 | this.onZoom = null
1088 | this.beforePan = null
1089 | this.onPan = null
1090 | this.onUpdatedCTM = null
1091 |
1092 | // Destroy custom event handlers
1093 | if (this.options.customEventsHandler != null) { // jshint ignore:line
1094 | this.options.customEventsHandler.destroy({
1095 | svgElement: this.svg
1096 | , eventsListenerElement: this.options.eventsListenerElement
1097 | , instance: this.getPublicInstance()
1098 | })
1099 | }
1100 |
1101 | // Unbind eventListeners
1102 | for (var event in this.eventListeners) {
1103 | (this.options.eventsListenerElement || this.svg)
1104 | .removeEventListener(event, this.eventListeners[event], false)
1105 | }
1106 |
1107 | // Unbind wheelListener
1108 | this.disableMouseWheelZoom()
1109 |
1110 | // Remove control icons
1111 | this.getPublicInstance().disableControlIcons()
1112 |
1113 | // Reset zoom and pan
1114 | this.reset()
1115 |
1116 | // Remove instance from instancesStore
1117 | instancesStore = instancesStore.filter(function(instance){
1118 | return instance.svg !== that.svg
1119 | })
1120 |
1121 | // Delete options and its contents
1122 | delete this.options
1123 |
1124 | // Delete viewport to make public shadow viewport functions uncallable
1125 | delete this.viewport
1126 |
1127 | // Destroy public instance and rewrite getPublicInstance
1128 | delete this.publicInstance
1129 | delete this.pi
1130 | this.getPublicInstance = function(){
1131 | return null
1132 | }
1133 | }
1134 |
1135 | /**
1136 | * Returns a public instance object
1137 | *
1138 | * @return {Object} Public instance object
1139 | */
1140 | SvgPanZoom.prototype.getPublicInstance = function() {
1141 | var that = this
1142 |
1143 | // Create cache
1144 | if (!this.publicInstance) {
1145 | this.publicInstance = this.pi = {
1146 | // Pan
1147 | enablePan: function() {that.options.panEnabled = true; return that.pi}
1148 | , disablePan: function() {that.options.panEnabled = false; return that.pi}
1149 | , isPanEnabled: function() {return !!that.options.panEnabled}
1150 | , pan: function(point) {that.pan(point); return that.pi}
1151 | , panBy: function(point) {that.panBy(point); return that.pi}
1152 | , getPan: function() {return that.getPan()}
1153 | // Pan event
1154 | , setBeforePan: function(fn) {that.options.beforePan = fn === null ? null : Utils.proxy(fn, that.publicInstance); return that.pi}
1155 | , setOnPan: function(fn) {that.options.onPan = fn === null ? null : Utils.proxy(fn, that.publicInstance); return that.pi}
1156 | // Zoom and Control Icons
1157 | , enableZoom: function() {that.options.zoomEnabled = true; return that.pi}
1158 | , disableZoom: function() {that.options.zoomEnabled = false; return that.pi}
1159 | , isZoomEnabled: function() {return !!that.options.zoomEnabled}
1160 | , enableControlIcons: function() {
1161 | if (!that.options.controlIconsEnabled) {
1162 | that.options.controlIconsEnabled = true
1163 | ControlIcons.enable(that)
1164 | }
1165 | return that.pi
1166 | }
1167 | , disableControlIcons: function() {
1168 | if (that.options.controlIconsEnabled) {
1169 | that.options.controlIconsEnabled = false;
1170 | ControlIcons.disable(that)
1171 | }
1172 | return that.pi
1173 | }
1174 | , isControlIconsEnabled: function() {return !!that.options.controlIconsEnabled}
1175 | // Double click zoom
1176 | , enableDblClickZoom: function() {that.options.dblClickZoomEnabled = true; return that.pi}
1177 | , disableDblClickZoom: function() {that.options.dblClickZoomEnabled = false; return that.pi}
1178 | , isDblClickZoomEnabled: function() {return !!that.options.dblClickZoomEnabled}
1179 | // Mouse wheel zoom
1180 | , enableMouseWheelZoom: function() {that.enableMouseWheelZoom(); return that.pi}
1181 | , disableMouseWheelZoom: function() {that.disableMouseWheelZoom(); return that.pi}
1182 | , isMouseWheelZoomEnabled: function() {return !!that.options.mouseWheelZoomEnabled}
1183 | // Zoom scale and bounds
1184 | , setZoomScaleSensitivity: function(scale) {that.options.zoomScaleSensitivity = scale; return that.pi}
1185 | , setMinZoom: function(zoom) {that.options.minZoom = zoom; return that.pi}
1186 | , setMaxZoom: function(zoom) {that.options.maxZoom = zoom; return that.pi}
1187 | // Zoom event
1188 | , setBeforeZoom: function(fn) {that.options.beforeZoom = fn === null ? null : Utils.proxy(fn, that.publicInstance); return that.pi}
1189 | , setOnZoom: function(fn) {that.options.onZoom = fn === null ? null : Utils.proxy(fn, that.publicInstance); return that.pi}
1190 | // Zooming
1191 | , zoom: function(scale) {that.publicZoom(scale, true); return that.pi}
1192 | , zoomBy: function(scale) {that.publicZoom(scale, false); return that.pi}
1193 | , zoomAtPoint: function(scale, point) {that.publicZoomAtPoint(scale, point, true); return that.pi}
1194 | , zoomAtPointBy: function(scale, point) {that.publicZoomAtPoint(scale, point, false); return that.pi}
1195 | , zoomIn: function() {this.zoomBy(1 + that.options.zoomScaleSensitivity); return that.pi}
1196 | , zoomOut: function() {this.zoomBy(1 / (1 + that.options.zoomScaleSensitivity)); return that.pi}
1197 | , getZoom: function() {return that.getRelativeZoom()}
1198 | // CTM update
1199 | , setOnUpdatedCTM: function(fn) {that.options.onUpdatedCTM = fn === null ? null : Utils.proxy(fn, that.publicInstance); return that.pi}
1200 | // Reset
1201 | , resetZoom: function() {that.resetZoom(); return that.pi}
1202 | , resetPan: function() {that.resetPan(); return that.pi}
1203 | , reset: function() {that.reset(); return that.pi}
1204 | // Fit, Contain and Center
1205 | , fit: function() {that.fit(); return that.pi}
1206 | , contain: function() {that.contain(); return that.pi}
1207 | , center: function() {that.center(); return that.pi}
1208 | // Size and Resize
1209 | , updateBBox: function() {that.updateBBox(); return that.pi}
1210 | , resize: function() {that.resize(); return that.pi}
1211 | , getSizes: function() {
1212 | return {
1213 | width: that.width
1214 | , height: that.height
1215 | , realZoom: that.getZoom()
1216 | , viewBox: that.viewport.getViewBox()
1217 | }
1218 | }
1219 | // Destroy
1220 | , destroy: function() {that.destroy(); return that.pi}
1221 | }
1222 | }
1223 |
1224 | return this.publicInstance
1225 | }
1226 |
1227 | /**
1228 | * Stores pairs of instances of SvgPanZoom and SVG
1229 | * Each pair is represented by an object {svg: SVGSVGElement, instance: SvgPanZoom}
1230 | *
1231 | * @type {Array}
1232 | */
1233 | var instancesStore = []
1234 |
1235 | var svgPanZoom = function(elementOrSelector, options){
1236 | var svg = Utils.getSvg(elementOrSelector)
1237 |
1238 | if (svg === null) {
1239 | return null
1240 | } else {
1241 | // Look for existent instance
1242 | for(var i = instancesStore.length - 1; i >= 0; i--) {
1243 | if (instancesStore[i].svg === svg) {
1244 | return instancesStore[i].instance.getPublicInstance()
1245 | }
1246 | }
1247 |
1248 | // If instance not found - create one
1249 | instancesStore.push({
1250 | svg: svg
1251 | , instance: new SvgPanZoom(svg, options)
1252 | })
1253 |
1254 | // Return just pushed instance
1255 | return instancesStore[instancesStore.length - 1].instance.getPublicInstance()
1256 | }
1257 | }
1258 |
1259 | module.exports = svgPanZoom;
1260 |
1261 | },{"./control-icons":2,"./shadow-viewport":3,"./svg-utilities":5,"./uniwheel":6,"./utilities":7}],5:[function(require,module,exports){
1262 | var Utils = require('./utilities')
1263 | , _browser = 'unknown'
1264 | ;
1265 |
1266 | // http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
1267 | if (/*@cc_on!@*/false || !!document.documentMode) { // internet explorer
1268 | _browser = 'ie';
1269 | }
1270 |
1271 | module.exports = {
1272 | svgNS: 'http://www.w3.org/2000/svg'
1273 | , xmlNS: 'http://www.w3.org/XML/1998/namespace'
1274 | , xmlnsNS: 'http://www.w3.org/2000/xmlns/'
1275 | , xlinkNS: 'http://www.w3.org/1999/xlink'
1276 | , evNS: 'http://www.w3.org/2001/xml-events'
1277 |
1278 | /**
1279 | * Get svg dimensions: width and height
1280 | *
1281 | * @param {SVGSVGElement} svg
1282 | * @return {Object} {width: 0, height: 0}
1283 | */
1284 | , getBoundingClientRectNormalized: function(svg) {
1285 | if (svg.clientWidth && svg.clientHeight) {
1286 | return {width: svg.clientWidth, height: svg.clientHeight}
1287 | } else if (!!svg.getBoundingClientRect()) {
1288 | return svg.getBoundingClientRect();
1289 | } else {
1290 | throw new Error('Cannot get BoundingClientRect for SVG.');
1291 | }
1292 | }
1293 |
1294 | /**
1295 | * Gets g element with class of "viewport" or creates it if it doesn't exist
1296 | *
1297 | * @param {SVGSVGElement} svg
1298 | * @return {SVGElement} g (group) element
1299 | */
1300 | , getOrCreateViewport: function(svg, selector) {
1301 | var viewport = null
1302 |
1303 | if (Utils.isElement(selector)) {
1304 | viewport = selector
1305 | } else {
1306 | viewport = svg.querySelector(selector)
1307 | }
1308 |
1309 | // Check if there is just one main group in SVG
1310 | if (!viewport) {
1311 | var childNodes = Array.prototype.slice.call(svg.childNodes || svg.children).filter(function(el){
1312 | return el.nodeName !== 'defs' && el.nodeName !== '#text'
1313 | })
1314 |
1315 | // Node name should be SVGGElement and should have no transform attribute
1316 | // Groups with transform are not used as viewport because it involves parsing of all transform possibilities
1317 | if (childNodes.length === 1 && childNodes[0].nodeName === 'g' && childNodes[0].getAttribute('transform') === null) {
1318 | viewport = childNodes[0]
1319 | }
1320 | }
1321 |
1322 | // If no favorable group element exists then create one
1323 | if (!viewport) {
1324 | var viewportId = 'viewport-' + new Date().toISOString().replace(/\D/g, '');
1325 | viewport = document.createElementNS(this.svgNS, 'g');
1326 | viewport.setAttribute('id', viewportId);
1327 |
1328 | // Internet Explorer (all versions?) can't use childNodes, but other browsers prefer (require?) using childNodes
1329 | var svgChildren = svg.childNodes || svg.children;
1330 | if (!!svgChildren && svgChildren.length > 0) {
1331 | for (var i = svgChildren.length; i > 0; i--) {
1332 | // Move everything into viewport except defs
1333 | if (svgChildren[svgChildren.length - i].nodeName !== 'defs') {
1334 | viewport.appendChild(svgChildren[svgChildren.length - i]);
1335 | }
1336 | }
1337 | }
1338 | svg.appendChild(viewport);
1339 | }
1340 |
1341 | // Parse class names
1342 | var classNames = [];
1343 | if (viewport.getAttribute('class')) {
1344 | classNames = viewport.getAttribute('class').split(' ')
1345 | }
1346 |
1347 | // Set class (if not set already)
1348 | if (!~classNames.indexOf('svg-pan-zoom_viewport')) {
1349 | classNames.push('svg-pan-zoom_viewport')
1350 | viewport.setAttribute('class', classNames.join(' '))
1351 | }
1352 |
1353 | return viewport
1354 | }
1355 |
1356 | /**
1357 | * Set SVG attributes
1358 | *
1359 | * @param {SVGSVGElement} svg
1360 | */
1361 | , setupSvgAttributes: function(svg) {
1362 | // Setting default attributes
1363 | svg.setAttribute('xmlns', this.svgNS);
1364 | svg.setAttributeNS(this.xmlnsNS, 'xmlns:xlink', this.xlinkNS);
1365 | svg.setAttributeNS(this.xmlnsNS, 'xmlns:ev', this.evNS);
1366 |
1367 | // Needed for Internet Explorer, otherwise the viewport overflows
1368 | if (svg.parentNode !== null) {
1369 | var style = svg.getAttribute('style') || '';
1370 | if (style.toLowerCase().indexOf('overflow') === -1) {
1371 | svg.setAttribute('style', 'overflow: hidden; ' + style);
1372 | }
1373 | }
1374 | }
1375 |
1376 | /**
1377 | * How long Internet Explorer takes to finish updating its display (ms).
1378 | */
1379 | , internetExplorerRedisplayInterval: 300
1380 |
1381 | /**
1382 | * Forces the browser to redisplay all SVG elements that rely on an
1383 | * element defined in a 'defs' section. It works globally, for every
1384 | * available defs element on the page.
1385 | * The throttling is intentionally global.
1386 | *
1387 | * This is only needed for IE. It is as a hack to make markers (and 'use' elements?)
1388 | * visible after pan/zoom when there are multiple SVGs on the page.
1389 | * See bug report: https://connect.microsoft.com/IE/feedback/details/781964/
1390 | * also see svg-pan-zoom issue: https://github.com/ariutta/svg-pan-zoom/issues/62
1391 | */
1392 | , refreshDefsGlobal: Utils.throttle(function() {
1393 | var allDefs = document.querySelectorAll('defs');
1394 | var allDefsCount = allDefs.length;
1395 | for (var i = 0; i < allDefsCount; i++) {
1396 | var thisDefs = allDefs[i];
1397 | thisDefs.parentNode.insertBefore(thisDefs, thisDefs);
1398 | }
1399 | }, this.internetExplorerRedisplayInterval)
1400 |
1401 | /**
1402 | * Sets the current transform matrix of an element
1403 | *
1404 | * @param {SVGElement} element
1405 | * @param {SVGMatrix} matrix CTM
1406 | * @param {SVGElement} defs
1407 | */
1408 | , setCTM: function(element, matrix, defs) {
1409 | var that = this
1410 | , s = 'matrix(' + matrix.a + ',' + matrix.b + ',' + matrix.c + ',' + matrix.d + ',' + matrix.e + ',' + matrix.f + ')';
1411 |
1412 | element.setAttributeNS(null, 'transform', s);
1413 | if ('transform' in element.style) {
1414 | element.style.transform = s;
1415 | } else if ('-ms-transform' in element.style) {
1416 | element.style['-ms-transform'] = s;
1417 | } else if ('-webkit-transform' in element.style) {
1418 | element.style['-webkit-transform'] = s;
1419 | }
1420 |
1421 | // IE has a bug that makes markers disappear on zoom (when the matrix "a" and/or "d" elements change)
1422 | // see http://stackoverflow.com/questions/17654578/svg-marker-does-not-work-in-ie9-10
1423 | // and http://srndolha.wordpress.com/2013/11/25/svg-line-markers-may-disappear-in-internet-explorer-11/
1424 | if (_browser === 'ie' && !!defs) {
1425 | // this refresh is intended for redisplaying the SVG during zooming
1426 | defs.parentNode.insertBefore(defs, defs);
1427 | // this refresh is intended for redisplaying the other SVGs on a page when panning a given SVG
1428 | // it is also needed for the given SVG itself, on zoomEnd, if the SVG contains any markers that
1429 | // are located under any other element(s).
1430 | window.setTimeout(function() {
1431 | that.refreshDefsGlobal();
1432 | }, that.internetExplorerRedisplayInterval);
1433 | }
1434 | }
1435 |
1436 | /**
1437 | * Instantiate an SVGPoint object with given event coordinates
1438 | *
1439 | * @param {Event} evt
1440 | * @param {SVGSVGElement} svg
1441 | * @return {SVGPoint} point
1442 | */
1443 | , getEventPoint: function(evt, svg) {
1444 | var point = svg.createSVGPoint()
1445 |
1446 | Utils.mouseAndTouchNormalize(evt, svg)
1447 |
1448 | point.x = evt.clientX
1449 | point.y = evt.clientY
1450 |
1451 | return point
1452 | }
1453 |
1454 | /**
1455 | * Get SVG center point
1456 | *
1457 | * @param {SVGSVGElement} svg
1458 | * @return {SVGPoint}
1459 | */
1460 | , getSvgCenterPoint: function(svg, width, height) {
1461 | return this.createSVGPoint(svg, width / 2, height / 2)
1462 | }
1463 |
1464 | /**
1465 | * Create a SVGPoint with given x and y
1466 | *
1467 | * @param {SVGSVGElement} svg
1468 | * @param {Number} x
1469 | * @param {Number} y
1470 | * @return {SVGPoint}
1471 | */
1472 | , createSVGPoint: function(svg, x, y) {
1473 | var point = svg.createSVGPoint()
1474 | point.x = x
1475 | point.y = y
1476 |
1477 | return point
1478 | }
1479 | }
1480 |
1481 | },{"./utilities":7}],6:[function(require,module,exports){
1482 | // uniwheel 0.1.2 (customized)
1483 | // A unified cross browser mouse wheel event handler
1484 | // https://github.com/teemualap/uniwheel
1485 |
1486 | module.exports = (function(){
1487 |
1488 | //Full details: https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel
1489 |
1490 | var prefix = "", _addEventListener, _removeEventListener, onwheel, support, fns = [];
1491 |
1492 | // detect event model
1493 | if ( window.addEventListener ) {
1494 | _addEventListener = "addEventListener";
1495 | _removeEventListener = "removeEventListener";
1496 | } else {
1497 | _addEventListener = "attachEvent";
1498 | _removeEventListener = "detachEvent";
1499 | prefix = "on";
1500 | }
1501 |
1502 | // detect available wheel event
1503 | support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
1504 | document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
1505 | "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
1506 |
1507 |
1508 | function createCallback(element,callback,capture) {
1509 |
1510 | var fn = function(originalEvent) {
1511 |
1512 | !originalEvent && ( originalEvent = window.event );
1513 |
1514 | // create a normalized event object
1515 | var event = {
1516 | // keep a ref to the original event object
1517 | originalEvent: originalEvent,
1518 | target: originalEvent.target || originalEvent.srcElement,
1519 | type: "wheel",
1520 | deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
1521 | deltaX: 0,
1522 | delatZ: 0,
1523 | preventDefault: function() {
1524 | originalEvent.preventDefault ?
1525 | originalEvent.preventDefault() :
1526 | originalEvent.returnValue = false;
1527 | }
1528 | };
1529 |
1530 | // calculate deltaY (and deltaX) according to the event
1531 | if ( support == "mousewheel" ) {
1532 | event.deltaY = - 1/40 * originalEvent.wheelDelta;
1533 | // Webkit also support wheelDeltaX
1534 | originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
1535 | } else {
1536 | event.deltaY = originalEvent.detail;
1537 | }
1538 |
1539 | // it's time to fire the callback
1540 | return callback( event );
1541 |
1542 | };
1543 |
1544 | fns.push({
1545 | element: element,
1546 | fn: fn,
1547 | capture: capture
1548 | });
1549 |
1550 | return fn;
1551 | }
1552 |
1553 | function getCallback(element,capture) {
1554 | for (var i = 0; i < fns.length; i++) {
1555 | if (fns[i].element === element && fns[i].capture === capture) {
1556 | return fns[i].fn;
1557 | }
1558 | }
1559 | return function(){};
1560 | }
1561 |
1562 | function removeCallback(element,capture) {
1563 | for (var i = 0; i < fns.length; i++) {
1564 | if (fns[i].element === element && fns[i].capture === capture) {
1565 | return fns.splice(i,1);
1566 | }
1567 | }
1568 | }
1569 |
1570 | function _addWheelListener( elem, eventName, callback, useCapture ) {
1571 |
1572 | var cb;
1573 |
1574 | if (support === "wheel") {
1575 | cb = callback;
1576 | } else {
1577 | cb = createCallback(elem,callback,useCapture);
1578 | }
1579 |
1580 | //elem[ _addEventListener ]( prefix + eventName, cb, useCapture || false );
1581 | elem[ _addEventListener ]( prefix + eventName, cb, useCapture || { capture: false, passive: false } );
1582 | }
1583 |
1584 | function _removeWheelListener( elem, eventName, callback, useCapture ) {
1585 |
1586 | if (support === "wheel") {
1587 | cb = callback;
1588 | } else {
1589 | cb = getCallback(elem,useCapture);
1590 | }
1591 |
1592 | //elem[ _removeEventListener ]( prefix + eventName, cb, useCapture || false );
1593 | elem[ _removeEventListener ]( prefix + eventName, cb, useCapture || { capture: false, passive: false } );
1594 | removeCallback(elem,useCapture);
1595 |
1596 | }
1597 |
1598 | function addWheelListener( elem, callback, useCapture ) {
1599 | _addWheelListener( elem, support, callback, useCapture );
1600 |
1601 | // handle MozMousePixelScroll in older Firefox
1602 | if( support == "DOMMouseScroll" ) {
1603 | _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture);
1604 | }
1605 | }
1606 |
1607 | function removeWheelListener(elem,callback,useCapture){
1608 | _removeWheelListener(elem,support,callback,useCapture);
1609 |
1610 | // handle MozMousePixelScroll in older Firefox
1611 | if( support == "DOMMouseScroll" ) {
1612 | _removeWheelListener(elem, "MozMousePixelScroll", callback, useCapture);
1613 | }
1614 | }
1615 |
1616 | return {
1617 | on: addWheelListener,
1618 | off: removeWheelListener
1619 | };
1620 |
1621 | })();
1622 |
1623 | },{}],7:[function(require,module,exports){
1624 | module.exports = {
1625 | /**
1626 | * Extends an object
1627 | *
1628 | * @param {Object} target object to extend
1629 | * @param {Object} source object to take properties from
1630 | * @return {Object} extended object
1631 | */
1632 | extend: function(target, source) {
1633 | target = target || {};
1634 | for (var prop in source) {
1635 | // Go recursively
1636 | if (this.isObject(source[prop])) {
1637 | target[prop] = this.extend(target[prop], source[prop])
1638 | } else {
1639 | target[prop] = source[prop]
1640 | }
1641 | }
1642 | return target;
1643 | }
1644 |
1645 | /**
1646 | * Checks if an object is a DOM element
1647 | *
1648 | * @param {Object} o HTML element or String
1649 | * @return {Boolean} returns true if object is a DOM element
1650 | */
1651 | , isElement: function(o){
1652 | return (
1653 | o instanceof HTMLElement || o instanceof SVGElement || o instanceof SVGSVGElement || //DOM2
1654 | (o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string')
1655 | );
1656 | }
1657 |
1658 | /**
1659 | * Checks if an object is an Object
1660 | *
1661 | * @param {Object} o Object
1662 | * @return {Boolean} returns true if object is an Object
1663 | */
1664 | , isObject: function(o){
1665 | return Object.prototype.toString.call(o) === '[object Object]';
1666 | }
1667 |
1668 | /**
1669 | * Checks if variable is Number
1670 | *
1671 | * @param {Integer|Float} n
1672 | * @return {Boolean} returns true if variable is Number
1673 | */
1674 | , isNumber: function(n) {
1675 | return !isNaN(parseFloat(n)) && isFinite(n);
1676 | }
1677 |
1678 | /**
1679 | * Search for an SVG element
1680 | *
1681 | * @param {Object|String} elementOrSelector DOM Element or selector String
1682 | * @return {Object|Null} SVG or null
1683 | */
1684 | , getSvg: function(elementOrSelector) {
1685 | var element
1686 | , svg;
1687 |
1688 | if (!this.isElement(elementOrSelector)) {
1689 | // If selector provided
1690 | if (typeof elementOrSelector === 'string' || elementOrSelector instanceof String) {
1691 | // Try to find the element
1692 | element = document.querySelector(elementOrSelector)
1693 |
1694 | if (!element) {
1695 | throw new Error('Provided selector did not find any elements. Selector: ' + elementOrSelector)
1696 | return null
1697 | }
1698 | } else {
1699 | throw new Error('Provided selector is not an HTML object nor String')
1700 | return null
1701 | }
1702 | } else {
1703 | element = elementOrSelector
1704 | }
1705 |
1706 | if (element.tagName.toLowerCase() === 'svg') {
1707 | svg = element;
1708 | } else {
1709 | if (element.tagName.toLowerCase() === 'object') {
1710 | svg = element.contentDocument.documentElement;
1711 | } else {
1712 | if (element.tagName.toLowerCase() === 'embed') {
1713 | svg = element.getSVGDocument().documentElement;
1714 | } else {
1715 | if (element.tagName.toLowerCase() === 'img') {
1716 | throw new Error('Cannot script an SVG in an "img" element. Please use an "object" element or an in-line SVG.');
1717 | } else {
1718 | throw new Error('Cannot get SVG.');
1719 | }
1720 | return null
1721 | }
1722 | }
1723 | }
1724 |
1725 | return svg
1726 | }
1727 |
1728 | /**
1729 | * Attach a given context to a function
1730 | * @param {Function} fn Function
1731 | * @param {Object} context Context
1732 | * @return {Function} Function with certain context
1733 | */
1734 | , proxy: function(fn, context) {
1735 | return function() {
1736 | return fn.apply(context, arguments)
1737 | }
1738 | }
1739 |
1740 | /**
1741 | * Returns object type
1742 | * Uses toString that returns [object SVGPoint]
1743 | * And than parses object type from string
1744 | *
1745 | * @param {Object} o Any object
1746 | * @return {String} Object type
1747 | */
1748 | , getType: function(o) {
1749 | return Object.prototype.toString.apply(o).replace(/^\[object\s/, '').replace(/\]$/, '')
1750 | }
1751 |
1752 | /**
1753 | * If it is a touch event than add clientX and clientY to event object
1754 | *
1755 | * @param {Event} evt
1756 | * @param {SVGSVGElement} svg
1757 | */
1758 | , mouseAndTouchNormalize: function(evt, svg) {
1759 | // If no cilentX and but touch objects are available
1760 | if (evt.clientX === void 0 || evt.clientX === null) {
1761 | // Fallback
1762 | evt.clientX = 0
1763 | evt.clientY = 0
1764 |
1765 | // If it is a touch event
1766 | if (evt.changedTouches !== void 0 && evt.changedTouches.length) {
1767 | // If touch event has changedTouches
1768 | if (evt.changedTouches[0].clientX !== void 0) {
1769 | evt.clientX = evt.changedTouches[0].clientX
1770 | evt.clientY = evt.changedTouches[0].clientY
1771 | }
1772 | // If changedTouches has pageX attribute
1773 | else if (evt.changedTouches[0].pageX !== void 0) {
1774 | var rect = svg.getBoundingClientRect();
1775 |
1776 | evt.clientX = evt.changedTouches[0].pageX - rect.left
1777 | evt.clientY = evt.changedTouches[0].pageY - rect.top
1778 | }
1779 | // If it is a custom event
1780 | } else if (evt.originalEvent !== void 0) {
1781 | if (evt.originalEvent.clientX !== void 0) {
1782 | evt.clientX = evt.originalEvent.clientX
1783 | evt.clientY = evt.originalEvent.clientY
1784 | }
1785 | }
1786 | }
1787 | }
1788 |
1789 | /**
1790 | * Check if an event is a double click/tap
1791 | * TODO: For touch gestures use a library (hammer.js) that takes in account other events
1792 | * (touchmove and touchend). It should take in account tap duration and traveled distance
1793 | *
1794 | * @param {Event} evt
1795 | * @param {Event} prevEvt Previous Event
1796 | * @return {Boolean}
1797 | */
1798 | , isDblClick: function(evt, prevEvt) {
1799 | // Double click detected by browser
1800 | if (evt.detail === 2) {
1801 | return true;
1802 | }
1803 | // Try to compare events
1804 | else if (prevEvt !== void 0 && prevEvt !== null) {
1805 | var timeStampDiff = evt.timeStamp - prevEvt.timeStamp // should be lower than 250 ms
1806 | , touchesDistance = Math.sqrt(Math.pow(evt.clientX - prevEvt.clientX, 2) + Math.pow(evt.clientY - prevEvt.clientY, 2))
1807 |
1808 | return timeStampDiff < 250 && touchesDistance < 10
1809 | }
1810 |
1811 | // Nothing found
1812 | return false;
1813 | }
1814 |
1815 | /**
1816 | * Returns current timestamp as an integer
1817 | *
1818 | * @return {Number}
1819 | */
1820 | , now: Date.now || function() {
1821 | return new Date().getTime();
1822 | }
1823 |
1824 | // From underscore.
1825 | // Returns a function, that, when invoked, will only be triggered at most once
1826 | // during a given window of time. Normally, the throttled function will run
1827 | // as much as it can, without ever going more than once per `wait` duration;
1828 | // but if you'd like to disable the execution on the leading edge, pass
1829 | // `{leading: false}`. To disable execution on the trailing edge, ditto.
1830 | // jscs:disable
1831 | // jshint ignore:start
1832 | , throttle: function(func, wait, options) {
1833 | var that = this;
1834 | var context, args, result;
1835 | var timeout = null;
1836 | var previous = 0;
1837 | if (!options) options = {};
1838 | var later = function() {
1839 | previous = options.leading === false ? 0 : that.now();
1840 | timeout = null;
1841 | result = func.apply(context, args);
1842 | if (!timeout) context = args = null;
1843 | };
1844 | return function() {
1845 | var now = that.now();
1846 | if (!previous && options.leading === false) previous = now;
1847 | var remaining = wait - (now - previous);
1848 | context = this;
1849 | args = arguments;
1850 | if (remaining <= 0 || remaining > wait) {
1851 | clearTimeout(timeout);
1852 | timeout = null;
1853 | previous = now;
1854 | result = func.apply(context, args);
1855 | if (!timeout) context = args = null;
1856 | } else if (!timeout && options.trailing !== false) {
1857 | timeout = setTimeout(later, remaining);
1858 | }
1859 | return result;
1860 | };
1861 | }
1862 | // jshint ignore:end
1863 | // jscs:enable
1864 |
1865 | /**
1866 | * Create a requestAnimationFrame simulation
1867 | *
1868 | * @param {Number|String} refreshRate
1869 | * @return {Function}
1870 | */
1871 | , createRequestAnimationFrame: function(refreshRate) {
1872 | var timeout = null
1873 |
1874 | // Convert refreshRate to timeout
1875 | if (refreshRate !== 'auto' && refreshRate < 60 && refreshRate > 1) {
1876 | timeout = Math.floor(1000 / refreshRate)
1877 | }
1878 |
1879 | if (timeout === null) {
1880 | return window.requestAnimationFrame || requestTimeout(33)
1881 | } else {
1882 | return requestTimeout(timeout)
1883 | }
1884 | }
1885 | }
1886 |
1887 | /**
1888 | * Create a callback that will execute after a given timeout
1889 | *
1890 | * @param {Function} timeout
1891 | * @return {Function}
1892 | */
1893 | function requestTimeout(timeout) {
1894 | return function(callback) {
1895 | window.setTimeout(callback, timeout)
1896 | }
1897 | }
1898 |
1899 | },{}]},{},[1]);
1900 |
--------------------------------------------------------------------------------
/unique_classes.json:
--------------------------------------------------------------------------------
1 | {
2 | "Linked.Art": [
3 | "HumanMadeObject", "Material",
4 | "Place",
5 | "Actor", "Person", "Group",
6 | "Type", "Language", "Currency", "MeasurementUnit", "Material",
7 | "InformationObject", "VisualItem", "LinguisticObject", "Set", "Right",
8 | "Name", "Identifier",
9 | "Event", "Activity", "Acquisition", "Production", "Creation", "AttributeAssignment",
10 | "TimeSpan",
11 | "Dimension", "MonetaryUnit", "MeasurementUnit",
12 | "DigitalObject", "DigitalService"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/xml/index.php:
--------------------------------------------------------------------------------
1 | $i)
17 | {
18 | $iurl = $pi["dirname"]."/".$i["@attributes"]["schemaLocation"];
19 | $ipi = pathinfo ($iurl);
20 |
21 | echo "$url includes $ipi[basename]|$iurl\n";
22 | $idata = xsd2arr ($iurl, 0);
23 |
24 | if (isset($idata["simpleType"]))
25 | {echo simpleType ($idata["simpleType"], $ipi["basename"]);}
26 | }
27 |
28 | exit;
29 |
30 | /*if ($str = file_get_contents($file)) {
31 | prg(0, $str);
32 |
33 | $xml = simplexml_load_string($str);
34 | $arr = object2array($xml);
35 |
36 | prg(0, $arr);
37 | } else {
38 | exit('Failed to open test.xml.');
39 | }*/
40 |
41 |
42 | function processSimpleType ($arr, $url="")
43 | {
44 | $out = "";
45 | // single item
46 | if (isset($arr["@attributes"]))
47 | {$out .= simpleType ($arr, $url="");}
48 | else
49 | {
50 | foreach ($arr as $k => $std)
51 | {$out .= simpleType ($std, $url);}
52 | }
53 |
54 | return ($out);
55 | }
56 |
57 | function simpleType ($std, $url="")
58 | {
59 | global $btno;
60 |
61 | $out = "";
62 |
63 | $thing = array(
64 | "name" => "",
65 | "type" => "",
66 | "values" => array(),
67 | "comments" => array(),
68 | "patterns" => array(),
69 | "others" => array());
70 |
71 | if (isset($std["@attributes"]["name"]) and $std["@attributes"]["name"])
72 | {$thing["name"] = $std["@attributes"]["name"];
73 | unset($std["@attributes"]);}
74 |
75 | if (isset($std["restriction"]["@attributes"]["base"]) and $std["restriction"]["@attributes"]["base"])
76 | {$thing["type"] = $std["restriction"]["@attributes"]["base"];
77 | unset($std["restriction"]["@attributes"]);}
78 |
79 | /*if (isset($std["restriction"]["enumeration"]) and $std["restriction"]["enumeration"])
80 | {foreach ($std["restriction"]["enumeration"] as $ek => $ev)
81 | {$thing["values"][] = $ev["@attributes"]["value"];}
82 | unset($std["restriction"]["enumeration"]);}*/
83 | if (isset($std["restriction"]["enumeration"]))
84 | {$thing["values"] = thingAttributes ($std["restriction"]["enumeration"], "value");
85 | unset($std["restriction"]["enumeration"]);}
86 |
87 | /*if (isset($std["restriction"]["comment"]) and $std["restriction"]["comment"])
88 | {foreach ($std["restriction"]["comment"] as $ek => $ev)
89 | {if ($ev){$thing["comments"][] = $ev["@attributes"]["value"];}}
90 | unset($std["restriction"]["comment"]);}*/
91 | if (isset($std["restriction"]["comment"]))
92 | {$thing["comments"] = thingAttributes ($std["restriction"]["comment"], "comment");
93 | unset($std["restriction"]["comment"]);}
94 |
95 |
96 | /*if (isset($std["restriction"]["pattern"]) and $std["restriction"]["pattern"])
97 | {
98 | if (isset($std["restriction"]["pattern"]["@attributes"]) and $std["restriction"]["pattern"]["@attributes"])
99 | {$thing["patterns"][] = $std["restriction"]["pattern"]["@attributes"]["value"];}
100 | else {
101 | foreach ($std["restriction"]["pattern"] as $ek => $ev)
102 | {if ($ev){$thing["patterns"][] = $ev["@attributes"]["value"];}}
103 | }
104 |
105 | }*/
106 | if (isset($std["restriction"]["pattern"]))
107 | {$thing["patterns"] = thingAttributes ($std["restriction"]["pattern"], "pattern");
108 | unset($std["restriction"]["pattern"]);}
109 |
110 | foreach ($std["restriction"] as $k => $a)
111 | {
112 | if (isset($a["@attributes"]["value"]))
113 | {$thing["others"][$k] = $a["@attributes"]["value"];}
114 | }
115 |
116 | if ($thing["name"])
117 | {
118 | if ($url) {
119 | $out .= "$url\thas metadata\t$thing[name]\n";
120 | }
121 | $out .= "$thing[name]\thas type\t$thing[type]#-$btno\n";
122 |
123 | $btno++;
124 |
125 | // Create nodes for each value
126 | /*if ($thing["values"])
127 | {
128 | foreach ($thing["values"] as $vk => $v)
129 | {$out .= "$thing[name]\thas possible value\t$v\n";}
130 | }*/
131 |
132 |
133 | if ($thing["values"])
134 | {$out .= "$thing[name]\thas possible values\t";
135 | $out .= implode("
", $thing["values"])."\t|note\n";}
136 |
137 | if ($thing["patterns"])
138 | {$out .= "$thing[name]\thas format\t".
139 | implode("
", $thing["patterns"])."\t|note\n";}
140 |
141 | if ($thing["comments"])
142 | {$out .= "$thing[name]\thas comment\t".
143 | implode("
", $thing["comments"])."\t|note\n";}
144 |
145 | if ($thing["others"])
146 | {foreach ($thing["others"] as $k => $v)
147 | {$out .= "$thing[name]\thas metadata\t$k\n".
148 | "$k\thas value\t$v\n";}}
149 | }
150 |
151 | return ($out);
152 | }
153 |
154 |
155 | function thingAttributes ($arr=array(), $label="things")
156 | {
157 | $thing = array();
158 |
159 | if (isset($arr) and $arr)
160 | {
161 | if (isset($arr["@attributes"]) and $arr["@attributes"])
162 | {$thing[] = $arr["@attributes"]["value"];}
163 | else {
164 | foreach ($arr as $k => $v)
165 | {
166 | if (isset($v["@attributes"]) and $v["@attributes"]) {
167 | $thing[] = $v["@attributes"]["value"];
168 | }
169 | }
170 | }
171 | }
172 |
173 | return ($thing);
174 | }
175 |
176 | function xsd2arr ($url, $export=false)
177 | {
178 | $doc = new DOMDocument();
179 | $doc->preserveWhiteSpace = true;
180 | $doc->load($url);
181 | $doc->save('t.xml');
182 | $xmlfile = file_get_contents('t.xml');
183 | $parseObj = str_replace($doc->lastChild->prefix.':',"",$xmlfile);
184 | $ob= simplexml_load_string($parseObj);
185 | $json = json_encode($ob);
186 |
187 | if ($export)
188 | {
189 | header('Content-Type: application/json');
190 | header("Access-Control-Allow-Origin: *");
191 | echo $json;
192 | exit;
193 | }
194 | else
195 | {$data = json_decode($json, true);
196 | return ($data);}
197 | }
198 |
199 | function prg($exit=false, $alt=false, $noecho=false)
200 | {
201 | if ($alt === false) {$out = $GLOBALS;}
202 | else {$out = $alt;}
203 |
204 | ob_start();
205 | echo "";
206 | if (is_object($out))
207 | {var_dump($out);}
208 | else
209 | {print_r ($out);}
210 | echo "
";
211 | $out = ob_get_contents();
212 | ob_end_clean(); // Don't send output to client
213 |
214 | if (!$noecho) {echo $out;}
215 |
216 | if ($exit) {exit;}
217 | else {return ($out);}
218 | }
219 |
220 | function getRemoteJsonDetails ($uri, $format=false, $decode=false)
221 | {if ($format) {$uri = $uri.".".$format;}
222 | $fc = file_get_contents($uri);
223 | if ($decode)
224 | {$output = json_decode($fc, true);}
225 | else
226 | {$output = $fc;}
227 | return ($output);}
228 |
229 |
230 | function object2array($object) { return @json_decode(@json_encode($object),1); }
231 |
232 | /*
233 |
234 | titleType|https://schema.datacite.org/meta/kernel-4.4/include/datacite-titleType-v4.xsd has label titleType#-1 type|name
235 | titleType has possible value AlternativeTitle
236 | titleType has possible value Subtitle
237 | titleType has possible value TranslatedTitle
238 | titleType has possible value Other#-1
239 | titleType has version history "Version 1.0 - Created 2011-01-13 - FZ, TIB, Germany
2013-05 v3.0: Addition of ID to simpleType element
2015-02-12 v4.0 Added value 'Other'"
240 |
241 | contributorType|https://schema.datacite.org/meta/kernel-4.4/include/datacite-contributorType-v4.xsd has label contributorType#-1 type|name
242 | contributorType has comment The type of contributor of the resource. |note
243 | contributorType has possible value ContactPerson
244 | contributorType has possible value DataCollector
245 | contributorType has possible value DataCurator
246 | contributorType has possible value DataManager
247 | contributorType has possible value Distributor
248 | contributorType has possible value Editor
249 | contributorType has possible value HostingInstitution
250 | contributorType has possible value Other
251 | contributorType has possible value Producer
252 | contributorType has possible value ProjectLeader
253 | contributorType has possible value ProjectManager
254 | contributorType has possible value ProjectMember
255 | contributorType has possible value RegistrationAgency
256 | contributorType has possible value RegistrationAuthority
257 | contributorType has possible value RelatedPerson
258 | contributorType has possible value ResearchGroup
259 | contributorType has possible value RightsHolder
260 | contributorType has possible value Researcher
261 | contributorType has possible value Sponsor
262 | contributorType has possible value Supervisor
263 | contributorType has possible value WorkPackageLeader
264 |
265 |
266 | */
267 |
268 | ?>
269 |
--------------------------------------------------------------------------------
/xml/t.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Root element of a single record. This wrapper element is for XML implementation only and is not defined in the DataCite DOI standard.
32 | Note: This is the case for all wrapper elements within this schema.
33 | No content in this wrapper element.
34 |
35 |
36 |
37 |
38 |
39 |
40 | A persistent identifier that identifies a resource.
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | The main researchers involved working on the data, or the authors of the publication in priority order. May be a corporate/institutional or personal name.
56 | Format: Family, Given.
57 | Personal names can be further specified using givenName and familyName.
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 | A name or title by which a resource is known.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | The name of the entity that holds, archives, publishes prints, distributes, releases, issues, or produces the resource. This property will be used to formulate the citation, so consider the prominence of the role.
103 | In the case of datasets, "publish" is understood to mean making the data available to the community of researchers.
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | Year when the data is made publicly available. If an embargo period has been in effect, use the date when the embargo period ends.
116 | In the case of datasets, "publish" is understood to mean making the data available on a specific date to the community of researchers. If there is no standard publication year value, use the date that would be preferred from a citation perspective.
117 | YYYY
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | The type of a resource. You may enter an additional free text description.
126 | The format is open, but the preferred format is a single term of some detail so that a pair can be formed with the sub-property.
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | Subject, keywords, classification codes, or key phrases describing the resource.
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | The institution or person responsible for collecting, creating, or otherwise contributing to the developement of the dataset.
165 | The personal name format should be: Family, Given.
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | Different dates relevant to the work.
196 | YYYY,YYYY-MM-DD, YYYY-MM-DDThh:mm:ssTZD or any other format or level of granularity described in W3CDTF. Use RKMS-ISO8601 standard for depicting date ranges.
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | Primary language of the resource. Allowed values are taken from IETF BCP 47, ISO 639-1 language codes.
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 | An identifier or identifiers other than the primary Identifier applied to the resource being registered. This may be any alphanumeric string which is unique within its domain of issue. May be used for local identifiers. AlternateIdentifier should be used for another identifier of the same instance (same location, same file).
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | Identifiers of related resources. Use this property to indicate subsets of properties, as appropriate.
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | Unstructures size information about the resource.
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 | Technical format of the resource.
273 | Use file extension or MIME type where possible.
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 | Version number of the resource. If the primary resource has changed the version number increases.
282 | Register a new identifier for a major version change. Individual stewards need to determine which are major vs. minor versions. May be used in conjunction with properties 11 and 12 (AlternateIdentifier and RelatedIdentifier) to indicate various information updates. May be used in conjunction with property 17 (Description) to indicate the nature and file/record range of version.
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 | Any rights information for this resource. Provide a rights management statement for the resource or reference a service providing such information. Include embargo information if applicable.
291 | Use the complete title of a license and include version information if applicable.
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 | All additional information that does not fit in any of the other categories. May be used for technical information. It is a best practice to supply a description.
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 | Spatial region or named place where the data was gathered or about which the data is focused.
337 |
338 |
339 |
340 |
341 | A point contains a single latitude-longitude pair.
342 |
343 |
344 |
345 |
346 | A box contains two white space separated latitude-longitude pairs, with each pair separated by whitespace. The first pair is the lower corner, the second is the upper corner.
347 |
348 |
349 |
350 |
351 | A drawn polygon area, defined by a set of points and lines connecting the points in a closed chain.
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 | Information about financial support (funding) for the resource being registered.
372 |
373 |
374 |
375 |
376 |
377 | Name of the funding provider.
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 | Uniquely identifies a funding entity, according to various types.
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 | The code assigned by the funder to a sponsored award (grant).
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 | The human readable title of the award (grant).
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 | Information about a resource related to the one being registered e.g. a journal or book of which the article or chapter is part.
425 |
426 |
427 |
428 |
429 |
430 | The identifier for the related item.
431 |
432 |
433 |
434 |
435 |
436 |
437 | The type of the Identifier for the related item e.g. DOI.
438 |
439 |
440 |
441 |
442 | The name of the scheme.
443 |
444 |
445 |
446 |
447 | The URI of the relatedMetadataScheme.
448 |
449 |
450 |
451 |
452 | The type of the relatedMetadataScheme, linked with the schemeURI.
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 | The institution or person responsible for creating the
465 | related resource. To supply multiple creators, repeat this property.
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 | Title of the related item.
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 | The year when the item was or will be made publicly available.
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 | Volume of the related item.
518 |
519 |
520 |
521 |
522 | Issue number or name of the related item.
523 |
524 |
525 |
526 |
527 | Number of the related item e.g. report number of article number.
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 | First page of the related item e.g. of the chapter, article, or conference paper.
540 |
541 |
542 |
543 |
544 | Last page of the related item e.g. of the chapter, article, or conference paper.
545 |
546 |
547 |
548 |
549 | The name of the entity that holds, archives, publishes prints, distributes, releases, issues, or produces the resource. This property will be used to formulate the citation, so consider the prominence of the role.
550 |
551 |
552 |
553 |
554 | Edition or version of the related item.
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 | The institution or person responsible for collecting,
563 | managing, distributing, or otherwise contributing to the development of
564 | the resource.
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 | The type of contributor of the resource.
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 | The type of the related item, e.g. journal article, book or chapter.
595 |
596 |
597 |
598 |
599 | Description of the relationship of the resource being registered (A) and the related resource (B).
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 | Uniquely identifies a creator or contributor, according to various identifier schemes.
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
641 |
642 |
646 |
647 |
652 |
653 |
658 |
659 |
660 |
661 |
662 |
663 |
664 | Uniquely identifies an affiliation, according to various identifier schemes.
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
--------------------------------------------------------------------------------