5ba1b5b0ff072377f22cda4c3fcc3eaa197fe4d2
2 copyright 2008-2014 Benoit Pin - Centre de recherche en informatique - MINES ParisTech
4 Licence Creative Commons http://creativecommons.org/licenses/by-nc/2.0/
11 var keyLeft
= 37, keyRight
= 39;
12 var isTextMime
= /^text\/.+/i;
13 var isAddToSelection
= /.*\/add_to_selection$/;
14 var imgRequestedSize
= /size=(\d+)/;
15 var DEFAULT_IMAGE_SIZES
= [500, 600, 800];
17 FilmSlider = function(filmBar
, slider
, ctxInfos
, image
, toolbar
, breadcrumbs
) {
18 var thisSlider
= this;
19 this.filmBar
= filmBar
;
20 this.filmBarWidth
= getObjectWidth(this.filmBar
);
21 var film
= filmBar
.firstChild
;
22 if (film
.nodeType
=== 3) { film
= film
.nextSibling
; }
25 this.rail
= slider
.parentNode
;
26 this.sliderSpeedRatio
= undefined;
27 this.sliderRatio
= undefined;
28 this.selectedSlide
= undefined;
29 this.selectedSlideInSelection
= undefined;
30 this.cartSlide
= document
.getElementById('cart_slide');
32 this.stretchable
= image
.parentNode
;
33 this.viewMode
= 'medium';
36 this.toolbar
= toolbar
;
38 var bcElements
= breadcrumbs
.getElementsByTagName('a');
39 this.lastBCElement
= bcElements
[bcElements
.length
-1];
40 var imgSrcParts
= image
.src
.split('/');
41 this.lastBCElement
.innerHTML
= imgSrcParts
[imgSrcParts
.length
-2];
42 this.hasBreadcrumbs
= true;
45 this.hasBreadcrumbs
= false;
48 var buttons
= toolbar
.getElementsByTagName('img');
50 for (i
=0 ; i
<buttons
.length
; i
++) {
52 name
= b
.getAttribute('name');
53 if (name
) { this.buttons
[name
] = b
; }
56 this.pendingImage
= new Image();
57 this.pendingImage
.onload = function() {
58 thisSlider
.refreshImage();
60 this.initialized
= false;
62 this.film
.style
.left
='0';
63 this.film
.style
.top
='0';
65 this.filmLength
= ctxInfos
.filmLength
;
66 this.center
= ctxInfos
.center
;
67 this.slideSize
= ctxInfos
.slideSize
;
68 this.ctxUrlTranslation
= ctxInfos
.ctxUrlTranslation
;
70 this.ddHandlers
= {'down' : function(evt
){thisSlider
.mouseDownHandler(evt
);},
71 'move' : function(evt
){thisSlider
.mouseMoveHandler(evt
);},
72 'up' : function(evt
){thisSlider
.mouseUpHandler(evt
);},
73 'out' : function(evt
){thisSlider
.mouseOutHandler(evt
);}
77 this.addEventListeners();
81 FilmSlider
.prototype.resizeSlider = function(evt
) {
82 var filmBarWidth
= this.filmBarWidth
;
83 if (!filmBarWidth
) { return; }
84 var filmWidth
= this.slideSize
* this.filmLength
;
85 var sliderRatio
= this.sliderRatio
= filmBarWidth
/ filmWidth
;
86 var sliderWidth
= filmBarWidth
* sliderRatio
;
87 this.rail
.style
.width
= filmBarWidth
+ 'px';
88 this.rail
.style
.display
= 'block';
89 this.rail
.style
.visibility
= 'visible';
90 if (sliderRatio
< 1) {
91 this.slider
.style
.width
= Math
.round(sliderWidth
) + 'px';
92 this.slider
.style
.visibility
= 'visible';
95 this.slider
.style
.visibility
= 'hidden';
98 this.winSize
= {'width' : getWindowWidth(),
99 'height' : getWindowHeight()};
100 this.maxRightPosition
= filmBarWidth
- sliderWidth
;
101 this.sliderSpeedRatio
= - (filmBarWidth
- sliderWidth
) / (filmWidth
- filmBarWidth
);
102 if (!this.initialized
) {
103 this.centerSlide(this.center
);
104 this.selectedSlide
= this.filmBar
.getElementsByTagName('img')[this.center
].parentNode
;
105 this.initialized
= true;
109 FilmSlider
.prototype._checkSizeAfterLoad = function(evt
) {
111 this.filmBarWidth
= this._barSizes
[this._barSizes
.length
] = getObjectWidth(this.filmBar
);
114 this._checkSizeIntervalId
= setInterval(function(evt
){self
._checkSize(evt
);}, 25);
115 setTimeout(function(evt
){self
._checkSizeStability();}, 250);
118 FilmSlider
.prototype._checkSize = function(evt
) {
119 this._barSizes
[this._barSizes
.length
] = getObjectWidth(this.filmBar
);
120 if (this._barSizes
.length
>= 2 &&
121 this._barSizes
[this._barSizes
.length
-2] !== this._barSizes
[this._barSizes
.length
-1]) {
122 this.filmBarWidth
= this._barSizes
[this._barSizes
.length
-1];
123 this.initialized
= false;
128 FilmSlider
.prototype._checkSizeStability = function(evt
) {
131 for (i
=0 ; i
<this._barSizes
.length
- 1 ; i
++) {
132 if (this._barSizes
[i
] !== this._barSizes
[i
+1]) {
134 setTimeout(function(evt
){self
._checkSizeStability();}, 250);
138 clearInterval(this._checkSizeIntervalId
);
139 delete this._barSizes
, this._checkSizeIntervalId
;
142 FilmSlider
.prototype.fitToScreen = function(evt
) {
144 var thisSlider
= this;
145 addListener(window
, 'resize', function(evt
){thisSlider
._fitToScreen();});
148 FilmSlider
.prototype._fitToScreen = function(evt
) {
149 var wh
= getWindowHeight();
150 var rb
= getObjectTop(this.rail
) + getObjectHeight(this.rail
); // rail bottom
152 var sh
= getObjectHeight(this.stretchable
);
153 var newSize
= sh
+ delta
;
154 this.stretchable
.style
.height
= newSize
+ 'px';
156 var ratio
= this.image
.height
/ this.image
.width
;
157 var bestFitSize
= this.getBestFitSize(ratio
);
158 var currentSize
= parseInt(imgRequestedSize
.exec(this.image
.src
)[1], 10);
159 if (currentSize
!== bestFitSize
) {
160 var src
= this.image
.src
.replace(imgRequestedSize
, 'size=' + bestFitSize
);
161 this.pendingImage
.src
= src
;
165 FilmSlider
.prototype.getBestFitSize = function(ratio
) {
166 var fw
= getObjectWidth(this.stretchable
) - 1;
167 var fh
= getObjectHeight(this.stretchable
) - 1;
171 for (i
=DEFAULT_IMAGE_SIZES
.length
-1 ; i
>0 ; i
--) {
172 irw
= DEFAULT_IMAGE_SIZES
[i
];
174 if (irw
<= fw
&& irh
<= fh
) { break; }
178 for (i
=DEFAULT_IMAGE_SIZES
.length
-1 ; i
>0 ; i
--) {
179 irh
= DEFAULT_IMAGE_SIZES
[i
];
181 if (irw
<= fw
&& irh
<= fh
) { break; }
184 return DEFAULT_IMAGE_SIZES
[i
];
187 FilmSlider
.prototype.centerSlide = function(slideIndex
) {
188 if (this.sliderRatio
> 1) { return; }
189 var filmBarWidth
= getObjectWidth(this.filmBar
);
190 var x
= slideIndex
* this.slideSize
;
191 x
= x
- (filmBarWidth
- this.slideSize
) / 2.0;
192 x
= x
* this.sliderSpeedRatio
;
193 var p
= new Point( -x
, 0 );
194 this.setSliderPosition(p
);
197 FilmSlider
.prototype.setSliderPosition = function(point
) {
198 if(point
.x
< 0) { point
.x
= 0; }
199 if (point
.x
> this.maxRightPosition
) { point
.x
= this.maxRightPosition
; }
200 this.slider
.style
.left
= point
.x
+ 'px';
201 this.setFilmPosition(point
);
204 FilmSlider
.prototype.setFilmPosition = function(point
) {
205 this.film
.style
.left
= point
.x
/ this.sliderSpeedRatio
+ 'px';
208 FilmSlider
.prototype.getSliderPosition = function() {
209 var x
= parseInt(this.slider
.style
.left
, 10);
210 var y
= parseInt(this.slider
.style
.top
, 10);
211 var p
= new Point(x
, y
);
215 FilmSlider
.prototype.getFilmPosition = function() {
216 var x
= parseInt(this.film
.style
.left
, 10);
217 var y
= parseInt(this.film
.style
.top
, 10);
218 var p
= new Point(x
, y
);
222 FilmSlider
.prototype.loadSibling = function(previous
) {
225 slide
= this.selectedSlide
.parentNode
.previousSibling
;
226 if (slide
&& slide
.nodeType
===3) { slide
= slide
.previousSibling
; }
229 slide
= this.selectedSlide
.parentNode
.nextSibling
;
230 if (slide
&& slide
.nodeType
===3) { slide
= slide
.nextSibling
; }
233 if (!slide
) { return; }
235 var target
= slide
.getElementsByTagName('a')[0];
236 raiseMouseEvent(target
, 'click');
237 var index
= parseInt(target
.getAttribute('portfolio:position'), 10);
238 this.centerSlide(index
);
242 FilmSlider
.prototype.addEventListeners = function() {
243 var thisSlider
= this;
244 addListener(window
, 'resize', function(evt
){thisSlider
.resizeSlider(evt
);});
245 addListener(this.filmBar
, 'click', function(evt
){thisSlider
.thumbnailClickHandler(evt
);});
246 addListener(this.toolbar
, 'click', function(evt
){thisSlider
.toolbarClickHandler(evt
);});
247 addListener(window
, 'load', function(evt
){thisSlider
.fitToScreen(evt
);});
248 addListener(window
, 'load', function(evt
){thisSlider
._checkSizeAfterLoad(evt
);});
251 addListener(this.slider
, 'mousedown', this.ddHandlers
.down
);
252 if(browser
.isDOM2Event
){
253 if (browser
.isAppleWebKit
) {
254 this.filmBar
.addEventListener('mousewheel', function(evt
){thisSlider
.mouseWheelHandler(evt
);}, false);
257 addListener(this.filmBar
, 'DOMMouseScroll', function(evt
){thisSlider
.mouseWheelHandler(evt
);});
260 else if (browser
.isIE6up
) {
261 addListener(this.filmBar
, 'mousewheel', function(evt
){thisSlider
.mouseWheelHandler(evt
);});
264 addListener(document
, 'keydown', function(evt
){thisSlider
.keyDownHandler(evt
);});
265 addListener(document
, 'keypress', function(evt
){thisSlider
.keyPressHandler(evt
);});
269 FilmSlider
.prototype.mouseDownHandler = function(evt
) {
270 this.initialClickPoint
= new Point(evt
.clientX
, evt
.clientY
);
271 this.initialPosition
= this.getSliderPosition();
272 this.dragInProgress
= true;
273 addListener(document
, 'mousemove', this.ddHandlers
.move);
274 addListener(document
, 'mouseup', this.ddHandlers
.up
);
275 addListener(document
.body
, 'mouseout', this.ddHandlers
.out
);
279 FilmSlider
.prototype.mouseMoveHandler = function(evt
) {
280 if(!this.dragInProgress
) { return; }
283 evt
= getEventObject(evt
);
284 var currentPoint
= new Point(evt
.clientX
, evt
.clientY
);
285 var displacement
= currentPoint
.diff(this.initialClickPoint
);
286 this.setSliderPosition(this.initialPosition
.add(displacement
));
289 FilmSlider
.prototype.mouseUpHandler = function(evt
) {
290 this.dragInProgress
= false;
291 evt
= getEventObject(evt
);
292 this.mouseMoveHandler(evt
);
296 FilmSlider
.prototype.mouseOutHandler = function(evt
) {
297 evt
= getEventObject(evt
);
301 x
> this.winSize
.width
||
303 y
> this.winSize
.height
305 this.mouseUpHandler(evt
);
309 FilmSlider
.prototype.thumbnailClickHandler = function(evt
) {
310 var target
= getTargetedObject(evt
);
311 while (target
.tagName
!== 'A' && target
!== this.filmBar
) { target
= target
.parentNode
; }
312 if (target
.tagName
!== 'A') { return; }
314 if (this.viewMode
=== 'full') {
315 this.mosaique
.unload();
316 this.mosaique
= null;
317 this.viewMode
= 'medium';
320 disablePropagation(evt
);
322 history
.pushState(target
.href
, '', target
.href
);
324 var imgBaseUrl
= target
.href
;
326 if (this.ctxUrlTranslation
[0]) {
327 canonicalImgUrl
= imgBaseUrl
.replace(this.ctxUrlTranslation
[0],
328 this.ctxUrlTranslation
[1]);
330 else { canonicalImgUrl
= imgBaseUrl
; }
332 var ajaxUrl
= imgBaseUrl
+ '/photo_view_ajax';
335 //this.pendingImage.src = canonicalImgUrl + '/getResizedImage?size=600';
336 var thumbnail
= target
.getElementsByTagName('IMG')[0];
337 var bestFitSize
= this.getBestFitSize(thumbnail
.height
/thumbnail
.width
);
338 this.pendingImage
.src
= canonicalImgUrl
+ '/getResizedImage?size=' + bestFitSize
;
341 var fullScreenLink
= this.buttons
.full_screen
.parentNode
;
342 fullScreenLink
.href
= canonicalImgUrl
+ '/zoom_view';
344 var toggleSelectionBtn
= this.buttons
.toggle_selection
;
345 var toggleSelectionLink
= toggleSelectionBtn
.parentNode
;
346 this.selectedSlideInSelection
= (target
.className
==='selected');
347 if (this.selectedSlideInSelection
) {
348 toggleSelectionBtn
.src
= portal_url() + '/unselect_flag_btn.gif';
349 toggleSelectionBtn
.alt
= toggleSelectionLink
.title
= 'Retirer de la sélection';
350 toggleSelectionLink
.href
= canonicalImgUrl
+ '/remove_to_selection';
353 toggleSelectionBtn
.src
= portal_url() + '/select_flag_btn.gif';
354 toggleSelectionBtn
.alt
= toggleSelectionLink
.title
= 'Ajouter à la sélection';
355 toggleSelectionLink
.href
= canonicalImgUrl
+ '/add_to_selection';
358 var showBuyableButtonLink
= this.buttons
.show_buyable
.parentNode
;
359 showBuyableButtonLink
.href
= canonicalImgUrl
+ '/get_slide_buyable_items';
360 this.cartSlide
.innerHTML
= '';
361 this.cartSlide
.style
.visibility
='hidden';
364 var metadataButton
= this.buttons
.edit_metadata
;
365 if (metadataButton
) {
366 var metadataEditLink
= metadataButton
.parentNode
;
367 metadataEditLink
.href
= canonicalImgUrl
+ '/photo_edit_form';
371 var req
= new XMLHttpRequest();
372 req
.onreadystatechange = function() {
373 switch (req
.readyState
) {
379 if (! isTextMime
.exec(req
.getResponseHeader('Content-Type'))) {
380 req
.onreadystatechange
= null;
383 window
.location
.href
= thisFS
._fallBackUrl
;
390 if (req
.status
=== 200) { thisFS
.populateViewer(req
); }
395 req
.open("GET", ajaxUrl
, true);
398 // update old displayed slide className
399 var className
= this.selectedSlide
.className
;
400 var classes
= className
.split(' ');
404 for (i
=0 ; i
<classes
.length
; i
++) {
406 if (name
!== 'displayed') {
407 newClasses
.push(name
);
411 this.selectedSlide
.className
= newClasses
.join(' ');
413 // hightlight new displayed slide
414 this.selectedSlide
= target
;
415 className
= this.selectedSlide
.className
;
416 classes
= className
.split(' ');
417 classes
.push('displayed');
418 this.selectedSlide
.className
= classes
.join(' ');
422 FilmSlider
.prototype.toolbarClickHandler = function(evt
) {
423 var target
= getTargetedObject(evt
);
424 var button
, link
, url
;
425 if(target
.tagName
=== 'IMG' && target
.getAttribute('name')) {
426 switch(target
.getAttribute('name')) {
429 disablePropagation(evt
);
431 link
= button
.parentNode
;
433 this.loadSibling(true);
437 disablePropagation(evt
);
439 link
= button
.parentNode
;
441 this.loadSibling(false);
445 disablePropagation(evt
);
446 target
.parentNode
.blur();
447 if (this.viewMode
=== 'full') {
448 this.mosaique
.unload();
449 this.mosaique
= null;
450 this.viewMode
= 'medium';
453 var main
= document
.getElementById('photo_viewer');
454 url
= target
.parentNode
.href
;
455 url
= url
.substring(0, url
.length
- '/zoom_view'.length
);
456 var margins
= {'top':0, 'right':-1, 'bottom':0, 'left':0};
457 this.mosaique
= new Mosaique(main
, url
, margins
);
458 this.viewMode
= 'full';
461 case 'toggle_selection':
463 disablePropagation(evt
);
465 link
= button
.parentNode
;
468 var req
= new XMLHttpRequest();
470 req
.open("POST", url
, true);
471 req
.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
475 var parts
= url
.split('/');
476 var canonicalImgUrl
= parts
.slice(0, parts
.length
-1).join('/');
478 if (isAddToSelection
.test(url
)) {
479 button
.src
= portal_url() + '/unselect_flag_btn.gif';
480 button
.alt
= link
.title
= 'Retirer de la sélection';
481 link
.href
= canonicalImgUrl
+ '/remove_to_selection';
482 this.selectedSlide
.className
= 'selected displayed';
483 this.image
.parentNode
.className
= 'selected';
484 this.selectedSlideInSelection
= true;
487 button
.src
= portal_url() + '/select_flag_btn.gif';
488 button
.alt
= link
.title
= 'Ajouter à la sélection';
489 link
.href
= canonicalImgUrl
+ '/add_to_selection';
490 this.selectedSlide
.className
= 'displayed';
491 this.image
.parentNode
.className
= '';
492 this.selectedSlideInSelection
= false;
498 disablePropagation(evt
);
500 link
= button
.parentNode
;
502 var slide
= this.cartSlide
;
503 slide
.innerHTML
= '';
504 slide
.style
.visibility
= 'visible';
505 var cw
= new CartWidget(slide
, link
.href
);
506 cw
.onCancel = function() {
507 CartWidget
.prototype.onCancel
.apply(this);
508 slide
.style
.visibility
= 'hidden';
510 cw
.onAfterConfirm = function() {
511 slide
.style
.visibility
= 'hidden';
519 case 'edit_metadata' :
521 disablePropagation(evt);
523 if (this.viewMode === 'full') {
524 this.mosaique.unload();
525 this.mosaique = null;
526 this.viewMode = 'medium';
529 var fi = new FragmentImporter(absolute_url());
530 fi.useMacro('metadata_edit_form_macros', 'iptc', 'image_metadata');
538 if(browser
.isDOM2Event
) {
539 if (browser
.isAppleWebKit
) {
540 FilmSlider
.prototype.mouseWheelHandler = function(evt
) {
542 var pos
= this.getSliderPosition();
543 pos
.x
-= evt
.wheelDelta
/ 40;
544 this.setSliderPosition(pos
);
548 FilmSlider
.prototype.mouseWheelHandler = function(evt
) {
550 var pos
= this.getSliderPosition();
551 pos
.x
+= evt
.detail
* 3;
552 this.setSliderPosition(pos
);
556 else if (browser
.isIE6up
) {
557 FilmSlider
.prototype.mouseWheelHandler = function() {
558 var evt
= window
.event
;
559 evt
.returnValue
= false;
560 var pos
= this.getSliderPosition();
561 pos
.x
-= evt
.wheelDelta
/ 40;
562 this.setSliderPosition(pos
);
566 FilmSlider
.prototype.keyDownHandler = function(evt
) {
567 evt
= getEventObject(evt
);
568 switch (evt
.keyCode
) {
570 this.loadSibling(true);
573 this.loadSibling(false);
581 FilmSlider
.prototype.keyPressHandler = function(evt
) {
582 var target
= getTargetedObject(evt
);
583 if (target
.tagName
=== 'INPUT' || target
.tagName
=== 'TEXTAREA') { return; }
584 evt
= getEventObject(evt
);
585 var charPress
= String
.fromCharCode((evt
.keyCode
) ? evt
.keyCode
: evt
.which
);
589 raiseMouseEvent(this.buttons
.full_screen
, 'click');
594 FilmSlider
.prototype.populateViewer = function(req
) {
595 var elements
= req
.responseXML
.documentElement
.childNodes
;
597 for(i
=0 ; i
< elements
.length
; i
++ ) {
598 element
= elements
[i
];
599 switch (element
.nodeName
) {
601 var dest
= document
.getElementById(element
.getAttribute('id'));
602 if (dest
) { dest
.innerHTML
= element
.firstChild
.nodeValue
; }
604 case 'imageattributes' :
605 var link
= this.buttons
.back_to_portfolio
.parentNode
;
606 link
.href
= element
.getAttribute('backToContextUrl');
607 link
= this.buttons
.show_buyable
.parentNode
;
608 var buyable
= element
.getAttribute('buyable');
609 if(buyable
=== 'True') { link
.className
= null; }
610 else if(buyable
=== 'False') { link
.className
= 'hidden'; }
611 this.image
.alt
= element
.getAttribute('alt');
612 this.updateBreadcrumbs(element
.getAttribute('lastBcUrl'),
613 element
.getAttribute('img_id'));
619 FilmSlider
.prototype.refreshImage = function() {
620 this.image
.style
.visibility
= 'hidden';
621 this.image
.src
= this.pendingImage
.src
;
622 this.image
.width
= this.pendingImage
.width
;
623 this.image
.height
= this.pendingImage
.height
;
624 this.image
.style
.visibility
= 'visible';
625 if (this.selectedSlideInSelection
) { this.image
.parentNode
.className
= 'selected'; }
626 else { this.image
.parentNode
.className
= ''; }
629 FilmSlider
.prototype.updateBreadcrumbs = function(url
, title
) {
630 if (this.hasBreadcrumbs
) {
631 this.lastBCElement
.href
= element
.getAttribute('lastBcUrl');
632 this.lastBCElement
.innerHTML
= element
.getAttribute('img_id');
636 FilmSlider
.prototype.startSlideShow = function() {
637 this.slideShowSlide
= this.pendingSlideShowSlide
= this.selectedSlide
;
638 return this.slideShowSlide
.href
;
641 FilmSlider
.prototype.slideShowNext = function() {
642 var nextSlide
= this.slideShowSlide
.parentNode
.nextSibling
;
643 if (nextSlide
&& nextSlide
.nodeType
===3) { nextSlide
= nextSlide
.nextSibling
; }
646 nextSlide
= nextSlide
.getElementsByTagName('a')[0];
647 this.pendingSlideShowSlide
= nextSlide
;
648 return this.pendingSlideShowSlide
.href
;
651 var row
= this.slideShowSlide
.parentNode
.parentNode
;
652 var first
= row
.firstChild
;
653 if (first
.nodeType
===3) { first
= first
.nextSibling
; }
654 this.pendingSlideShowSlide
= first
.getElementsByTagName('a')[0];
655 return this.pendingSlideShowSlide
.href
;
659 FilmSlider
.prototype.slideShowPrevious = function() {
660 var previousSlide
= this.slideShowSlide
.parentNode
.previousSibling
;
661 if (previousSlide
&& previousSlide
.nodeType
===3) { previousSlide
= previousSlide
.previousSibling
; }
664 previousSlide
= previousSlide
.getElementsByTagName('a')[0];
665 this.pendingSlideShowSlide
= previousSlide
;
666 return this.pendingSlideShowSlide
.href
;
669 var row
= this.slideShowSlide
.parentNode
.parentNode
;
670 var last
= row
.lastChild
;
671 if (last
.nodeType
===3) { last
= last
.previousSibling
; }
672 this.pendingSlideShowSlide
= last
.getElementsByTagName('a')[0];
673 return this.pendingSlideShowSlide
.href
;
677 FilmSlider
.prototype.slideShowImageLoaded = function() {
678 this.slideShowSlide
= this.pendingSlideShowSlide
;
681 FilmSlider
.prototype.stopSlideShow = function() {
682 raiseMouseEvent(this.slideShowSlide
, 'click');
683 var index
= parseInt(this.selectedSlide
.getAttribute('portfolio:position'), 10);
684 this.centerSlide(index
);
689 function Point(x
, y
) {
690 this.x
= Math
.round(x
);
691 this.y
= Math
.round(y
);
693 Point
.prototype.diff = function(point
) { return new Point(this.x
- point
.x
, this.y
- point
.y
); };
694 Point
.prototype.add = function(point
) { return new Point(this.x
+ point
.x
, this.y
+ point
.y
); };
695 Point
.prototype.mul = function(k
) { return new Point(this.x
* k
, this.y
*k
); };
696 Point
.prototype.toString = function() { return "(" + String(this.x
) + ", " + String(this.y
) + ")"; };