initial commit, got anchors working
This commit is contained in:
		
							parent
							
								
									23b3c92b18
								
							
						
					
					
						commit
						52b5dda707
					
				
					 14 changed files with 23928 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
# Line and Surface
 | 
			
		||||
 | 
			
		||||
Web presentation of the Line and Surface Project.
 | 
			
		||||
Web presentation of the Line and Surface project.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								app/.browserslistrc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/.browserslistrc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
> 1%
 | 
			
		||||
last 2 versions
 | 
			
		||||
not dead
 | 
			
		||||
							
								
								
									
										23
									
								
								app/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
.DS_Store
 | 
			
		||||
node_modules
 | 
			
		||||
/dist
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# local env files
 | 
			
		||||
.env.local
 | 
			
		||||
.env.*.local
 | 
			
		||||
 | 
			
		||||
# Log files
 | 
			
		||||
npm-debug.log*
 | 
			
		||||
yarn-debug.log*
 | 
			
		||||
yarn-error.log*
 | 
			
		||||
pnpm-debug.log*
 | 
			
		||||
 | 
			
		||||
# Editor directories and files
 | 
			
		||||
.idea
 | 
			
		||||
.vscode
 | 
			
		||||
*.suo
 | 
			
		||||
*.ntvs*
 | 
			
		||||
*.njsproj
 | 
			
		||||
*.sln
 | 
			
		||||
*.sw?
 | 
			
		||||
							
								
								
									
										5
									
								
								app/babel.config.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/babel.config.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
module.exports = {
 | 
			
		||||
  presets: [
 | 
			
		||||
    '@vue/cli-plugin-babel/preset'
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23626
									
								
								app/package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										23626
									
								
								app/package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										24
									
								
								app/package.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/package.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "line-and-surface",
 | 
			
		||||
  "version": "0.1.0",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "serve": "vue-cli-service serve",
 | 
			
		||||
    "build": "vue-cli-service build"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "core-js": "^3.6.5",
 | 
			
		||||
    "normalize.css": "^8.0.1",
 | 
			
		||||
    "panzoom": "^9.4.1",
 | 
			
		||||
    "vue": "^3.0.0",
 | 
			
		||||
    "vuex": "^4.0.0-0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@vue/cli-plugin-babel": "~4.5.0",
 | 
			
		||||
    "@vue/cli-plugin-typescript": "~4.5.0",
 | 
			
		||||
    "@vue/cli-plugin-vuex": "~4.5.0",
 | 
			
		||||
    "@vue/cli-service": "~4.5.0",
 | 
			
		||||
    "@vue/compiler-sfc": "^3.0.0",
 | 
			
		||||
    "typescript": "~3.9.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								app/public/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/public/index.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang="">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
 | 
			
		||||
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
 | 
			
		||||
    <title><%= htmlWebpackPlugin.options.title %></title>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <noscript>
 | 
			
		||||
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
 | 
			
		||||
    </noscript>
 | 
			
		||||
    <div id="app"></div>
 | 
			
		||||
    <!-- built files will be auto injected -->
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										30
									
								
								app/src/App.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								app/src/App.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <SVGContent id="root" url="intro.svg"/>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import {defineComponent} from "vue";
 | 
			
		||||
import SVGContent from "@/components/SVGContent.vue";
 | 
			
		||||
import "normalize.css";
 | 
			
		||||
import ZoomPan from "@/components/ZoomPan.vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "App",
 | 
			
		||||
  components: {
 | 
			
		||||
    ZoomPan,
 | 
			
		||||
    SVGContent
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
html, body {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html, body, #app, #root {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  cursor: default;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										99
									
								
								app/src/components/SVGContent.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								app/src/components/SVGContent.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,99 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="content" ref="root">
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import {defineComponent, onMounted, ref} from "vue";
 | 
			
		||||
import createPanZoom, {PanZoom} from "panzoom";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "SVGContent",
 | 
			
		||||
  props: {
 | 
			
		||||
    url: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      required: true
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  setup(props) {
 | 
			
		||||
    const domparser = new DOMParser();
 | 
			
		||||
    const root = ref(null);
 | 
			
		||||
 | 
			
		||||
    onMounted(async () => {
 | 
			
		||||
      const element = root.value as unknown as HTMLDivElement;
 | 
			
		||||
 | 
			
		||||
      const panzoom = createPanZoom(element, {
 | 
			
		||||
        smoothScroll: false,
 | 
			
		||||
        zoomSpeed: 0.05
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      panzoom.on("transform", function (panzoom: PanZoom) {
 | 
			
		||||
        const transform = panzoom.getTransform();
 | 
			
		||||
        // console.log(transform);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      panzoom.on("panend", function (panzoom: PanZoom) {
 | 
			
		||||
        console.log("panend");
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const fetchResult = await fetch(props.url);
 | 
			
		||||
      const svgParsed = domparser.parseFromString(await fetchResult.text(), "image/svg+xml") as Document;
 | 
			
		||||
      const svg = element.appendChild(svgParsed.firstElementChild as Element) as any;
 | 
			
		||||
 | 
			
		||||
      const anchors = processAnchors(svg);
 | 
			
		||||
      const anchor = anchors[0];
 | 
			
		||||
      window.addEventListener("keydown", (ev) => {
 | 
			
		||||
        if (ev.key !== " ") {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const transform = panzoom.getTransform();
 | 
			
		||||
        console.log(transform);
 | 
			
		||||
        const currentRatio = svg.clientWidth * transform.scale / svg.viewBox.baseVal.width;
 | 
			
		||||
        const targetScale = 2;
 | 
			
		||||
 | 
			
		||||
        const svgTargetX = anchor.x.baseVal.value + anchor.width.baseVal.value / 2;
 | 
			
		||||
        const svgTargetY = anchor.y.baseVal.value + anchor.height.baseVal.value / 2;
 | 
			
		||||
 | 
			
		||||
        console.log(svgTargetX * currentRatio + transform.x);
 | 
			
		||||
 | 
			
		||||
        panzoom.smoothMoveTo(
 | 
			
		||||
            svgTargetX * currentRatio * -1 + window.innerWidth / 2,
 | 
			
		||||
            svgTargetY * currentRatio * -1 + window.innerHeight / 2,
 | 
			
		||||
        );
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          panzoom.smoothZoomAbs(window.innerWidth / 2, window.innerHeight / 2, 1);
 | 
			
		||||
        }, 1000);
 | 
			
		||||
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      root
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function processAnchors(document: XMLDocument): SVGRectElement[] {
 | 
			
		||||
  let result = [];
 | 
			
		||||
  let i = 1;
 | 
			
		||||
  while (true) {
 | 
			
		||||
    let anchor = document.getElementById(`anchor_${i}`) as SVGRectElement | null;
 | 
			
		||||
    if (anchor === null) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    anchor.classList.add("svgcontent_anchor");
 | 
			
		||||
    result.push(anchor);
 | 
			
		||||
    i++;
 | 
			
		||||
  }
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style>
 | 
			
		||||
.svgcontent_anchor {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										38
									
								
								app/src/components/ZoomPan.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app/src/components/ZoomPan.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="zoompan" ref="root">
 | 
			
		||||
    <slot></slot>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import {defineComponent, onMounted, ref, reactive} from "vue";
 | 
			
		||||
import createPanZoom, {PanZoom} from "panzoom";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "ZoomPan",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const root = ref(null);
 | 
			
		||||
    const bbox = reactive({
 | 
			
		||||
      x: undefined,
 | 
			
		||||
      y: undefined
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    onMounted(async () => {
 | 
			
		||||
      const element = root.value as unknown as HTMLDivElement;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    });
 | 
			
		||||
    return {
 | 
			
		||||
      root,
 | 
			
		||||
      bbox
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
			
		||||
<style scoped>
 | 
			
		||||
.zoompan {
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										5
									
								
								app/src/main.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
import { createApp } from 'vue'
 | 
			
		||||
import App from './App.vue'
 | 
			
		||||
import store from './store'
 | 
			
		||||
 | 
			
		||||
createApp(App).use(store).mount('#app')
 | 
			
		||||
							
								
								
									
										6
									
								
								app/src/shims-vue.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/shims-vue.d.ts
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
/* eslint-disable */
 | 
			
		||||
declare module '*.vue' {
 | 
			
		||||
  import type { DefineComponent } from 'vue'
 | 
			
		||||
  const component: DefineComponent<{}, {}, any>
 | 
			
		||||
  export default component
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								app/src/store/index.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/src/store/index.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
import { createStore } from 'vuex'
 | 
			
		||||
 | 
			
		||||
export default createStore({
 | 
			
		||||
  state: {
 | 
			
		||||
  },
 | 
			
		||||
  mutations: {
 | 
			
		||||
  },
 | 
			
		||||
  actions: {
 | 
			
		||||
  },
 | 
			
		||||
  modules: {
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										39
									
								
								app/tsconfig.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/tsconfig.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "target": "esnext",
 | 
			
		||||
    "module": "esnext",
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
    "importHelpers": true,
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "skipLibCheck": true,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "allowSyntheticDefaultImports": true,
 | 
			
		||||
    "sourceMap": true,
 | 
			
		||||
    "baseUrl": ".",
 | 
			
		||||
    "types": [
 | 
			
		||||
      "webpack-env"
 | 
			
		||||
    ],
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@/*": [
 | 
			
		||||
        "src/*"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "lib": [
 | 
			
		||||
      "esnext",
 | 
			
		||||
      "dom",
 | 
			
		||||
      "dom.iterable",
 | 
			
		||||
      "scripthost"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "include": [
 | 
			
		||||
    "src/**/*.ts",
 | 
			
		||||
    "src/**/*.tsx",
 | 
			
		||||
    "src/**/*.vue",
 | 
			
		||||
    "tests/**/*.ts",
 | 
			
		||||
    "tests/**/*.tsx"
 | 
			
		||||
  ],
 | 
			
		||||
  "exclude": [
 | 
			
		||||
    "node_modules"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue