Rework SVGRect and Doors
This commit is contained in:
		
							parent
							
								
									de5fff311c
								
							
						
					
					
						commit
						cfea9b051f
					
				
					 3 changed files with 89 additions and 76 deletions
				
			
		|  | @ -1,5 +1,10 @@ | ||||||
| <template> | <template> | ||||||
|   <SVGRect :rectangle="door.position" @click.left="on_click" /> |   <SVGRect | ||||||
|  |     style="cursor: pointer" | ||||||
|  |     :rectangle="door.position" | ||||||
|  |     @click.left="on_click" | ||||||
|  |   > | ||||||
|  |   </SVGRect> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
|  | @ -32,9 +37,3 @@ export default class extends Vue { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
| rect { |  | ||||||
|   cursor: pointer; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
|  | @ -1,5 +1,22 @@ | ||||||
| <template> | <template> | ||||||
|  |   <foreignObject | ||||||
|  |     :x="Math.round(parent_aspect_ratio * rectangle.left)" | ||||||
|  |     :y="rectangle.top" | ||||||
|  |     :width="Math.round(parent_aspect_ratio * rectangle.width)" | ||||||
|  |     :height="rectangle.height" | ||||||
|  |     :style="`transform: scaleX(${1 / parent_aspect_ratio})`" | ||||||
|  |   > | ||||||
|  |     <div | ||||||
|  |       v-if="variant !== undefined" | ||||||
|  |       xmlns="http://www.w3.org/1999/xhtml" | ||||||
|  |       class="px-4 is-flex is-align-items-center is-justify-content-center is-size-1 has-text-weight-bold" | ||||||
|  |     > | ||||||
|  |       <slot name="default" /> | ||||||
|  |     </div> | ||||||
|  |   </foreignObject> | ||||||
|   <rect |   <rect | ||||||
|  |     ref="rect" | ||||||
|  |     v-bind="$attrs" | ||||||
|     :class="variant !== undefined ? variant : ''" |     :class="variant !== undefined ? variant : ''" | ||||||
|     :x="rectangle.left" |     :x="rectangle.left" | ||||||
|     :y="rectangle.top" |     :y="rectangle.top" | ||||||
|  | @ -12,7 +29,13 @@ | ||||||
| import { Rectangle } from "@/lib/rectangle"; | import { Rectangle } from "@/lib/rectangle"; | ||||||
| import { Options, Vue } from "vue-class-component"; | import { Options, Vue } from "vue-class-component"; | ||||||
| 
 | 
 | ||||||
| type RectColor = "primary" | "link" | "info" | "success" | "warning" | "danger"; | type BulmaVariant = | ||||||
|  |   | "primary" | ||||||
|  |   | "link" | ||||||
|  |   | "info" | ||||||
|  |   | "success" | ||||||
|  |   | "warning" | ||||||
|  |   | "danger"; | ||||||
| 
 | 
 | ||||||
| @Options({ | @Options({ | ||||||
|   props: { |   props: { | ||||||
|  | @ -24,14 +47,56 @@ type RectColor = "primary" | "link" | "info" | "success" | "warning" | "danger"; | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
| export default class extends Vue { | export default class extends Vue { | ||||||
|   public variant?: RectColor; |   public variant?: BulmaVariant; | ||||||
|   public rectangle!: Rectangle; |   public rectangle!: Rectangle; | ||||||
|  | 
 | ||||||
|  |   private refreshKey = 0; | ||||||
|  | 
 | ||||||
|  |   declare $refs: { | ||||||
|  |     rect: unknown; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   private refresh() { | ||||||
|  |     window.setTimeout(() => { | ||||||
|  |       // don't loop endlessly | ||||||
|  |       if (this.refreshKey < 10000) { | ||||||
|  |         this.refreshKey++; | ||||||
|  |       } | ||||||
|  |     }, 100); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public get parent_aspect_ratio(): number { | ||||||
|  |     this.refreshKey; // read it just to force recompute on change | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       !(this.$refs.rect instanceof SVGRectElement) || | ||||||
|  |       this.$refs.rect.parentElement === null | ||||||
|  |     ) { | ||||||
|  |       this.refresh(); | ||||||
|  |       return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const parent = this.$refs.rect.parentElement; | ||||||
|  |     const result = parent.clientWidth / parent.clientHeight; | ||||||
|  | 
 | ||||||
|  |     // force recompute for suspicious results | ||||||
|  |     if (result === 0 || result === Infinity) { | ||||||
|  |       this.refresh(); | ||||||
|  |       return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  |   } | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
| @import "@/bulma-vars"; | @import "@/bulma-vars"; | ||||||
| 
 | 
 | ||||||
|  | foreignObject > div { | ||||||
|  |   height: inherit; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| rect { | rect { | ||||||
|   fill: transparent; |   fill: transparent; | ||||||
|   fill-opacity: 0.3; |   fill-opacity: 0.3; | ||||||
|  |  | ||||||
|  | @ -1,18 +1,8 @@ | ||||||
| <template> | <template> | ||||||
|   <SVGRect |   <SVGRect | ||||||
|  |     style="cursor: text" | ||||||
|     :rectangle="door.position" |     :rectangle="door.position" | ||||||
|     :variant="editing ? 'success' : 'primary'" |     :variant="editing ? 'success' : 'primary'" | ||||||
|   /> |  | ||||||
|   <foreignObject |  | ||||||
|     :x="Math.round(parent_aspect_ratio * door.position.left)" |  | ||||||
|     :y="door.position.top" |  | ||||||
|     :width="Math.round(parent_aspect_ratio * door.position.width)" |  | ||||||
|     :height="door.position.height" |  | ||||||
|     :style="`transform: scaleX(${1 / parent_aspect_ratio})`" |  | ||||||
|   > |  | ||||||
|     <div |  | ||||||
|       xmlns="http://www.w3.org/1999/xhtml" |  | ||||||
|       class="px-4 is-flex is-align-items-center is-justify-content-center" |  | ||||||
|     @click.left="on_click" |     @click.left="on_click" | ||||||
|   > |   > | ||||||
|     <input |     <input | ||||||
|  | @ -25,11 +15,10 @@ | ||||||
|       placeholder="Tag" |       placeholder="Tag" | ||||||
|       @keydown="on_keydown" |       @keydown="on_keydown" | ||||||
|     /> |     /> | ||||||
|       <div v-else class="is-size-1 has-text-weight-bold has-text-danger"> |     <div v-else class="has-text-danger"> | ||||||
|       {{ door.day > 0 ? door.day : "*" }} |       {{ door.day > 0 ? door.day : "*" }} | ||||||
|     </div> |     </div> | ||||||
|     </div> |   </SVGRect> | ||||||
|   </foreignObject> |  | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
|  | @ -52,48 +41,18 @@ export default class extends Vue { | ||||||
| 
 | 
 | ||||||
|   public day_str = ""; |   public day_str = ""; | ||||||
|   public editing = false; |   public editing = false; | ||||||
|   private refreshKey = 0; |  | ||||||
| 
 | 
 | ||||||
|   declare $refs: { |   declare $refs: { | ||||||
|     day_input: HTMLInputElement | unknown; |     day_input: HTMLInputElement | unknown; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   private refresh() { |  | ||||||
|     window.setTimeout(() => { |  | ||||||
|       // don't loop endlessly |  | ||||||
|       if (this.refreshKey < 10000) { |  | ||||||
|         this.refreshKey++; |  | ||||||
|       } |  | ||||||
|     }, 100); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   public get parent_aspect_ratio(): number { |  | ||||||
|     this.refreshKey; // read it just to force recompute on change |  | ||||||
| 
 |  | ||||||
|     if (!(this.$el instanceof Text) || this.$el.parentElement === null) { |  | ||||||
|       this.refresh(); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const parent = this.$el.parentElement; |  | ||||||
|     const result = parent.clientWidth / parent.clientHeight; |  | ||||||
| 
 |  | ||||||
|     // force recompute for suspicious results |  | ||||||
|     if (result === 0 || result === Infinity) { |  | ||||||
|       this.refresh(); |  | ||||||
|       return 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private toggle_editing() { |   private toggle_editing() { | ||||||
|     this.day_str = String(this.door.day); |     this.day_str = String(this.door.day); | ||||||
|     this.editing = !this.editing; |     this.editing = !this.editing; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public on_click(event: MouseEvent) { |   public on_click(event: MouseEvent) { | ||||||
|     if (event.target === null || !(event.target instanceof HTMLDivElement)) { |     if (event.target === null || !(event.target instanceof SVGRectElement)) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -131,13 +90,3 @@ export default class extends Vue { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
| 
 |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| foreignObject { |  | ||||||
|   cursor: text; |  | ||||||
| 
 |  | ||||||
|   > div { |  | ||||||
|     height: inherit; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue