Initial commit
@@ -0,0 +1,2 @@
|
||||
/data/today/ export-ignore
|
||||
/data/geo/ export-ignore
|
||||
@@ -0,0 +1,5 @@
|
||||
images/picto_*
|
||||
GTFS/
|
||||
data/
|
||||
downloads/
|
||||
|
||||
@@ -0,0 +1,675 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
@@ -0,0 +1,675 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Où est mon bus ? OpenStreetMap et OpenData #
|
||||
|
||||
Où est mon bus ? est une carte interactive en ligne basée sur OpenStreetMap et les données OpenData de Rennes Métropole.
|
||||
|
||||
L'application indique les arrêts de bus en temps réel.
|
||||
|
||||
En cliquant sur les arrêts de bus, les prochains passages des lignes sont affichés en direct en précisant un éventuel retard ou avance.
|
||||
|
||||
La position des bus est indiquée sur la carte avec un rafraîchissement automatique toutes les minutes.
|
||||
Caractéristiques principales :
|
||||
|
||||
* arrêts de bus affichés aux arrêts en temps réel, si un bus est prévu dans la journée.
|
||||
* affichage des deux prochains passages de bus en temps réel sur les arrêts.
|
||||
* affichage de la position des bus sur la carte.
|
||||
* géolocalisation automatique ou avec saisie d'un lieu référencé sur OpenStreetMap (avec auto-complétion).
|
||||
* informations @STARendirect en temps réel.
|
||||
* consultation des fiches horaires officielles via les icônes des lignes.
|
||||
|
||||
Où est mon bus ? est une application simple et rapide pour ne plus rater son bus !
|
||||
|
||||
Elle peut être utilisée sans installation, simplement en se rendant sur le site ouestmonbus.com depuis un ordinateur, un smartphone ou une tablette.
|
||||
|
||||
## Crédits
|
||||
|
||||
ouestmonbus.com est développé par Benoît Meunier avec la participation de Karin Meunier (direction graphisme et expérience utilisateur).
|
||||
Ce service est proposé gratuitement sans garantie de fonctionnement.
|
||||
|
||||
Il est construit à l'aide des librairies Leaflet, Metro UI CSS, jQuery, mobile-detect.js, underscore.js et Moment.js.
|
||||
Les données de carte proviennent des contributeurs de OpenStreetMap, et les informations sur le service de Rennes Métropole et Keolis Rennes.
|
||||
Le service Photon.io est utilisé pour la localisation.
|
||||
|
||||
ouestmonbus.com est un logiciel libre sous licence GPL v3.
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/mstile-70x70.png"/>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<square310x310logo src="/mstile-310x310.png"/>
|
||||
<wide310x150logo src="/mstile-310x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
@@ -0,0 +1,60 @@
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(181, 226, 140, 0.6);
|
||||
}
|
||||
.marker-cluster-small div {
|
||||
background-color: rgba(110, 204, 57, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-medium {
|
||||
background-color: rgba(241, 211, 87, 0.6);
|
||||
}
|
||||
.marker-cluster-medium div {
|
||||
background-color: rgba(240, 194, 12, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-large {
|
||||
background-color: rgba(253, 156, 115, 0.6);
|
||||
}
|
||||
.marker-cluster-large div {
|
||||
background-color: rgba(241, 128, 23, 0.6);
|
||||
}
|
||||
|
||||
/* IE 6-8 fallback colors */
|
||||
.leaflet-oldie .marker-cluster-small {
|
||||
background-color: rgb(181, 226, 140);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-small div {
|
||||
background-color: rgb(110, 204, 57);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-medium {
|
||||
background-color: rgb(241, 211, 87);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-medium div {
|
||||
background-color: rgb(240, 194, 12);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-large {
|
||||
background-color: rgb(253, 156, 115);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-large div {
|
||||
background-color: rgb(241, 128, 23);
|
||||
}
|
||||
|
||||
.marker-cluster {
|
||||
background-clip: padding-box;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.marker-cluster div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.marker-cluster span {
|
||||
line-height: 30px;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
|
||||
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
}
|
||||
|
||||
.leaflet-cluster-spider-leg {
|
||||
/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
|
||||
-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
|
||||
-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
|
||||
transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 696 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 618 B |
@@ -0,0 +1,640 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg,
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile {
|
||||
will-change: opacity;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path {
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
ul.photon-autocomplete {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 9px #999999;
|
||||
display: none;
|
||||
}
|
||||
.photon-autocomplete li {
|
||||
min-height: 40px;
|
||||
line-height: 1em;
|
||||
padding: 5px 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 1em;
|
||||
}
|
||||
.photon-autocomplete li strong {
|
||||
display: block;
|
||||
}
|
||||
.photon-autocomplete li.on {
|
||||
background-color: #2980b9;
|
||||
cursor: pointer;
|
||||
}
|
||||
.photon-autocomplete li.photon-no-result {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
line-height: 40px;
|
||||
}
|
||||
.photon-autocomplete .photon-feedback {
|
||||
display: block;
|
||||
text-align: right;
|
||||
font-size: 0.8em;
|
||||
padding: 3px;
|
||||
color: #999;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.photon-input:focus {
|
||||
width: 400px;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
|
||||
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(181, 226, 140, 0.6);
|
||||
}
|
||||
.marker-cluster-small div {
|
||||
background-color: rgba(110, 204, 57, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-medium {
|
||||
background-color: rgba(241, 211, 87, 0.6);
|
||||
}
|
||||
.marker-cluster-medium div {
|
||||
background-color: rgba(240, 194, 12, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-large {
|
||||
background-color: rgba(253, 156, 115, 0.6);
|
||||
}
|
||||
.marker-cluster-large div {
|
||||
background-color: rgba(241, 128, 23, 0.6);
|
||||
}
|
||||
|
||||
/* IE 6-8 fallback colors */
|
||||
.leaflet-oldie .marker-cluster-small {
|
||||
background-color: rgb(181, 226, 140);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-small div {
|
||||
background-color: rgb(110, 204, 57);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-medium {
|
||||
background-color: rgb(241, 211, 87);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-medium div {
|
||||
background-color: rgb(240, 194, 12);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-large {
|
||||
background-color: rgb(253, 156, 115);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-large div {
|
||||
background-color: rgb(241, 128, 23);
|
||||
}
|
||||
|
||||
.marker-cluster {
|
||||
background-clip: padding-box;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.marker-cluster div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.marker-cluster span {
|
||||
line-height: 30px;
|
||||
}
|
||||
@@ -0,0 +1,715 @@
|
||||
.flexbox {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
.flex-dir-row {
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
}
|
||||
.flex-dir-row-reverse {
|
||||
-webkit-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.flex-dir-column {
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-dir-column-reverse {
|
||||
-webkit-flex-direction: column-reverse;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
.flex-wrap {
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.flex-wrap-reverse {
|
||||
-webkit-flex-wrap: wrap-reverse;
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
.flex-no-wrap {
|
||||
-webkit-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.flex-just-start {
|
||||
-webkit-justify-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.flex-just-end {
|
||||
-webkit-justify-content: flex-end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.flex-just-center {
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.flex-just-sa {
|
||||
-webkit-justify-content: space-around;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.flex-just-sb {
|
||||
-webkit-justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.flex-align-stretch {
|
||||
-webkit-align-items: stretch;
|
||||
align-items: stretch;
|
||||
}
|
||||
.flex-align-start {
|
||||
-webkit-align-items: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.flex-align-end {
|
||||
-webkit-align-items: flex-end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.flex-align-center {
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
.flex-align-base {
|
||||
-webkit-align-items: baseline;
|
||||
align-items: baseline;
|
||||
}
|
||||
.flex-content-stretch {
|
||||
-webkit-align-content: stretch;
|
||||
align-content: stretch;
|
||||
}
|
||||
.flex-content-start {
|
||||
-webkit-align-content: flex-start;
|
||||
align-content: flex-start;
|
||||
}
|
||||
.flex-content-end {
|
||||
-webkit-align-content: flex-end;
|
||||
align-content: flex-end;
|
||||
}
|
||||
.flex-content-center {
|
||||
-webkit-align-content: center;
|
||||
align-content: center;
|
||||
}
|
||||
.flex-content-sb {
|
||||
-webkit-align-content: space-between;
|
||||
align-content: space-between;
|
||||
}
|
||||
.flex-content-sa {
|
||||
-webkit-align-content: space-around;
|
||||
align-content: space-around;
|
||||
}
|
||||
.flex-self-auto {
|
||||
-webkit-align-self: auto;
|
||||
align-self: auto;
|
||||
}
|
||||
.flex-self-start {
|
||||
-webkit-align-self: flex-start;
|
||||
align-self: flex-start;
|
||||
}
|
||||
.flex-self-end {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end;
|
||||
}
|
||||
.flex-self-center {
|
||||
-webkit-align-self: center;
|
||||
align-self: center;
|
||||
}
|
||||
.flex-self-base {
|
||||
-webkit-align-self: baseline;
|
||||
align-self: baseline;
|
||||
}
|
||||
.flex-self-stretch {
|
||||
-webkit-align-self: stretch;
|
||||
align-self: stretch;
|
||||
}
|
||||
.no-shrink {
|
||||
-webkit-flex-shrink: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
.no-grow {
|
||||
-webkit-flex-grow: 0 !important;
|
||||
flex-grow: 0 !important;
|
||||
}
|
||||
.flex-size-auto {
|
||||
-webkit-flex: 1 auto;
|
||||
flex: 1 auto;
|
||||
}
|
||||
.flex-size1 {
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.flex-size2 {
|
||||
-webkit-flex-grow: 2;
|
||||
flex-grow: 2;
|
||||
}
|
||||
.flex-size3 {
|
||||
-webkit-flex-grow: 3;
|
||||
flex-grow: 3;
|
||||
}
|
||||
.flex-size4 {
|
||||
-webkit-flex-grow: 4;
|
||||
flex-grow: 4;
|
||||
}
|
||||
.flex-size5 {
|
||||
-webkit-flex-grow: 5;
|
||||
flex-grow: 5;
|
||||
}
|
||||
.flex-size6 {
|
||||
-webkit-flex-grow: 6;
|
||||
flex-grow: 6;
|
||||
}
|
||||
.flex-size7 {
|
||||
-webkit-flex-grow: 7;
|
||||
flex-grow: 7;
|
||||
}
|
||||
.flex-size8 {
|
||||
-webkit-flex-grow: 8;
|
||||
flex-grow: 8;
|
||||
}
|
||||
.flex-size9 {
|
||||
-webkit-flex-grow: 9;
|
||||
flex-grow: 9;
|
||||
}
|
||||
.flex-size10 {
|
||||
-webkit-flex-grow: 10;
|
||||
flex-grow: 10;
|
||||
}
|
||||
.flex-size11 {
|
||||
-webkit-flex-grow: 11;
|
||||
flex-grow: 11;
|
||||
}
|
||||
.flex-size12 {
|
||||
-webkit-flex-grow: 12;
|
||||
flex-grow: 12;
|
||||
}
|
||||
.flex-size-p10 {
|
||||
-webkit-flex: 0 0 10%;
|
||||
flex: 0 0 10%;
|
||||
}
|
||||
.flex-size-p20 {
|
||||
-webkit-flex: 0 0 20%;
|
||||
flex: 0 0 20%;
|
||||
}
|
||||
.flex-size-p30 {
|
||||
-webkit-flex: 0 0 30%;
|
||||
flex: 0 0 30%;
|
||||
}
|
||||
.flex-size-p40 {
|
||||
-webkit-flex: 0 0 40%;
|
||||
flex: 0 0 40%;
|
||||
}
|
||||
.flex-size-p50 {
|
||||
-webkit-flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
.flex-size-p60 {
|
||||
-webkit-flex: 0 0 60%;
|
||||
flex: 0 0 60%;
|
||||
}
|
||||
.flex-size-p70 {
|
||||
-webkit-flex: 0 0 70%;
|
||||
flex: 0 0 70%;
|
||||
}
|
||||
.flex-size-p80 {
|
||||
-webkit-flex: 0 0 80%;
|
||||
flex: 0 0 80%;
|
||||
}
|
||||
.flex-size-p90 {
|
||||
-webkit-flex: 0 0 90%;
|
||||
flex: 0 0 90%;
|
||||
}
|
||||
.flex-size-p100 {
|
||||
-webkit-flex: 0 0 100%;
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
.flex-size-x100 {
|
||||
-webkit-flex: 0 0 100px;
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
.flex-size-x200 {
|
||||
-webkit-flex: 0 0 200px;
|
||||
flex: 0 0 200px;
|
||||
}
|
||||
.flex-size-x300 {
|
||||
-webkit-flex: 0 0 300px;
|
||||
flex: 0 0 300px;
|
||||
}
|
||||
.flex-size-x400 {
|
||||
-webkit-flex: 0 0 400px;
|
||||
flex: 0 0 400px;
|
||||
}
|
||||
.flex-size-x500 {
|
||||
-webkit-flex: 0 0 500px;
|
||||
flex: 0 0 500px;
|
||||
}
|
||||
.flex-size-x600 {
|
||||
-webkit-flex: 0 0 600px;
|
||||
flex: 0 0 600px;
|
||||
}
|
||||
.flex-size-x700 {
|
||||
-webkit-flex: 0 0 700px;
|
||||
flex: 0 0 700px;
|
||||
}
|
||||
.flex-size-x800 {
|
||||
-webkit-flex: 0 0 800px;
|
||||
flex: 0 0 800px;
|
||||
}
|
||||
.flex-size-x900 {
|
||||
-webkit-flex: 0 0 900px;
|
||||
flex: 0 0 900px;
|
||||
}
|
||||
.flex-size-x1000 {
|
||||
-webkit-flex: 0 0 1000px;
|
||||
flex: 0 0 1000px;
|
||||
}
|
||||
@media screen and (min-width: 1401px) {
|
||||
html {
|
||||
font-size: 120%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1400px) {
|
||||
html {
|
||||
font-size: 110%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1200px) {
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
html {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 320px) {
|
||||
html {
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p {
|
||||
margin: .625rem;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1401px) {
|
||||
.container {
|
||||
width: 1200px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 992px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 320px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 800px) {
|
||||
.flex-grid .row {
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.flex-grid .row .cell,
|
||||
.flex-grid .row .cell[class*=size] {
|
||||
-webkit-flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
.flex-grid .row .cell:nth-child(1):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(1):last-child,
|
||||
.flex-grid .row .cell:nth-child(3):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(3):last-child,
|
||||
.flex-grid .row .cell:nth-child(5):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(5):last-child,
|
||||
.flex-grid .row .cell:nth-child(7):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(7):last-child,
|
||||
.flex-grid .row .cell:nth-child(9):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(9):last-child,
|
||||
.flex-grid .row .cell:nth-child(11):last-child,
|
||||
.flex-grid .row .cell[class*=size]:nth-child(11):last-child {
|
||||
-webkit-flex-basis: 100%;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
.flex-grid .row {
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid .row,
|
||||
.grid .row[class*=cells] {
|
||||
margin: 0;
|
||||
}
|
||||
.grid .row > .cell,
|
||||
.grid .row[class*=cells] > .cell,
|
||||
.grid .row > .cell[class*=colspan],
|
||||
.grid .row[class*=cells] > .cell[class*=colspan] {
|
||||
width: 48.936175% ;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.grid .row > .cell:nth-child(odd),
|
||||
.grid .row[class*=cells] > .cell:nth-child(odd),
|
||||
.grid .row > .cell[class*=colspan]:nth-child(odd),
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(odd) {
|
||||
margin-left: 0;
|
||||
}
|
||||
.grid .row > .cell:nth-child(1):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(1):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(1):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(1):last-child,
|
||||
.grid .row > .cell:nth-child(3):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(3):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(3):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(3):last-child,
|
||||
.grid .row > .cell:nth-child(5):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(5):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(5):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(5):last-child,
|
||||
.grid .row > .cell:nth-child(7):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(7):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(7):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(7):last-child,
|
||||
.grid .row > .cell:nth-child(9):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(9):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(9):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(9):last-child,
|
||||
.grid .row > .cell:nth-child(11):last-child,
|
||||
.grid .row[class*=cells] > .cell:nth-child(11):last-child,
|
||||
.grid .row > .cell[class*=colspan]:nth-child(11):last-child,
|
||||
.grid .row[class*=cells] > .cell[class*=colspan]:nth-child(11):last-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.grid .row,
|
||||
.grid .row[class*=cells] {
|
||||
margin: 0;
|
||||
}
|
||||
.grid .row > .cell,
|
||||
.grid .row[class*=cells] > .cell,
|
||||
.grid .row > .cell[class*=colspan],
|
||||
.grid .row[class*=cells] > .cell[class*=colspan] {
|
||||
width: 100%;
|
||||
margin: .3125rem 0;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid.condensed .row,
|
||||
.grid.condensed .row[class*=cells] {
|
||||
margin: 0;
|
||||
}
|
||||
.grid.condensed .row > .cell,
|
||||
.grid.condensed .row[class*=cells] > .cell,
|
||||
.grid.condensed .row > .cell[class*=colspan],
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan] {
|
||||
width: 50% ;
|
||||
margin-bottom: 10px ;
|
||||
}
|
||||
.grid.condensed .row > .cell:nth-child(odd),
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(odd),
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(odd),
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(odd) {
|
||||
margin-left: 0;
|
||||
}
|
||||
.grid.condensed .row > .cell:nth-child(1):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(1):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(1):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(1):last-child,
|
||||
.grid.condensed .row > .cell:nth-child(3):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(3):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(3):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(3):last-child,
|
||||
.grid.condensed .row > .cell:nth-child(5):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(5):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(5):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(5):last-child,
|
||||
.grid.condensed .row > .cell:nth-child(7):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(7):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(7):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(7):last-child,
|
||||
.grid.condensed .row > .cell:nth-child(9):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(9):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(9):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(9):last-child,
|
||||
.grid.condensed .row > .cell:nth-child(11):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell:nth-child(11):last-child,
|
||||
.grid.condensed .row > .cell[class*=colspan]:nth-child(11):last-child,
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan]:nth-child(11):last-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
.grid.condensed .row,
|
||||
.grid.condensed .row[class*=cells] {
|
||||
margin: 0;
|
||||
}
|
||||
.grid.condensed .row > .cell,
|
||||
.grid.condensed .row[class*=cells] > .cell,
|
||||
.grid.condensed .row > .cell[class*=colspan],
|
||||
.grid.condensed .row[class*=cells] > .cell[class*=colspan] {
|
||||
width: 100%;
|
||||
margin: .3125rem 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
.f-menu {
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
.f-menu > li .d-menu {
|
||||
position: relative;
|
||||
box-shadow: none;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.sidebar {
|
||||
width: 52px;
|
||||
}
|
||||
.sidebar li > a {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
width: 52px !important;
|
||||
}
|
||||
.sidebar li > a > .title {
|
||||
display: none ;
|
||||
}
|
||||
.sidebar li > a > .counter {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 4px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 320px) {
|
||||
.wizard2 .step:before {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.small-tile {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.wide-tile {
|
||||
width: 248px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.wide-tile-v {
|
||||
width: 120px;
|
||||
height: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.large-tile {
|
||||
width: 248px;
|
||||
height: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.big-tile {
|
||||
width: 376px;
|
||||
height: 376px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile.super-tile {
|
||||
width: 504px;
|
||||
height: 504px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-square {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-small {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-wide {
|
||||
width: 248px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-large {
|
||||
width: 248px;
|
||||
height: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-big {
|
||||
width: 376px;
|
||||
height: 376px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-super {
|
||||
width: 504px;
|
||||
height: 504px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-small-x {
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-square-x {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-wide-x {
|
||||
width: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-large-x {
|
||||
width: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-big-x {
|
||||
width: 376px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-super-x {
|
||||
width: 504px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-small-y {
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-square-y {
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-wide-y {
|
||||
height: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-large-y {
|
||||
height: 248px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-big-y {
|
||||
height: 376px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-super-y {
|
||||
height: 504px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-content.iconic .icon {
|
||||
width: 51.2px;
|
||||
height: 51.2px;
|
||||
margin-left: -25.6px;
|
||||
margin-top: -32px;
|
||||
font-size: 51.2px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.tile-small .tile-content.iconic .icon {
|
||||
font-size: 25.6px;
|
||||
width: 25.6px;
|
||||
height: 25.6px;
|
||||
margin-left: -12.8px;
|
||||
margin-top: -12.8px;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.tile-area {
|
||||
width: 100% ;
|
||||
padding: 0;
|
||||
}
|
||||
.tile-area .tile-area-title {
|
||||
display: none;
|
||||
}
|
||||
.tile-area .tile-group {
|
||||
margin: 0 ;
|
||||
padding: 0 ;
|
||||
float: none;
|
||||
}
|
||||
.tile-area .tile-group .tile-group-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.tile-container {
|
||||
width: 100% ;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 320px) {
|
||||
.tile-big,
|
||||
.tile.big-tile,
|
||||
.tile-super,
|
||||
.tile.super-tile {
|
||||
width: 310px ;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 640px) {
|
||||
.no-phone {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.no-tablet {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 900px) {
|
||||
.no-pc {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
*[dir=ltr] {
|
||||
direction: ltr;
|
||||
unicode-bidi: embed;
|
||||
}
|
||||
*[dir=rtl] {
|
||||
direction: rtl;
|
||||
unicode-bidi: embed;
|
||||
}
|
||||
bdo[dir=ltr] {
|
||||
direction: ltr;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
bdo[dir=rtl] {
|
||||
direction: rtl;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
*[dir=rtl] ul,
|
||||
*[dir=rtl] ol,
|
||||
ul[dir=rtl],
|
||||
ol[dir=rtl] {
|
||||
margin-right: .3125rem;
|
||||
margin-left: 0;
|
||||
padding-right: .625rem;
|
||||
}
|
||||
*[dir=rtl] ul li ul,
|
||||
*[dir=rtl] ol li ul,
|
||||
ul[dir=rtl] li ul,
|
||||
ol[dir=rtl] li ul,
|
||||
*[dir=rtl] ul li ol,
|
||||
*[dir=rtl] ol li ol,
|
||||
ul[dir=rtl] li ol,
|
||||
ol[dir=rtl] li ol {
|
||||
padding-right: 1.5625rem;
|
||||
padding-left: 0;
|
||||
}
|
||||
*[dir=rtl] dl dd,
|
||||
dl[dir=rtl] dd {
|
||||
margin-right: .9375rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
*[dir=rtl] dl.horizontal dt,
|
||||
dl[dir=rtl].horizontal dt {
|
||||
float: right;
|
||||
width: 10rem;
|
||||
overflow: hidden;
|
||||
clear: left;
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
*[dir=rtl] dl.horizontal dd,
|
||||
dl[dir=rtl].horizontal dd {
|
||||
margin-right: 11.25rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
*[dir=rtl] blockquote,
|
||||
blockquote[dir=rtl] {
|
||||
margin: .625rem 0;
|
||||
padding: 0 .625rem 0 0;
|
||||
border-left: none;
|
||||
border-right: 0.25rem #999999 solid;
|
||||
}
|
||||
*[dir=rtl] .input-control.text .button,
|
||||
.input-control[dir=rtl].text .button,
|
||||
*[dir=rtl] .input-control.select .button,
|
||||
.input-control[dir=rtl].select .button,
|
||||
*[dir=rtl] .input-control.file .button,
|
||||
.input-control[dir=rtl].file .button,
|
||||
*[dir=rtl] .input-control.password .button,
|
||||
.input-control[dir=rtl].password .button,
|
||||
*[dir=rtl] .input-control.number .button,
|
||||
.input-control[dir=rtl].number .button,
|
||||
*[dir=rtl] .input-control.email .button,
|
||||
.input-control[dir=rtl].email .button,
|
||||
*[dir=rtl] .input-control.tel .button,
|
||||
.input-control[dir=rtl].tel .button,
|
||||
*[dir=rtl] .input-control.text .button-group,
|
||||
.input-control[dir=rtl].text .button-group,
|
||||
*[dir=rtl] .input-control.select .button-group,
|
||||
.input-control[dir=rtl].select .button-group,
|
||||
*[dir=rtl] .input-control.file .button-group,
|
||||
.input-control[dir=rtl].file .button-group,
|
||||
*[dir=rtl] .input-control.password .button-group,
|
||||
.input-control[dir=rtl].password .button-group,
|
||||
*[dir=rtl] .input-control.number .button-group,
|
||||
.input-control[dir=rtl].number .button-group,
|
||||
*[dir=rtl] .input-control.email .button-group,
|
||||
.input-control[dir=rtl].email .button-group,
|
||||
*[dir=rtl] .input-control.tel .button-group,
|
||||
.input-control[dir=rtl].tel .button-group {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
*[dir=rtl] .input-control.text .prepend-icon,
|
||||
.input-control[dir=rtl].text .prepend-icon,
|
||||
*[dir=rtl] .input-control.select .prepend-icon,
|
||||
.input-control[dir=rtl].select .prepend-icon,
|
||||
*[dir=rtl] .input-control.file .prepend-icon,
|
||||
.input-control[dir=rtl].file .prepend-icon,
|
||||
*[dir=rtl] .input-control.password .prepend-icon,
|
||||
.input-control[dir=rtl].password .prepend-icon,
|
||||
*[dir=rtl] .input-control.number .prepend-icon,
|
||||
.input-control[dir=rtl].number .prepend-icon,
|
||||
*[dir=rtl] .input-control.email .prepend-icon,
|
||||
.input-control[dir=rtl].email .prepend-icon,
|
||||
*[dir=rtl] .input-control.tel .prepend-icon,
|
||||
.input-control[dir=rtl].tel .prepend-icon {
|
||||
left: auto;
|
||||
right: 4px;
|
||||
}
|
||||
*[dir=rtl] .input-control.text .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].text .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.select .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].select .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.file .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].file .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.password .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].password .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.number .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].number .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.email .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].email .prepend-icon ~ input,
|
||||
*[dir=rtl] .input-control.tel .prepend-icon ~ input,
|
||||
.input-control[dir=rtl].tel .prepend-icon ~ input {
|
||||
padding-left: 0;
|
||||
padding-right: 30px;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[dir=ltr]{direction:ltr;unicode-bidi:embed}[dir=rtl]{direction:rtl;unicode-bidi:embed}bdo[dir=ltr]{direction:ltr;unicode-bidi:bidi-override}bdo[dir=rtl]{direction:rtl;unicode-bidi:bidi-override}[dir=rtl] ol,[dir=rtl] ul,ol[dir=rtl],ul[dir=rtl]{margin-right:.3125rem;margin-left:0;padding-right:.625rem}[dir=rtl] ol li ol,[dir=rtl] ol li ul,[dir=rtl] ul li ol,[dir=rtl] ul li ul,ol[dir=rtl] li ol,ol[dir=rtl] li ul,ul[dir=rtl] li ol,ul[dir=rtl] li ul{padding-right:1.5625rem;padding-left:0}[dir=rtl] dl dd,dl[dir=rtl] dd{margin-right:.9375rem;margin-left:0}[dir=rtl] dl.horizontal dt,dl[dir=rtl].horizontal dt{float:right;width:10rem;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}[dir=rtl] dl.horizontal dd,dl[dir=rtl].horizontal dd{margin-right:11.25rem;margin-left:0}[dir=rtl] blockquote,blockquote[dir=rtl]{margin:.625rem 0;padding:0 .625rem 0 0;border-left:none;border-right:.25rem #999 solid}.input-control[dir=rtl].email .button,.input-control[dir=rtl].email .button-group,.input-control[dir=rtl].file .button,.input-control[dir=rtl].file .button-group,.input-control[dir=rtl].number .button,.input-control[dir=rtl].number .button-group,.input-control[dir=rtl].password .button,.input-control[dir=rtl].password .button-group,.input-control[dir=rtl].select .button,.input-control[dir=rtl].select .button-group,.input-control[dir=rtl].tel .button,.input-control[dir=rtl].tel .button-group,.input-control[dir=rtl].text .button,.input-control[dir=rtl].text .button-group,[dir=rtl] .input-control.email .button,[dir=rtl] .input-control.email .button-group,[dir=rtl] .input-control.file .button,[dir=rtl] .input-control.file .button-group,[dir=rtl] .input-control.number .button,[dir=rtl] .input-control.number .button-group,[dir=rtl] .input-control.password .button,[dir=rtl] .input-control.password .button-group,[dir=rtl] .input-control.select .button,[dir=rtl] .input-control.select .button-group,[dir=rtl] .input-control.tel .button,[dir=rtl] .input-control.tel .button-group,[dir=rtl] .input-control.text .button,[dir=rtl] .input-control.text .button-group{right:auto;left:0}.input-control[dir=rtl].email .prepend-icon,.input-control[dir=rtl].file .prepend-icon,.input-control[dir=rtl].number .prepend-icon,.input-control[dir=rtl].password .prepend-icon,.input-control[dir=rtl].select .prepend-icon,.input-control[dir=rtl].tel .prepend-icon,.input-control[dir=rtl].text .prepend-icon,[dir=rtl] .input-control.email .prepend-icon,[dir=rtl] .input-control.file .prepend-icon,[dir=rtl] .input-control.number .prepend-icon,[dir=rtl] .input-control.password .prepend-icon,[dir=rtl] .input-control.select .prepend-icon,[dir=rtl] .input-control.tel .prepend-icon,[dir=rtl] .input-control.text .prepend-icon{left:auto;right:4px}.input-control[dir=rtl].email .prepend-icon~input,.input-control[dir=rtl].file .prepend-icon~input,.input-control[dir=rtl].number .prepend-icon~input,.input-control[dir=rtl].password .prepend-icon~input,.input-control[dir=rtl].select .prepend-icon~input,.input-control[dir=rtl].tel .prepend-icon~input,.input-control[dir=rtl].text .prepend-icon~input,[dir=rtl] .input-control.email .prepend-icon~input,[dir=rtl] .input-control.file .prepend-icon~input,[dir=rtl] .input-control.number .prepend-icon~input,[dir=rtl] .input-control.password .prepend-icon~input,[dir=rtl] .input-control.select .prepend-icon~input,[dir=rtl] .input-control.tel .prepend-icon~input,[dir=rtl] .input-control.text .prepend-icon~input{padding-left:0;padding-right:30px}[dir=rtl] .grid .row>.cell{float:right}
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 423 KiB |
@@ -0,0 +1,441 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import coloredlogs
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
import zipfile
|
||||
import datetime
|
||||
import dateutil.parser
|
||||
import csv
|
||||
import shutil
|
||||
import glob
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
if not sys.version_info >= (3, 8):
|
||||
print("Python >= 3.8 is required")
|
||||
exit(1)
|
||||
|
||||
URL_API_GTFS = "https://data.explore.star.fr/api/records/1.0/search?apikey=3324de385f6b7b5bdfa1727d3e1a9f4bed5dd1accb288db6df5e8487&dataset=tco-busmetro-horaires-gtfs-versions-td&q=&sort=-debutvalidite"
|
||||
URL_API_PICTO_BUS = "https://data.explore.star.fr/api/records/1.0/search/?apikey=3324de385f6b7b5bdfa1727d3e1a9f4bed5dd1accb288db6df5e8487&dataset=tco-bus-lignes-pictogrammes-dm&q=&rows=200&sort=idligne&refine.resolution=1%3A22"
|
||||
URL_API_PICTO_METRO = "https://data.explore.star.fr/api/records/1.0/search/?apikey=3324de385f6b7b5bdfa1727d3e1a9f4bed5dd1accb288db6df5e8487&dataset=tco-metro-lignes-pictogrammes-dm&q=&rows=200&sort=idligne&refine.resolution=1%3A22"
|
||||
URL_PICTO_PREFIX_BUS = (
|
||||
"https://data.explore.star.fr/explore/dataset/tco-bus-lignes-pictogrammes-dm/files/"
|
||||
)
|
||||
URL_PICTO_PREFIX_METRO = "https://data.explore.star.fr/explore/dataset/tco-metro-lignes-pictogrammes-dm/files/"
|
||||
|
||||
|
||||
class Station(object):
|
||||
"""
|
||||
Classe qui représente une station.
|
||||
Utilisé pour transformer un object en json
|
||||
"""
|
||||
|
||||
def __init__(self, sid, name=None, lon=None, lat=None):
|
||||
self.lat = lat
|
||||
self.lon = lon
|
||||
self.sid = sid
|
||||
self.name = name
|
||||
self.terminus = None
|
||||
self.limits = None
|
||||
self.lines = None
|
||||
self.parcours = None
|
||||
|
||||
def __str__(self):
|
||||
o = {}
|
||||
o["type"] = "Feature"
|
||||
o["geometry"] = {}
|
||||
o["geometry"]["type"] = "Point"
|
||||
o["geometry"]["coordinates"] = [self.lon, self.lat]
|
||||
o["properties"] = {}
|
||||
o["properties"]["id"] = self.sid
|
||||
o["properties"]["name"] = self.name
|
||||
o["properties"]["terminus"] = list(self.terminus)
|
||||
o["properties"]["limits"] = self.limits
|
||||
o["properties"]["lines"] = list(self.lines)
|
||||
o["properties"]["parcours"] = list(self.parcours)
|
||||
return json.dumps(o)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
def get_gtfs_dir(today):
|
||||
"""
|
||||
Récupère le repertoire GTFS le plus récent (en fonction de la publication)
|
||||
qui correspond à la date passé en paramètre.
|
||||
Si il n'y a pas de de données GTFS disponible retourne None.
|
||||
"""
|
||||
gtfs_path = "./GTFS/"
|
||||
available_dir = []
|
||||
for filename in os.listdir(gtfs_path):
|
||||
logger.debug("Found directory: " + filename)
|
||||
gtfs_dir = gtfs_path + filename
|
||||
if os.path.isdir(gtfs_dir):
|
||||
start = datetime.datetime.strptime(
|
||||
filename.split("_")[0], "%Y-%m-%d"
|
||||
).date()
|
||||
end = datetime.datetime.strptime(filename.split("_")[1], "%Y-%m-%d").date()
|
||||
if today >= start and today <= end:
|
||||
available_dir.append(gtfs_dir)
|
||||
available_dir_sorted = sorted(available_dir, key=lambda e: e.split("_")[2])
|
||||
if len(available_dir_sorted) > 0:
|
||||
gtfs_dir = available_dir_sorted[-1]
|
||||
logger.debug("Use directory: " + gtfs_dir)
|
||||
return gtfs_dir
|
||||
else:
|
||||
logger.debug("No GTFS data for date: " + str(today))
|
||||
return
|
||||
|
||||
|
||||
#### Generateur de données ###
|
||||
# Recodé en python depuis le générateur original en nodejs
|
||||
# Ajout des parcours en plus pour chaque station
|
||||
|
||||
|
||||
def get_serviceid_today(gtfs_dir, today):
|
||||
services = []
|
||||
csv_calendar = list(csv.DictReader(open(gtfs_dir + "/calendar.txt")))
|
||||
weekdays = list(csv_calendar[0].keys())[1:8]
|
||||
for i in csv_calendar:
|
||||
start_date = datetime.datetime.strptime(i["start_date"], "%Y%m%d").date()
|
||||
end_date = datetime.datetime.strptime(i["end_date"], "%Y%m%d").date()
|
||||
weekday = weekdays[today.weekday()]
|
||||
if i[weekday] == "1" and today >= start_date and today <= end_date:
|
||||
services.append(i["service_id"])
|
||||
|
||||
csv_calendar_dates = list(csv.DictReader(open(gtfs_dir + "/calendar_dates.txt")))
|
||||
for i in csv_calendar_dates:
|
||||
c_date = datetime.datetime.strptime(i["date"], "%Y%m%d").date()
|
||||
if today == c_date:
|
||||
services.append(i["service_id"])
|
||||
|
||||
return services
|
||||
|
||||
|
||||
def get_trips_from_services(gtfs_dir, services_today):
|
||||
trips = {}
|
||||
csv_trips = list(csv.DictReader(open(gtfs_dir + "/trips.txt")))
|
||||
for i in csv_trips:
|
||||
if i["service_id"] in services_today:
|
||||
info = {}
|
||||
info["route_id"] = i["route_id"]
|
||||
info["shape_id"] = i["shape_id"]
|
||||
info["sens"] = i["direction_id"]
|
||||
info["last_sequence"] = "1"
|
||||
trips[i["trip_id"]] = info
|
||||
|
||||
return trips
|
||||
|
||||
|
||||
def generate_stop_map(gtfs_dir):
|
||||
all_stops = {}
|
||||
|
||||
csv_stops = list(csv.DictReader(open(gtfs_dir + "/stops.txt")))
|
||||
for i in csv_stops:
|
||||
stop_detail = {}
|
||||
stop_detail["id"] = i["stop_id"]
|
||||
stop_detail["name"] = i["stop_name"]
|
||||
stop_detail["lat"] = i["stop_lat"]
|
||||
stop_detail["lon"] = i["stop_lon"]
|
||||
stop_detail["trips"] = {}
|
||||
all_stops[i["stop_id"]] = stop_detail
|
||||
|
||||
return all_stops
|
||||
|
||||
|
||||
def associate_trips(gtfs_dir, all_stops, trips):
|
||||
|
||||
csv_stop_times = list(csv.DictReader(open(gtfs_dir + "/stop_times.txt")))
|
||||
for i in csv_stop_times:
|
||||
if i["trip_id"] in trips:
|
||||
stop_info = {}
|
||||
stop_info["arrival_time"] = i["arrival_time"]
|
||||
stop_info["departure_time"] = i["departure_time"]
|
||||
stop_info["route_id"] = trips[i["trip_id"]]["route_id"]
|
||||
stop_info["shape_id"] = trips[i["trip_id"]]["shape_id"]
|
||||
stop_info["sens"] = trips[i["trip_id"]]["sens"]
|
||||
trips[i["trip_id"]]["last_sequence"] = str(
|
||||
max(int(trips[i["trip_id"]]["last_sequence"]), int(i["stop_sequence"]))
|
||||
)
|
||||
stop_info["stop_sequence"] = i["stop_sequence"]
|
||||
all_stops[i["stop_id"]]["trips"][i["trip_id"]] = stop_info
|
||||
|
||||
return all_stops, trips
|
||||
|
||||
|
||||
def filter_no_trips(all_stops):
|
||||
newDict = {}
|
||||
for (k, v) in all_stops.items():
|
||||
if len(all_stops[k]["trips"]) != 0:
|
||||
newDict[k] = v
|
||||
return newDict
|
||||
|
||||
|
||||
def finalize_stops(all_stops, trips):
|
||||
all_stops = filter_no_trips(all_stops)
|
||||
all_stations = []
|
||||
for stop_key, stop_value in all_stops.items():
|
||||
station = Station(stop_key)
|
||||
station.lat = stop_value["lat"]
|
||||
station.lon = stop_value["lon"]
|
||||
station.name = stop_value["name"]
|
||||
terminus_dict = {}
|
||||
station.terminus = set()
|
||||
first_trip = next(iter((stop_value["trips"].items())))
|
||||
first_arrival_time = first_trip[1]["arrival_time"]
|
||||
last_departure_time = first_trip[1]["departure_time"]
|
||||
station.lines = set()
|
||||
station.parcours = set()
|
||||
for (k, v) in stop_value["trips"].items():
|
||||
if v["stop_sequence"] == trips[k]["last_sequence"]:
|
||||
terminus_dict[k] = v
|
||||
arrival_time = v["arrival_time"]
|
||||
departure_time = v["departure_time"]
|
||||
first_arrival_time = min(first_arrival_time, arrival_time)
|
||||
last_departure_time = max(last_departure_time, departure_time)
|
||||
station.lines.add(v["route_id"] + "," + v["sens"])
|
||||
if len(v["shape_id"]):
|
||||
station.parcours.add(v["shape_id"])
|
||||
for (k, v) in terminus_dict.items():
|
||||
station.terminus.add(v["route_id"] + "," + v["sens"])
|
||||
station.limits = [first_arrival_time, last_departure_time]
|
||||
all_stations.append(station)
|
||||
return all_stations
|
||||
|
||||
|
||||
### Fin du générateur
|
||||
|
||||
|
||||
def stations():
|
||||
"""
|
||||
Génère toutes les données geojson possible depuis aujourd'hui
|
||||
jusqu'à la fin des données GTFS disponible.
|
||||
Si les données des stations ont déjà été generées et qu'elles proviennt de données
|
||||
GTFS qui ont la même date de publication on ne les génère pas à nouveau.
|
||||
"""
|
||||
|
||||
os.makedirs("./GTFS/", exist_ok=True)
|
||||
os.makedirs("./data/", exist_ok=True)
|
||||
today = datetime.datetime.now().date()
|
||||
while gtfs_dir := get_gtfs_dir(today):
|
||||
logger.debug("Generate data for " + str(today))
|
||||
publication_gtfs = gtfs_dir.split("_")[-1]
|
||||
publication_gtfs_date = datetime.datetime.fromtimestamp(
|
||||
int(publication_gtfs)
|
||||
).date()
|
||||
logger.debug("Use %s (%s)", gtfs_dir, str(publication_gtfs_date))
|
||||
filename = "./data/" + today.strftime("stations_%Y_%m_%d.geojson")
|
||||
if os.path.exists(filename):
|
||||
logger.debug(filename + " already exists")
|
||||
with open(filename + ".info", "r") as f:
|
||||
present_file_info = json.load(f)
|
||||
present_file_publication = present_file_info["publication"]
|
||||
logger.debug(
|
||||
"File is generated from data published on " + present_file_publication
|
||||
)
|
||||
present_file_publication_date = datetime.datetime.fromtimestamp(
|
||||
int(present_file_publication)
|
||||
).date()
|
||||
if present_file_publication_date == publication_gtfs_date:
|
||||
logger.debug("stations file is up to date")
|
||||
today += datetime.timedelta(days=1)
|
||||
continue
|
||||
services_today = get_serviceid_today(gtfs_dir, today)
|
||||
trips = get_trips_from_services(gtfs_dir, services_today)
|
||||
all_stops = generate_stop_map(gtfs_dir)
|
||||
all_stops, trips = associate_trips(gtfs_dir, all_stops, trips)
|
||||
all_stations = finalize_stops(all_stops, trips)
|
||||
with open(filename, "w") as f:
|
||||
f.write(str(all_stations))
|
||||
with open(filename + ".info", "w") as f:
|
||||
info = {"publication": publication_gtfs}
|
||||
json.dump(info, f)
|
||||
today += datetime.timedelta(days=1)
|
||||
# import ipdb; ipdb.set_trace()
|
||||
|
||||
|
||||
def download_file(url, output_filename):
|
||||
"""
|
||||
Helper: télécharge un fichier
|
||||
"""
|
||||
logger.info("Download: %s", url)
|
||||
with requests.get(url, stream=True) as r:
|
||||
r.raise_for_status()
|
||||
with open(output_filename, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
# If you have chunk encoded response uncomment if
|
||||
# and set chunk_size parameter to None.
|
||||
# if chunk:
|
||||
f.write(chunk)
|
||||
|
||||
|
||||
def picto():
|
||||
"""
|
||||
Télécharge tous les picto disponibles.
|
||||
Si ils sont déjà présent on ne fait rien.
|
||||
"""
|
||||
|
||||
for param in [
|
||||
(URL_API_PICTO_BUS, URL_PICTO_PREFIX_BUS),
|
||||
(URL_API_PICTO_METRO, URL_PICTO_PREFIX_METRO),
|
||||
]:
|
||||
r = requests.get(param[0])
|
||||
data = r.json()
|
||||
records = data["records"]
|
||||
logger.debug(json.dumps(records, indent=4))
|
||||
for entry in records:
|
||||
filename = "./images/picto_" + entry["fields"]["idligne"] + ".png"
|
||||
if not os.path.exists(filename):
|
||||
url = param[1] + entry["fields"]["image"]["id"] + "/download/"
|
||||
download_file(url, filename)
|
||||
assert os.path.exists(filename)
|
||||
|
||||
|
||||
def download():
|
||||
"""
|
||||
Télécharge les fichier zip des données GTFS puis les extrait.
|
||||
Si le fichier est déjà téléchargé on ne fait rien.
|
||||
"""
|
||||
|
||||
os.makedirs("./downloads/", exist_ok=True)
|
||||
os.makedirs("./GTFS/", exist_ok=True)
|
||||
r = requests.get(URL_API_GTFS)
|
||||
data = r.json()
|
||||
records = data["records"]
|
||||
logger.debug(json.dumps(records, indent=4))
|
||||
for entry in records:
|
||||
filename = "./downloads/" + entry["fields"]["fichier"]["filename"]
|
||||
filename_info = filename + ".json"
|
||||
with open(filename_info, "w") as f:
|
||||
f.write(json.dumps(entry, indent=4))
|
||||
size = entry["fields"]["tailleoctets"]
|
||||
if not os.path.exists(filename) or os.path.getsize(filename) != size:
|
||||
url = entry["fields"]["url"]
|
||||
output_filename = "./downloads/" + url.split("/")[-1]
|
||||
download_file(url, output_filename)
|
||||
assert os.path.exists(filename)
|
||||
assert os.path.getsize(filename) == size
|
||||
publication_timestamp = dateutil.parser.parse(
|
||||
entry["fields"]["publication"]
|
||||
).timestamp()
|
||||
path_extract = (
|
||||
"./GTFS/"
|
||||
+ entry["fields"]["debutvalidite"]
|
||||
+ "_"
|
||||
+ entry["fields"]["finvalidite"]
|
||||
+ "_"
|
||||
+ str(int(publication_timestamp))
|
||||
)
|
||||
if not os.path.exists(path_extract):
|
||||
os.mkdir(path_extract)
|
||||
if not os.listdir(path_extract):
|
||||
with zipfile.ZipFile(filename) as zf:
|
||||
zf.extractall(path_extract)
|
||||
|
||||
|
||||
def clean():
|
||||
"""
|
||||
Supprime toutes les données produites par ce programme.
|
||||
"""
|
||||
|
||||
shutil.rmtree("./downloads")
|
||||
shutil.rmtree("./GTFS")
|
||||
for picto in glob.glob("./images/picto_*"):
|
||||
os.remove(picto)
|
||||
for stations in glob.glob("./data/stations_*"):
|
||||
os.remove(stations)
|
||||
|
||||
|
||||
def prune():
|
||||
"""
|
||||
Supprime les fichier zip, les données GTFS et les stations si elles ne sont
|
||||
plus valide (avec un delta de deux jours).
|
||||
"""
|
||||
|
||||
today = (datetime.datetime.now() - datetime.timedelta(days=2)).date()
|
||||
for zipfile in glob.glob("./downloads/*.zip"):
|
||||
zipfileinfo = zipfile + ".json"
|
||||
with open(zipfileinfo, "r") as f:
|
||||
info = json.load(f)
|
||||
fin = dateutil.parser.parse(info["fields"]["finvalidite"]).date()
|
||||
if today > fin:
|
||||
os.remove(zipfile) if os.path.exists(zipfile) else None
|
||||
os.remove(zipfileinfo) if os.path.exists(zipfileinfo) else None
|
||||
logger.debug(zipfile + " removed")
|
||||
logger.debug(zipfileinfo + " removed")
|
||||
for gtfsdir in os.listdir("./GTFS/"):
|
||||
fin = dateutil.parser.parse(gtfsdir.split("_")[1]).date()
|
||||
if today > fin:
|
||||
dir_to_remove = "./GTFS/" + gtfsdir
|
||||
shutil.rmtree(dir_to_remove)
|
||||
logger.debug(dir_to_remove + " removed")
|
||||
for stationsfile in glob.glob("./data/stations_*"):
|
||||
filename = os.path.basename(stationsfile)
|
||||
datefromfile = "-".join(filename.split(".")[:1][0].split("_")[1:])
|
||||
date = dateutil.parser.parse(datefromfile).date()
|
||||
if today > date:
|
||||
os.remove(stationsfile) if os.path.exists(stationsfile) else None
|
||||
os.remove(stationsfile + ".info") if os.path.exists(
|
||||
stationsfile + ".info"
|
||||
) else None
|
||||
logger.debug(stationsfile + "removed")
|
||||
|
||||
|
||||
def auto():
|
||||
"""
|
||||
Execute toutes les tâches nécéssaire au fonctionnement du service.
|
||||
Commande à executer chaque jour avec tâche cron.
|
||||
"""
|
||||
|
||||
picto()
|
||||
download()
|
||||
stations()
|
||||
prune()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# fmt: off
|
||||
description_str = ('ouestmonbus.com GTFS downloader \n' +
|
||||
'and data generator\n')
|
||||
# fmt: on
|
||||
usage_str = "%(prog)s action"
|
||||
epilog_str = "v 0.1"
|
||||
frm = argparse.RawTextHelpFormatter
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description_str,
|
||||
epilog=epilog_str,
|
||||
usage=usage_str,
|
||||
formatter_class=frm,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--log",
|
||||
help="log level",
|
||||
default="INFO",
|
||||
)
|
||||
cmd_parser = parser.add_subparsers(dest="command", help="command parser")
|
||||
subparser = cmd_parser.add_parser("download", help="download GTFS")
|
||||
subparser = cmd_parser.add_parser("stations", help="generate stations geojson")
|
||||
subparser = cmd_parser.add_parser("picto", help="download picto")
|
||||
subparser = cmd_parser.add_parser("clean", help="delete all")
|
||||
subparser = cmd_parser.add_parser("prune", help="delete expired data")
|
||||
subparser = cmd_parser.add_parser(
|
||||
"auto", help="execute all needed task to use with cron"
|
||||
)
|
||||
subparser.add_argument(
|
||||
"--days",
|
||||
type=int,
|
||||
default=1,
|
||||
help="nb days to generate",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
coloredlogs.install(level=args.log)
|
||||
logger = logging.getLogger(__name__)
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
locals()[args.command]()
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 395 B |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 797 B |
|
After Width: | Height: | Size: 1015 B |
|
After Width: | Height: | Size: 1015 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,171 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='fr'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Où est mon bus ?</title>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>
|
||||
<meta name='description' content=
|
||||
'Carte interactive basée sur OpenStreetMap des stations de bus de Rennes Métropole, avec affichage des horaires et des bus en temps réel.'>
|
||||
<meta name='keywords' content='Rennes, Open Data, Horaire, Bus, Métro, Horaires, Temps Réel, OpenStreepMap, Star, Keolis'>
|
||||
<meta name='author' content='Benoît Meunier et Karin Meunier'>
|
||||
<meta name='publisher' content='Benoît Meunier'>
|
||||
<meta name='copyright' content='Copyright 2015-2023 Benoît Meunier et Karin Meunier'>
|
||||
<link rel='apple-touch-icon' sizes='57x57' href='./apple-touch-icon-57x57.png'>
|
||||
<link rel='apple-touch-icon' sizes='60x60' href='./apple-touch-icon-60x60.png'>
|
||||
<link rel='apple-touch-icon' sizes='72x72' href='./apple-touch-icon-72x72.png'>
|
||||
<link rel='apple-touch-icon' sizes='76x76' href='./apple-touch-icon-76x76.png'>
|
||||
<link rel='apple-touch-icon' sizes='114x114' href='./apple-touch-icon-114x114.png'>
|
||||
<link rel='apple-touch-icon' sizes='120x120' href='./apple-touch-icon-120x120.png'>
|
||||
<link rel='apple-touch-icon' sizes='144x144' href='./apple-touch-icon-144x144.png'>
|
||||
<link rel='apple-touch-icon' sizes='152x152' href='./apple-touch-icon-152x152.png'>
|
||||
<link rel='apple-touch-icon' sizes='180x180' href='./apple-touch-icon-180x180.png'>
|
||||
<link rel='icon' type='image/png' href='./favicon-32x32.png' sizes='32x32'>
|
||||
<link rel='icon' type='image/png' href='./android-chrome-192x192.png' sizes='192x192'>
|
||||
<link rel='icon' type='image/png' href='./favicon-96x96.png' sizes='96x96'>
|
||||
<link rel='icon' type='image/png' href='./favicon-16x16.png' sizes='16x16'>
|
||||
<meta name='msapplication-TileColor' content='#da532c'>
|
||||
<meta name='msapplication-TileImage' content='./mstile-144x144.png'>
|
||||
<meta name='theme-color' content='#ffffff'>
|
||||
<link id='appcss' rel='stylesheet' href='./ouestmonbus.css'>
|
||||
<link rel='stylesheet' href='./css/metro.min.css'>
|
||||
<link rel='stylesheet' href='./css/metro-schemes.min.css'>
|
||||
<link rel='stylesheet' href='./css/metro-rtl.min.css'>
|
||||
<link rel='stylesheet' href='./css/metro-responsive.min.css'>
|
||||
<link rel='stylesheet' href='./css/metro-icons.min.css'>
|
||||
<link rel='stylesheet' href='./css/MarkerCluster.Default.css'>
|
||||
<link rel='stylesheet' href='./css/MarkerCluster.css'>
|
||||
<link rel='stylesheet' href='./css/leaflet.photon.css'>
|
||||
<link rel='stylesheet' href='./css/leaflet.css'>
|
||||
</head>
|
||||
<body>
|
||||
<div class='app-bar fixed-top darcula' data-role='appbar'>
|
||||
<ul class='app-bar-menu'>
|
||||
<li>
|
||||
<a href='javascript:void(0)' id='ouestmonbus_btn' class='bg-hover-green bg-emerald fg-white' data-hint-color=
|
||||
"fg-white" data-hint-background="bg-green" data-role="hint" data-hint="Nouveautés|de l'application"
|
||||
data-hint-mode="2"><img height="72" width="72" style="height: 3.125rem; width:3.125rem; display: inline-block;" src='./android-chrome-72x72.png' alt=
|
||||
'logo'></a>
|
||||
</li>
|
||||
<li class="bar_button">
|
||||
<a data-hint="Géolocalisation|positionnement automatique" data-hint-mode="2" data-hint-color="fg-white"
|
||||
data-hint-background="bg-cobalt" data-role="hint" class="bg-cobalt bg-hover-cyan" href='javascript:void(0)' id=
|
||||
'localise_btn'><span class='mif-location'></span></a>
|
||||
</li>
|
||||
<li class="bar_button">
|
||||
<a data-hint="Rechercher|un lieu sur la carte" data-hint-mode="2" data-hint-color="fg-white"
|
||||
data-hint-background="bg-orange" data-role="hint" class="bg-orange bg-hover-amber" href='javascript:void(0)'
|
||||
id='address_btn'><span class='mif-search'></span></a>
|
||||
</li>
|
||||
<li class="bar_button">
|
||||
<a data-hint="Infos trafic|chargement en cours" data-hint-mode="2" data-hint-color="fg-white"
|
||||
data-hint-background="bg-red" data-role="hint" class="bg-red bg-hover-lightRed" href='javascript:void(0)' id=
|
||||
'perturbations_btn'><span class='mif-info'></span></a>
|
||||
</li>
|
||||
<li class="bar_button">
|
||||
<a data-hint="Options|et paramétrage" data-hint-mode="2" data-hint-color="fg-white" data-hint-background=
|
||||
"bg-steel" data-role="hint" class="bg-steel bg-hover-lime" href='javascript:void(0)' id=
|
||||
'config_btn'><span class='mif-cogs'></span></a>
|
||||
</li>
|
||||
<li class="bar_button">
|
||||
<a data-hint="Aide|et informations" data-hint-mode="2" data-hint-color="fg-white" data-hint-background=
|
||||
"bg-yellow" data-role="hint" class="bg-yellow bg-hover-lime" href='javascript:void(0)' id=
|
||||
'about_btn'><span class='mif-question'></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id='map' class='map-container'></div>
|
||||
<div id='progressbar'></div>
|
||||
<div class='app-container'>
|
||||
<div data-role='dialog' data-color='fg-white' data-background='bg-gray' data-close-button='true' id='about_dlg'
|
||||
class='padding10 dialogontop'>
|
||||
<div class='panel'>
|
||||
<div class='heading'>
|
||||
<span class='title'>A quoi ça sert ?</span>
|
||||
</div>
|
||||
<div style='padding: 0.5rem 0.5rem 0.5rem 0.5rem;' class='content' id='text_usage'></div>
|
||||
</div>
|
||||
<div class='marginup10 panel'>
|
||||
<div class='heading'>
|
||||
<span class='title'>Qui développe ce service ?</span>
|
||||
</div>
|
||||
<div style='padding: 0.5rem 0.5rem 0.5rem 0.5rem;' class='content' id='text_who_develop'></div>
|
||||
</div>
|
||||
<div class='marginup10 align-right'><span id='version'></span></div>
|
||||
</div>
|
||||
<div data-role='dialog' id='ouestmonbus_news_dlg' data-width="23rem" data-background='bg-gray' data-color=
|
||||
'fg-white' class='padding10 dialogontop' data-close-button='yes'>
|
||||
<div class='panel'>
|
||||
<div class='heading'>
|
||||
<span class='title'>Nouveautés</span>
|
||||
</div>
|
||||
<div style='padding: 0.5rem 0.5rem 0.5rem 0.5rem;' class='content' id='app_news'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-role='dialog' data-windows-style='true' id='localisation_failed_dlg' data-background='bg-gray'
|
||||
data-color='fg-white' class='padding10 dialogontop' data-close-button='yes'>
|
||||
<div class='padding10'>
|
||||
<b>Impossible de vous localiser</b><br>
|
||||
<br>
|
||||
Votre appareil ou votre navigateur n'est pas configuré pour vous permettre d'être localisé.<br>
|
||||
Utilisez la saisie d'un lieu au clavier.
|
||||
</div><button id='localisation_failed_dlg_close' class='button place-right'>OK</button>
|
||||
</div>
|
||||
<div data-role='dialog' data-windows-style='true' id='localisation_nothere_dlg' data-background='bg-gray'
|
||||
data-color='fg-white' class='padding10 dialogontop' data-close-button='yes'>
|
||||
<div class='padding10'>
|
||||
<b>Impossible de vous localiser</b><br>
|
||||
<br>
|
||||
Votre appareil ou votre navigateur indique que vous n'êtes pas dans Rennes Métropole.<br>
|
||||
Utilisez la saisie d'un lieu au clavier.
|
||||
</div><button id='localisation_nothere_dlg_close' class='button place-right'>OK</button>
|
||||
</div>
|
||||
<div data-role='dialog' data-windows-style='true' id='api_time_failure_dlg' data-background='bg-red' data-color=
|
||||
'fg-white' class='padding10 dialogontop' data-close-button='yes'>
|
||||
<b>Problème technique: l'heure remontée par le service OpenData Keolis indique un décalage de plus de 30
|
||||
minutes.<br>
|
||||
Les données ne sont plus en temps réel.</b>
|
||||
</div>
|
||||
<div data-role='dialog' id='trafic_dlg' data-width="23rem" data-color='fg-black' data-background='bg-gray'
|
||||
data-close-button='true' class='padding10 dialogontop'>
|
||||
<div id='trafic_dlg_content' class='bg-white' style='overflow-y:scroll;'></div>
|
||||
</div>
|
||||
<div data-role='dialog' id='config_dlg' data-width="23rem" data-color='fg-black' data-background='bg-gray' class=
|
||||
'padding10 dialogontop'>
|
||||
<div class='padding10 bg-white'>
|
||||
<div class="panel">
|
||||
<div class='heading'>
|
||||
<span class='title'>Planifier un trajet</span>
|
||||
</div>
|
||||
<div class="bg-white" style="line-height: 1.5em;">
|
||||
<br>
|
||||
<span>Afficher toutes les stations</span> <label class="switch place-right"><input id=
|
||||
"all_stations_checkbox" type="checkbox"> <span class="check place-right"></span></label><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='marginup10'>
|
||||
<button id='config_valid_btn' class="button place-right">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src='./js/loglevel.min.js'></script>
|
||||
<script src='./js/jquery.min.js'></script>
|
||||
<script src='./js/metro.min.js'></script>
|
||||
<script src='./js/leaflet.min.js'></script>
|
||||
<script src='./js/leaflet.geometryutil.js'></script>
|
||||
<script src='./js/leaflet.markercluster.min.js'></script>
|
||||
<script src='./js/Leaflet.MovingMarker.js'></script>
|
||||
<script src='./js/leaflet.photon.js'></script>
|
||||
<script src='./js/moment.min.js'></script>
|
||||
<script src='./js/underscore.min.js'></script>
|
||||
<script src='./js/mobile-detect.min.js'></script>
|
||||
<script src='./js/progressbar.min.js'></script>
|
||||
<script src='./js/marked.min.js'></script>
|
||||
<script id='appscript' src='./ouestmonbus.js?%VERSION%'></script>
|
||||
<script>
|
||||
|
||||
var app = new OuestmonbusApp();
|
||||
app.init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Download dependencies"
|
||||
mkdir -p js css fonts
|
||||
|
||||
wget "https://code.jquery.com/jquery-3.6.0.min.js" -O "js/jquery.min.js"
|
||||
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/js/metro.min.js" -O "js/metro.min.js"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro.min.css" -O "css/metro.min.css"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro-schemes.min.css" -O "css/metro-schemes.min.css"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro-rtl.min.css" -O "css/metro-rtl.min.css"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro-rtl.min.css" -O "css/metro-rtl.min.css"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro-responsive.min.css" -O "css/metro-responsive.min.css"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/css/metro-icons.min.css" -O "css/metro-icons.min.css"
|
||||
wget "https://github.com/olton/Metro-UI-CSS-3/raw/master/build/fonts/metro.eot" -O "fonts/metro.eot"
|
||||
wget "https://github.com/olton/Metro-UI-CSS-3/raw/master/build/fonts/metro.svg" -O "fonts/metro.svg"
|
||||
wget "https://github.com/olton/Metro-UI-CSS-3/raw/master/build/fonts/metro.woff" -O "fonts/metro.woff"
|
||||
wget "https://github.com/olton/Metro-UI-CSS-3/raw/master/build/fonts/metro.ttf" -O "fonts/metro.ttf"
|
||||
wget "https://raw.githubusercontent.com/olton/Metro-UI-CSS-3/master/build/fonts/selection.json" -O "fonts/selection.json"
|
||||
|
||||
sed -i 's/https:\/\/themes.googleusercontent.com\/static//g' css/metro.min.css
|
||||
|
||||
wget "http://cdn.leafletjs.com/leaflet/v1.7.1/leaflet.zip" -O "/tmp/leaflet.zip"
|
||||
rm -rf /tmp/leaflet
|
||||
mkdir -p /tmp/leaflet
|
||||
unzip /tmp/leaflet.zip -d /tmp/leaflet
|
||||
cp /tmp/leaflet/leaflet.js js/leaflet.js
|
||||
cp /tmp/leaflet/leaflet.js.map js/leaflet.js.map
|
||||
cp /tmp/leaflet/leaflet.css css/leaflet.css
|
||||
cp -r /tmp/leaflet/images css/
|
||||
|
||||
wget "https://github.com/makinacorpus/Leaflet.GeometryUtil/archive/refs/tags/v0.9.1.zip" -O "/tmp/Leaflet.GeometryUtil.zip"
|
||||
rm -rf /tmp/Leaflet.GeometryUtil
|
||||
mkdir -p /tmp/Leaflet.GeometryUtil
|
||||
unzip /tmp/Leaflet.GeometryUtil.zip -d /tmp/Leaflet.GeometryUtil
|
||||
cp /tmp/Leaflet.GeometryUtil/Leaflet.GeometryUtil-0.9.1/src/leaflet.geometryutil.js "js/leaflet.geometryutil.js"
|
||||
rm -rf /tmp/Leaflet.GeometryUtil
|
||||
|
||||
wget "https://github.com/Leaflet/Leaflet.markercluster/archive/refs/tags/v1.4.1.zip" -O "/tmp/Leaflet.markercluster.zip"
|
||||
rm -rf /tmp/Leaflet.markercluster
|
||||
mkdir -p /tmp/Leaflet.markercluster
|
||||
unzip /tmp/Leaflet.markercluster.zip -d /tmp/Leaflet.markercluster/
|
||||
cp /tmp/Leaflet.markercluster/Leaflet.markercluster-1.4.1/dist/leaflet.markercluster.js "js/leaflet.markercluster.js"
|
||||
cp /tmp/Leaflet.markercluster/Leaflet.markercluster-1.4.1/dist/leaflet.markercluster.js.map "js/leaflet.markercluster.js.map"
|
||||
cp /tmp/Leaflet.markercluster/Leaflet.markercluster-1.4.1/dist/MarkerCluster.css "css/MarkerCluster.css"
|
||||
cp /tmp/Leaflet.markercluster/Leaflet.markercluster-1.4.1/dist/MarkerCluster.Default.css "css/MarkerCluster.Default.css"
|
||||
|
||||
wget "https://raw.githubusercontent.com/ewoken/Leaflet.MovingMarker/master/MovingMarker.js" -O "js/Leaflet.MovingMarker.js"
|
||||
|
||||
wget "https://raw.githubusercontent.com/komoot/leaflet.photon/master/leaflet.photon.js" -O "js/leaflet.photon.js"
|
||||
wget "https://raw.githubusercontent.com/komoot/leaflet.photon/master/leaflet.photon.css" -O "css/leaflet.photon.css"
|
||||
|
||||
wget "https://raw.githubusercontent.com/moment/moment/master/min/moment.min.js" -O "js/moment.min.js"
|
||||
wget "https://raw.githubusercontent.com/moment/moment/master/min/moment.min.js.map" -O "js/moment.min.js.map"
|
||||
|
||||
wget "https://raw.githubusercontent.com/jashkenas/underscore/master/underscore-min.js" -O "js/underscore.min.js"
|
||||
|
||||
wget "https://raw.githubusercontent.com/hgoebl/mobile-detect.js/master/mobile-detect.min.js" -O "js/mobile-detect.min.js"
|
||||
|
||||
wget "https://raw.githubusercontent.com/kimmobrunfeldt/progressbar.js/master/dist/progressbar.min.js" -O "js/progressbar.min.js"
|
||||
wget "https://raw.githubusercontent.com/kimmobrunfeldt/progressbar.js/master/dist/progressbar.min.js.map" -O "js/progressbar.min.js.map"
|
||||
|
||||
wget "https://data.explore.star.fr/api/datasets/1.0/img-illustrations-modes-dm/attachments/picto_modes_zip" -O /tmp/picto_modes.zip
|
||||
|
||||
unzip -o /tmp/picto_modes.zip -d /tmp/picto/
|
||||
mv /tmp/picto/*/Bus*.png images/
|
||||
mv /tmp/picto/*/Metro*.png images/
|
||||
|
||||
wget "https://raw.githubusercontent.com/pimterry/loglevel/master/dist/loglevel.min.js" -O "js/loglevel.min.js"
|
||||
|
||||
wget "https://cdn.jsdelivr.net/npm/marked/marked.min.js" -O "js/marked.min.js"
|
||||
@@ -0,0 +1,304 @@
|
||||
L.interpolatePosition = function(p1, p2, duration, t) {
|
||||
var k = t/duration;
|
||||
k = (k > 0) ? k : 0;
|
||||
k = (k > 1) ? 1 : k;
|
||||
return L.latLng(p1.lat + k * (p2.lat - p1.lat),
|
||||
p1.lng + k * (p2.lng - p1.lng));
|
||||
};
|
||||
|
||||
L.Marker.MovingMarker = L.Marker.extend({
|
||||
|
||||
//state constants
|
||||
statics: {
|
||||
notStartedState: 0,
|
||||
endedState: 1,
|
||||
pausedState: 2,
|
||||
runState: 3
|
||||
},
|
||||
|
||||
options: {
|
||||
autostart: false,
|
||||
loop: false,
|
||||
},
|
||||
|
||||
initialize: function (latlngs, durations, options) {
|
||||
L.Marker.prototype.initialize.call(this, latlngs[0], options);
|
||||
|
||||
this._latlngs = latlngs.map(function(e, index) {
|
||||
return L.latLng(e);
|
||||
});
|
||||
|
||||
if (durations instanceof Array) {
|
||||
this._durations = durations;
|
||||
} else {
|
||||
this._durations = this._createDurations(this._latlngs, durations);
|
||||
}
|
||||
|
||||
this._currentDuration = 0;
|
||||
this._currentIndex = 0;
|
||||
|
||||
this._state = L.Marker.MovingMarker.notStartedState;
|
||||
this._startTime = 0;
|
||||
this._startTimeStamp = 0; // timestamp given by requestAnimFrame
|
||||
this._pauseStartTime = 0;
|
||||
this._animId = 0;
|
||||
this._animRequested = false;
|
||||
this._currentLine = [];
|
||||
this._stations = {};
|
||||
},
|
||||
|
||||
isRunning: function() {
|
||||
return this._state === L.Marker.MovingMarker.runState;
|
||||
},
|
||||
|
||||
isEnded: function() {
|
||||
return this._state === L.Marker.MovingMarker.endedState;
|
||||
},
|
||||
|
||||
isStarted: function() {
|
||||
return this._state !== L.Marker.MovingMarker.notStartedState;
|
||||
},
|
||||
|
||||
isPaused: function() {
|
||||
return this._state === L.Marker.MovingMarker.pausedState;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
if (this.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isPaused()) {
|
||||
this.resume();
|
||||
} else {
|
||||
this._loadLine(0);
|
||||
this._startAnimation();
|
||||
this.fire('start');
|
||||
}
|
||||
},
|
||||
|
||||
resume: function() {
|
||||
if (! this.isPaused()) {
|
||||
return;
|
||||
}
|
||||
// update the current line
|
||||
this._currentLine[0] = this.getLatLng();
|
||||
this._currentDuration -= (this._pauseStartTime - this._startTime);
|
||||
this._startAnimation();
|
||||
},
|
||||
|
||||
pause: function() {
|
||||
if (! this.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pauseStartTime = Date.now();
|
||||
this._state = L.Marker.MovingMarker.pausedState;
|
||||
this._stopAnimation();
|
||||
this._updatePosition();
|
||||
},
|
||||
|
||||
stop: function(elapsedTime) {
|
||||
if (this.isEnded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._stopAnimation();
|
||||
|
||||
if (typeof(elapsedTime) === 'undefined') {
|
||||
// user call
|
||||
elapsedTime = 0;
|
||||
this._updatePosition();
|
||||
}
|
||||
|
||||
this._state = L.Marker.MovingMarker.endedState;
|
||||
this.fire('end', {elapsedTime: elapsedTime});
|
||||
},
|
||||
|
||||
addLatLng: function(latlng, duration) {
|
||||
this._latlngs.push(L.latLng(latlng));
|
||||
this._durations.push(duration);
|
||||
},
|
||||
|
||||
moveTo: function(latlng, duration) {
|
||||
this._stopAnimation();
|
||||
this._latlngs = [this.getLatLng(), L.latLng(latlng)];
|
||||
this._durations = [duration];
|
||||
this._state = L.Marker.MovingMarker.notStartedState;
|
||||
this.start();
|
||||
this.options.loop = false;
|
||||
},
|
||||
|
||||
addStation: function(pointIndex, duration) {
|
||||
if (pointIndex > this._latlngs.length - 2 || pointIndex < 1) {
|
||||
return;
|
||||
}
|
||||
this._stations[pointIndex] = duration;
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
L.Marker.prototype.onAdd.call(this, map);
|
||||
|
||||
if (this.options.autostart && (! this.isStarted())) {
|
||||
this.start();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isRunning()) {
|
||||
this._resumeAnimation();
|
||||
}
|
||||
},
|
||||
|
||||
onRemove: function(map) {
|
||||
L.Marker.prototype.onRemove.call(this, map);
|
||||
this._stopAnimation();
|
||||
},
|
||||
|
||||
_createDurations: function (latlngs, duration) {
|
||||
var lastIndex = latlngs.length - 1;
|
||||
var distances = [];
|
||||
var totalDistance = 0;
|
||||
var distance = 0;
|
||||
|
||||
// compute array of distances between points
|
||||
for (var i = 0; i < lastIndex; i++) {
|
||||
distance = latlngs[i + 1].distanceTo(latlngs[i]);
|
||||
distances.push(distance);
|
||||
totalDistance += distance;
|
||||
}
|
||||
|
||||
var ratioDuration = duration / totalDistance;
|
||||
|
||||
var durations = [];
|
||||
for (i = 0; i < distances.length; i++) {
|
||||
durations.push(distances[i] * ratioDuration);
|
||||
}
|
||||
|
||||
return durations;
|
||||
},
|
||||
|
||||
_startAnimation: function() {
|
||||
this._state = L.Marker.MovingMarker.runState;
|
||||
this._animId = L.Util.requestAnimFrame(function(timestamp) {
|
||||
this._startTime = Date.now();
|
||||
this._startTimeStamp = timestamp;
|
||||
this._animate(timestamp);
|
||||
}, this, true);
|
||||
this._animRequested = true;
|
||||
},
|
||||
|
||||
_resumeAnimation: function() {
|
||||
if (! this._animRequested) {
|
||||
this._animRequested = true;
|
||||
this._animId = L.Util.requestAnimFrame(function(timestamp) {
|
||||
this._animate(timestamp);
|
||||
}, this, true);
|
||||
}
|
||||
},
|
||||
|
||||
_stopAnimation: function() {
|
||||
if (this._animRequested) {
|
||||
L.Util.cancelAnimFrame(this._animId);
|
||||
this._animRequested = false;
|
||||
}
|
||||
},
|
||||
|
||||
_updatePosition: function() {
|
||||
var elapsedTime = Date.now() - this._startTime;
|
||||
this._animate(this._startTimeStamp + elapsedTime, true);
|
||||
},
|
||||
|
||||
_loadLine: function(index) {
|
||||
this._currentIndex = index;
|
||||
this._currentDuration = this._durations[index];
|
||||
this._currentLine = this._latlngs.slice(index, index + 2);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the line where the marker is
|
||||
* @param {Number} timestamp
|
||||
* @return {Number} elapsed time on the current line or null if
|
||||
* we reached the end or marker is at a station
|
||||
*/
|
||||
_updateLine: function(timestamp) {
|
||||
// time elapsed since the last latlng
|
||||
var elapsedTime = timestamp - this._startTimeStamp;
|
||||
|
||||
// not enough time to update the line
|
||||
if (elapsedTime <= this._currentDuration) {
|
||||
return elapsedTime;
|
||||
}
|
||||
|
||||
var lineIndex = this._currentIndex;
|
||||
var lineDuration = this._currentDuration;
|
||||
var stationDuration;
|
||||
|
||||
while (elapsedTime > lineDuration) {
|
||||
// substract time of the current line
|
||||
elapsedTime -= lineDuration;
|
||||
stationDuration = this._stations[lineIndex + 1];
|
||||
|
||||
// test if there is a station at the end of the line
|
||||
if (stationDuration !== undefined) {
|
||||
if (elapsedTime < stationDuration) {
|
||||
this.setLatLng(this._latlngs[lineIndex + 1]);
|
||||
return null;
|
||||
}
|
||||
elapsedTime -= stationDuration;
|
||||
}
|
||||
|
||||
lineIndex++;
|
||||
|
||||
// test if we have reached the end of the polyline
|
||||
if (lineIndex >= this._latlngs.length - 1) {
|
||||
|
||||
if (this.options.loop) {
|
||||
lineIndex = 0;
|
||||
this.fire('loop', {elapsedTime: elapsedTime});
|
||||
} else {
|
||||
// place the marker at the end, else it would be at
|
||||
// the last position
|
||||
this.setLatLng(this._latlngs[this._latlngs.length - 1]);
|
||||
this.stop(elapsedTime);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
lineDuration = this._durations[lineIndex];
|
||||
}
|
||||
|
||||
this._loadLine(lineIndex);
|
||||
this._startTimeStamp = timestamp - elapsedTime;
|
||||
this._startTime = Date.now() - elapsedTime;
|
||||
return elapsedTime;
|
||||
},
|
||||
|
||||
_animate: function(timestamp, noRequestAnim) {
|
||||
this._animRequested = false;
|
||||
|
||||
// find the next line and compute the new elapsedTime
|
||||
var elapsedTime = this._updateLine(timestamp);
|
||||
|
||||
if (this.isEnded()) {
|
||||
// no need to animate
|
||||
return;
|
||||
}
|
||||
|
||||
if (elapsedTime != null) {
|
||||
// compute the position
|
||||
var p = L.interpolatePosition(this._currentLine[0],
|
||||
this._currentLine[1],
|
||||
this._currentDuration,
|
||||
elapsedTime);
|
||||
this.setLatLng(p);
|
||||
}
|
||||
|
||||
if (! noRequestAnim) {
|
||||
this._animId = L.Util.requestAnimFrame(this._animate, this, false);
|
||||
this._animRequested = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.Marker.movingMarker = function (latlngs, duration, options) {
|
||||
return new L.Marker.MovingMarker(latlngs, duration, options);
|
||||
};
|
||||
@@ -0,0 +1,767 @@
|
||||
// Packaging/modules magic dance.
|
||||
(function (factory) {
|
||||
var L;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['leaflet'], factory);
|
||||
} else if (typeof module !== 'undefined') {
|
||||
// Node/CommonJS
|
||||
L = require('leaflet');
|
||||
module.exports = factory(L);
|
||||
} else {
|
||||
// Browser globals
|
||||
if (typeof window.L === 'undefined')
|
||||
throw 'Leaflet must be loaded first';
|
||||
factory(window.L);
|
||||
}
|
||||
}(function (L) {
|
||||
"use strict";
|
||||
|
||||
L.Polyline._flat = L.LineUtil.isFlat || L.Polyline._flat || function (latlngs) {
|
||||
// true if it's a flat array of latlngs; false if nested
|
||||
return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
|
||||
};
|
||||
|
||||
/**
|
||||
* @fileOverview Leaflet Geometry utilities for distances and linear referencing.
|
||||
* @name L.GeometryUtil
|
||||
*/
|
||||
|
||||
L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
|
||||
|
||||
/**
|
||||
Shortcut function for planar distance between two {L.LatLng} at current zoom.
|
||||
|
||||
@tutorial distance-length
|
||||
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {L.LatLng} latlngA geographical point A
|
||||
@param {L.LatLng} latlngB geographical point B
|
||||
@returns {Number} planar distance
|
||||
*/
|
||||
distance: function (map, latlngA, latlngB) {
|
||||
return map.latLngToLayerPoint(latlngA).distanceTo(map.latLngToLayerPoint(latlngB));
|
||||
},
|
||||
|
||||
/**
|
||||
Shortcut function for planar distance between a {L.LatLng} and a segment (A-B).
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {L.LatLng} latlngA geographical point A of the segment
|
||||
@param {L.LatLng} latlngB geographical point B of the segment
|
||||
@returns {Number} planar distance
|
||||
*/
|
||||
distanceSegment: function (map, latlng, latlngA, latlngB) {
|
||||
var p = map.latLngToLayerPoint(latlng),
|
||||
p1 = map.latLngToLayerPoint(latlngA),
|
||||
p2 = map.latLngToLayerPoint(latlngB);
|
||||
return L.LineUtil.pointToSegmentDistance(p, p1, p2);
|
||||
},
|
||||
|
||||
/**
|
||||
Shortcut function for converting distance to readable distance.
|
||||
@param {Number} distance distance to be converted
|
||||
@param {String} unit 'metric' or 'imperial'
|
||||
@returns {String} in yard or miles
|
||||
*/
|
||||
readableDistance: function (distance, unit) {
|
||||
var isMetric = (unit !== 'imperial'),
|
||||
distanceStr;
|
||||
if (isMetric) {
|
||||
// show metres when distance is < 1km, then show km
|
||||
if (distance > 1000) {
|
||||
distanceStr = (distance / 1000).toFixed(2) + ' km';
|
||||
}
|
||||
else {
|
||||
distanceStr = Math.ceil(distance) + ' m';
|
||||
}
|
||||
}
|
||||
else {
|
||||
distance *= 1.09361;
|
||||
if (distance > 1760) {
|
||||
distanceStr = (distance / 1760).toFixed(2) + ' miles';
|
||||
}
|
||||
else {
|
||||
distanceStr = Math.ceil(distance) + ' yd';
|
||||
}
|
||||
}
|
||||
return distanceStr;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns true if the latlng belongs to segment A-B
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {L.LatLng} latlngA geographical point A of the segment
|
||||
@param {L.LatLng} latlngB geographical point B of the segment
|
||||
@param {?Number} [tolerance=0.2] tolerance to accept if latlng belongs really
|
||||
@returns {boolean}
|
||||
*/
|
||||
belongsSegment: function(latlng, latlngA, latlngB, tolerance) {
|
||||
tolerance = tolerance === undefined ? 0.2 : tolerance;
|
||||
var hypotenuse = latlngA.distanceTo(latlngB),
|
||||
delta = latlngA.distanceTo(latlng) + latlng.distanceTo(latlngB) - hypotenuse;
|
||||
return delta/hypotenuse < tolerance;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns total length of line
|
||||
* @tutorial distance-length
|
||||
*
|
||||
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
|
||||
* @returns {Number} Total length (pixels for Point, meters for LatLng)
|
||||
*/
|
||||
length: function (coords) {
|
||||
var accumulated = L.GeometryUtil.accumulatedLengths(coords);
|
||||
return accumulated.length > 0 ? accumulated[accumulated.length-1] : 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a list of accumulated length along a line.
|
||||
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
|
||||
* @returns {Array<Number>} Array of accumulated lengths (pixels for Point, meters for LatLng)
|
||||
*/
|
||||
accumulatedLengths: function (coords) {
|
||||
if (typeof coords.getLatLngs == 'function') {
|
||||
coords = coords.getLatLngs();
|
||||
}
|
||||
if (coords.length === 0)
|
||||
return [];
|
||||
var total = 0,
|
||||
lengths = [0];
|
||||
for (var i = 0, n = coords.length - 1; i< n; i++) {
|
||||
total += coords[i].distanceTo(coords[i+1]);
|
||||
lengths.push(total);
|
||||
}
|
||||
return lengths;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the closest point of a {L.LatLng} on the segment (A-B)
|
||||
|
||||
@tutorial closest
|
||||
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {L.LatLng} latlngA geographical point A of the segment
|
||||
@param {L.LatLng} latlngB geographical point B of the segment
|
||||
@returns {L.LatLng} Closest geographical point
|
||||
*/
|
||||
closestOnSegment: function (map, latlng, latlngA, latlngB) {
|
||||
var maxzoom = map.getMaxZoom();
|
||||
if (maxzoom === Infinity)
|
||||
maxzoom = map.getZoom();
|
||||
var p = map.project(latlng, maxzoom),
|
||||
p1 = map.project(latlngA, maxzoom),
|
||||
p2 = map.project(latlngB, maxzoom),
|
||||
closest = L.LineUtil.closestPointOnSegment(p, p1, p2);
|
||||
return map.unproject(closest, maxzoom);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the closest latlng on layer.
|
||||
|
||||
Accept nested arrays
|
||||
|
||||
@tutorial closest
|
||||
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {Array<L.LatLng>|Array<Array<L.LatLng>>|L.PolyLine|L.Polygon} layer - Layer that contains the result
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {?boolean} [vertices=false] - Whether to restrict to path vertices.
|
||||
@returns {L.LatLng} Closest geographical point or null if layer param is incorrect
|
||||
*/
|
||||
closest: function (map, layer, latlng, vertices) {
|
||||
|
||||
var latlngs,
|
||||
mindist = Infinity,
|
||||
result = null,
|
||||
i, n, distance, subResult;
|
||||
|
||||
if (layer instanceof Array) {
|
||||
// if layer is Array<Array<T>>
|
||||
if (layer[0] instanceof Array && typeof layer[0][0] !== 'number') {
|
||||
// if we have nested arrays, we calc the closest for each array
|
||||
// recursive
|
||||
for (i = 0; i < layer.length; i++) {
|
||||
subResult = L.GeometryUtil.closest(map, layer[i], latlng, vertices);
|
||||
if (subResult.distance < mindist) {
|
||||
mindist = subResult.distance;
|
||||
result = subResult;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (layer[0] instanceof L.LatLng
|
||||
|| typeof layer[0][0] === 'number'
|
||||
|| typeof layer[0].lat === 'number') { // we could have a latlng as [x,y] with x & y numbers or {lat, lng}
|
||||
layer = L.polyline(layer);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have here a Polyline, that means layer is incorrect
|
||||
// see https://github.com/makinacorpus/Leaflet.GeometryUtil/issues/23
|
||||
if (! ( layer instanceof L.Polyline ) )
|
||||
return result;
|
||||
|
||||
// deep copy of latlngs
|
||||
latlngs = JSON.parse(JSON.stringify(layer.getLatLngs().slice(0)));
|
||||
|
||||
// add the last segment for L.Polygon
|
||||
if (layer instanceof L.Polygon) {
|
||||
// add the last segment for each child that is a nested array
|
||||
var addLastSegment = function(latlngs) {
|
||||
if (L.Polyline._flat(latlngs)) {
|
||||
latlngs.push(latlngs[0]);
|
||||
} else {
|
||||
for (var i = 0; i < latlngs.length; i++) {
|
||||
addLastSegment(latlngs[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
addLastSegment(latlngs);
|
||||
}
|
||||
|
||||
// we have a multi polygon / multi polyline / polygon with holes
|
||||
// use recursive to explore and return the good result
|
||||
if ( ! L.Polyline._flat(latlngs) ) {
|
||||
for (i = 0; i < latlngs.length; i++) {
|
||||
// if we are at the lower level, and if we have a L.Polygon, we add the last segment
|
||||
subResult = L.GeometryUtil.closest(map, latlngs[i], latlng, vertices);
|
||||
if (subResult.distance < mindist) {
|
||||
mindist = subResult.distance;
|
||||
result = subResult;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
} else {
|
||||
|
||||
// Lookup vertices
|
||||
if (vertices) {
|
||||
for(i = 0, n = latlngs.length; i < n; i++) {
|
||||
var ll = latlngs[i];
|
||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
||||
if (distance < mindist) {
|
||||
mindist = distance;
|
||||
result = ll;
|
||||
result.distance = distance;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Keep the closest point of all segments
|
||||
for (i = 0, n = latlngs.length; i < n-1; i++) {
|
||||
var latlngA = latlngs[i],
|
||||
latlngB = latlngs[i+1];
|
||||
distance = L.GeometryUtil.distanceSegment(map, latlng, latlngA, latlngB);
|
||||
if (distance <= mindist) {
|
||||
mindist = distance;
|
||||
result = L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
|
||||
result.distance = distance;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the closest layer to latlng among a list of layers.
|
||||
|
||||
@tutorial closest
|
||||
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {Array<L.ILayer>} layers Set of layers
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@returns {object} ``{layer, latlng, distance}`` or ``null`` if list is empty;
|
||||
*/
|
||||
closestLayer: function (map, layers, latlng) {
|
||||
var mindist = Infinity,
|
||||
result = null,
|
||||
ll = null,
|
||||
distance = Infinity;
|
||||
|
||||
for (var i = 0, n = layers.length; i < n; i++) {
|
||||
var layer = layers[i];
|
||||
if (layer instanceof L.LayerGroup) {
|
||||
// recursive
|
||||
var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
|
||||
if (subResult.distance < mindist) {
|
||||
mindist = subResult.distance;
|
||||
result = subResult;
|
||||
}
|
||||
} else {
|
||||
// Single dimension, snap on points, else snap on closest
|
||||
if (typeof layer.getLatLng == 'function') {
|
||||
ll = layer.getLatLng();
|
||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
||||
}
|
||||
else {
|
||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
||||
}
|
||||
if (distance < mindist) {
|
||||
mindist = distance;
|
||||
result = {layer: layer, latlng: ll, distance: distance};
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the n closest layers to latlng among a list of input layers.
|
||||
|
||||
@param {L.Map} map - Leaflet map to be used for this method
|
||||
@param {Array<L.ILayer>} layers - Set of layers
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {?Number} [n=layers.length] - the expected number of output layers.
|
||||
@returns {Array<object>} an array of objects ``{layer, latlng, distance}`` or ``null`` if the input is invalid (empty list or negative n)
|
||||
*/
|
||||
nClosestLayers: function (map, layers, latlng, n) {
|
||||
n = typeof n === 'number' ? n : layers.length;
|
||||
|
||||
if (n < 1 || layers.length < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var results = [];
|
||||
var distance, ll;
|
||||
|
||||
for (var i = 0, m = layers.length; i < m; i++) {
|
||||
var layer = layers[i];
|
||||
if (layer instanceof L.LayerGroup) {
|
||||
// recursive
|
||||
var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
|
||||
results.push(subResult);
|
||||
} else {
|
||||
// Single dimension, snap on points, else snap on closest
|
||||
if (typeof layer.getLatLng == 'function') {
|
||||
ll = layer.getLatLng();
|
||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
||||
}
|
||||
else {
|
||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
||||
}
|
||||
results.push({layer: layer, latlng: ll, distance: distance});
|
||||
}
|
||||
}
|
||||
|
||||
results.sort(function(a, b) {
|
||||
return a.distance - b.distance;
|
||||
});
|
||||
|
||||
if (results.length > n) {
|
||||
return results.slice(0, n);
|
||||
} else {
|
||||
return results;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all layers within a radius of the given position, in an ascending order of distance.
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {Array<ILayer>} layers - A list of layers.
|
||||
@param {L.LatLng} latlng - The position to search
|
||||
@param {?Number} [radius=Infinity] - Search radius in pixels
|
||||
@return {object[]} an array of objects including layer within the radius, closest latlng, and distance
|
||||
*/
|
||||
layersWithin: function(map, layers, latlng, radius) {
|
||||
radius = typeof radius == 'number' ? radius : Infinity;
|
||||
|
||||
var results = [];
|
||||
var ll = null;
|
||||
var distance = 0;
|
||||
|
||||
for (var i = 0, n = layers.length; i < n; i++) {
|
||||
var layer = layers[i];
|
||||
|
||||
if (typeof layer.getLatLng == 'function') {
|
||||
ll = layer.getLatLng();
|
||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
||||
}
|
||||
else {
|
||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
||||
}
|
||||
|
||||
if (ll && distance < radius) {
|
||||
results.push({layer: layer, latlng: ll, distance: distance});
|
||||
}
|
||||
}
|
||||
|
||||
var sortedResults = results.sort(function(a, b) {
|
||||
return a.distance - b.distance;
|
||||
});
|
||||
|
||||
return sortedResults;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the closest position from specified {LatLng} among specified layers,
|
||||
with a maximum tolerance in pixels, providing snapping behaviour.
|
||||
|
||||
@tutorial closest
|
||||
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {Array<ILayer>} layers - A list of layers to snap on.
|
||||
@param {L.LatLng} latlng - The position to snap
|
||||
@param {?Number} [tolerance=Infinity] - Maximum number of pixels.
|
||||
@param {?boolean} [withVertices=true] - Snap to layers vertices or segment points (not only vertex)
|
||||
@returns {object} with snapped {LatLng} and snapped {Layer} or null if tolerance exceeded.
|
||||
*/
|
||||
closestLayerSnap: function (map, layers, latlng, tolerance, withVertices) {
|
||||
tolerance = typeof tolerance == 'number' ? tolerance : Infinity;
|
||||
withVertices = typeof withVertices == 'boolean' ? withVertices : true;
|
||||
|
||||
var result = L.GeometryUtil.closestLayer(map, layers, latlng);
|
||||
if (!result || result.distance > tolerance)
|
||||
return null;
|
||||
|
||||
// If snapped layer is linear, try to snap on vertices (extremities and middle points)
|
||||
if (withVertices && typeof result.layer.getLatLngs == 'function') {
|
||||
var closest = L.GeometryUtil.closest(map, result.layer, result.latlng, true);
|
||||
if (closest.distance < tolerance) {
|
||||
result.latlng = closest;
|
||||
result.distance = L.GeometryUtil.distance(map, closest, latlng);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the Point located on a segment at the specified ratio of the segment length.
|
||||
@param {L.Point} pA coordinates of point A
|
||||
@param {L.Point} pB coordinates of point B
|
||||
@param {Number} the length ratio, expressed as a decimal between 0 and 1, inclusive.
|
||||
@returns {L.Point} the interpolated point.
|
||||
*/
|
||||
interpolateOnPointSegment: function (pA, pB, ratio) {
|
||||
return L.point(
|
||||
(pA.x * (1 - ratio)) + (ratio * pB.x),
|
||||
(pA.y * (1 - ratio)) + (ratio * pB.y)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the coordinate of the point located on a line at the specified ratio of the line length.
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {Array<L.LatLng>|L.PolyLine} latlngs Set of geographical points
|
||||
@param {Number} ratio the length ratio, expressed as a decimal between 0 and 1, inclusive
|
||||
@returns {Object} an object with latLng ({LatLng}) and predecessor ({Number}), the index of the preceding vertex in the Polyline
|
||||
(-1 if the interpolated point is the first vertex)
|
||||
*/
|
||||
interpolateOnLine: function (map, latLngs, ratio) {
|
||||
latLngs = (latLngs instanceof L.Polyline) ? latLngs.getLatLngs() : latLngs;
|
||||
var n = latLngs.length;
|
||||
if (n < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ensure the ratio is between 0 and 1;
|
||||
ratio = Math.max(Math.min(ratio, 1), 0);
|
||||
|
||||
if (ratio === 0) {
|
||||
return {
|
||||
latLng: latLngs[0] instanceof L.LatLng ? latLngs[0] : L.latLng(latLngs[0]),
|
||||
predecessor: -1
|
||||
};
|
||||
}
|
||||
if (ratio == 1) {
|
||||
return {
|
||||
latLng: latLngs[latLngs.length -1] instanceof L.LatLng ? latLngs[latLngs.length -1] : L.latLng(latLngs[latLngs.length -1]),
|
||||
predecessor: latLngs.length - 2
|
||||
};
|
||||
}
|
||||
|
||||
// project the LatLngs as Points,
|
||||
// and compute total planar length of the line at max precision
|
||||
var maxzoom = map.getMaxZoom();
|
||||
if (maxzoom === Infinity)
|
||||
maxzoom = map.getZoom();
|
||||
var pts = [];
|
||||
var lineLength = 0;
|
||||
for(var i = 0; i < n; i++) {
|
||||
pts[i] = map.project(latLngs[i], maxzoom);
|
||||
if(i > 0)
|
||||
lineLength += pts[i-1].distanceTo(pts[i]);
|
||||
}
|
||||
|
||||
var ratioDist = lineLength * ratio;
|
||||
|
||||
// follow the line segments [ab], adding lengths,
|
||||
// until we find the segment where the points should lie on
|
||||
var cumulativeDistanceToA = 0, cumulativeDistanceToB = 0;
|
||||
for (var i = 0; cumulativeDistanceToB < ratioDist; i++) {
|
||||
var pointA = pts[i], pointB = pts[i+1];
|
||||
|
||||
cumulativeDistanceToA = cumulativeDistanceToB;
|
||||
cumulativeDistanceToB += pointA.distanceTo(pointB);
|
||||
}
|
||||
|
||||
if (pointA == undefined && pointB == undefined) { // Happens when line has no length
|
||||
var pointA = pts[0], pointB = pts[1], i = 1;
|
||||
}
|
||||
|
||||
// compute the ratio relative to the segment [ab]
|
||||
var segmentRatio = ((cumulativeDistanceToB - cumulativeDistanceToA) !== 0) ? ((ratioDist - cumulativeDistanceToA) / (cumulativeDistanceToB - cumulativeDistanceToA)) : 0;
|
||||
var interpolatedPoint = L.GeometryUtil.interpolateOnPointSegment(pointA, pointB, segmentRatio);
|
||||
return {
|
||||
latLng: map.unproject(interpolatedPoint, maxzoom),
|
||||
predecessor: i-1
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
Returns a float between 0 and 1 representing the location of the
|
||||
closest point on polyline to the given latlng, as a fraction of total line length.
|
||||
(opposite of L.GeometryUtil.interpolateOnLine())
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {L.PolyLine} polyline Polyline on which the latlng will be search
|
||||
@param {L.LatLng} latlng The position to search
|
||||
@returns {Number} Float between 0 and 1
|
||||
*/
|
||||
locateOnLine: function (map, polyline, latlng) {
|
||||
var latlngs = polyline.getLatLngs();
|
||||
if (latlng.equals(latlngs[0]))
|
||||
return 0.0;
|
||||
if (latlng.equals(latlngs[latlngs.length-1]))
|
||||
return 1.0;
|
||||
|
||||
var point = L.GeometryUtil.closest(map, polyline, latlng, false),
|
||||
lengths = L.GeometryUtil.accumulatedLengths(latlngs),
|
||||
total_length = lengths[lengths.length-1],
|
||||
portion = 0,
|
||||
found = false;
|
||||
for (var i=0, n = latlngs.length-1; i < n; i++) {
|
||||
var l1 = latlngs[i],
|
||||
l2 = latlngs[i+1];
|
||||
portion = lengths[i];
|
||||
if (L.GeometryUtil.belongsSegment(point, l1, l2, 0.0001)) {
|
||||
portion += l1.distanceTo(point);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw "Could not interpolate " + latlng.toString() + " within " + polyline.toString();
|
||||
}
|
||||
return portion / total_length;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns a clone with reversed coordinates.
|
||||
@param {L.PolyLine} polyline polyline to reverse
|
||||
@returns {L.PolyLine} polyline reversed
|
||||
*/
|
||||
reverse: function (polyline) {
|
||||
return L.polyline(polyline.getLatLngs().slice(0).reverse());
|
||||
},
|
||||
|
||||
/**
|
||||
Returns a sub-part of the polyline, from start to end.
|
||||
If start is superior to end, returns extraction from inverted line.
|
||||
@param {L.Map} map Leaflet map to be used for this method
|
||||
@param {L.PolyLine} polyline Polyline on which will be extracted the sub-part
|
||||
@param {Number} start ratio, expressed as a decimal between 0 and 1, inclusive
|
||||
@param {Number} end ratio, expressed as a decimal between 0 and 1, inclusive
|
||||
@returns {Array<L.LatLng>} new polyline
|
||||
*/
|
||||
extract: function (map, polyline, start, end) {
|
||||
if (start > end) {
|
||||
return L.GeometryUtil.extract(map, L.GeometryUtil.reverse(polyline), 1.0-start, 1.0-end);
|
||||
}
|
||||
|
||||
// Bound start and end to [0-1]
|
||||
start = Math.max(Math.min(start, 1), 0);
|
||||
end = Math.max(Math.min(end, 1), 0);
|
||||
|
||||
var latlngs = polyline.getLatLngs(),
|
||||
startpoint = L.GeometryUtil.interpolateOnLine(map, polyline, start),
|
||||
endpoint = L.GeometryUtil.interpolateOnLine(map, polyline, end);
|
||||
// Return single point if start == end
|
||||
if (start == end) {
|
||||
var point = L.GeometryUtil.interpolateOnLine(map, polyline, end);
|
||||
return [point.latLng];
|
||||
}
|
||||
// Array.slice() works indexes at 0
|
||||
if (startpoint.predecessor == -1)
|
||||
startpoint.predecessor = 0;
|
||||
if (endpoint.predecessor == -1)
|
||||
endpoint.predecessor = 0;
|
||||
var result = latlngs.slice(startpoint.predecessor+1, endpoint.predecessor+1);
|
||||
result.unshift(startpoint.latLng);
|
||||
result.push(endpoint.latLng);
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns true if first polyline ends where other second starts.
|
||||
@param {L.PolyLine} polyline First polyline
|
||||
@param {L.PolyLine} other Second polyline
|
||||
@returns {bool}
|
||||
*/
|
||||
isBefore: function (polyline, other) {
|
||||
if (!other) return false;
|
||||
var lla = polyline.getLatLngs(),
|
||||
llb = other.getLatLngs();
|
||||
return (lla[lla.length-1]).equals(llb[0]);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns true if first polyline starts where second ends.
|
||||
@param {L.PolyLine} polyline First polyline
|
||||
@param {L.PolyLine} other Second polyline
|
||||
@returns {bool}
|
||||
*/
|
||||
isAfter: function (polyline, other) {
|
||||
if (!other) return false;
|
||||
var lla = polyline.getLatLngs(),
|
||||
llb = other.getLatLngs();
|
||||
return (lla[0]).equals(llb[llb.length-1]);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns true if first polyline starts where second ends or start.
|
||||
@param {L.PolyLine} polyline First polyline
|
||||
@param {L.PolyLine} other Second polyline
|
||||
@returns {bool}
|
||||
*/
|
||||
startsAtExtremity: function (polyline, other) {
|
||||
if (!other) return false;
|
||||
var lla = polyline.getLatLngs(),
|
||||
llb = other.getLatLngs(),
|
||||
start = lla[0];
|
||||
return start.equals(llb[0]) || start.equals(llb[llb.length-1]);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns horizontal angle in degres between two points.
|
||||
@param {L.Point} a Coordinates of point A
|
||||
@param {L.Point} b Coordinates of point B
|
||||
@returns {Number} horizontal angle
|
||||
*/
|
||||
computeAngle: function(a, b) {
|
||||
return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns slope (Ax+B) between two points.
|
||||
@param {L.Point} a Coordinates of point A
|
||||
@param {L.Point} b Coordinates of point B
|
||||
@returns {Object} with ``a`` and ``b`` properties.
|
||||
*/
|
||||
computeSlope: function(a, b) {
|
||||
var s = (b.y - a.y) / (b.x - a.x),
|
||||
o = a.y - (s * a.x);
|
||||
return {'a': s, 'b': o};
|
||||
},
|
||||
|
||||
/**
|
||||
Returns LatLng of rotated point around specified LatLng center.
|
||||
@param {L.LatLng} latlngPoint: point to rotate
|
||||
@param {double} angleDeg: angle to rotate in degrees
|
||||
@param {L.LatLng} latlngCenter: center of rotation
|
||||
@returns {L.LatLng} rotated point
|
||||
*/
|
||||
rotatePoint: function(map, latlngPoint, angleDeg, latlngCenter) {
|
||||
var maxzoom = map.getMaxZoom();
|
||||
if (maxzoom === Infinity)
|
||||
maxzoom = map.getZoom();
|
||||
var angleRad = angleDeg*Math.PI/180,
|
||||
pPoint = map.project(latlngPoint, maxzoom),
|
||||
pCenter = map.project(latlngCenter, maxzoom),
|
||||
x2 = Math.cos(angleRad)*(pPoint.x-pCenter.x) - Math.sin(angleRad)*(pPoint.y-pCenter.y) + pCenter.x,
|
||||
y2 = Math.sin(angleRad)*(pPoint.x-pCenter.x) + Math.cos(angleRad)*(pPoint.y-pCenter.y) + pCenter.y;
|
||||
return map.unproject(new L.Point(x2,y2), maxzoom);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the bearing in degrees clockwise from north (0 degrees)
|
||||
from the first L.LatLng to the second, at the first LatLng
|
||||
@param {L.LatLng} latlng1: origin point of the bearing
|
||||
@param {L.LatLng} latlng2: destination point of the bearing
|
||||
@returns {float} degrees clockwise from north.
|
||||
*/
|
||||
bearing: function(latlng1, latlng2) {
|
||||
var rad = Math.PI / 180,
|
||||
lat1 = latlng1.lat * rad,
|
||||
lat2 = latlng2.lat * rad,
|
||||
lon1 = latlng1.lng * rad,
|
||||
lon2 = latlng2.lng * rad,
|
||||
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
|
||||
x = Math.cos(lat1) * Math.sin(lat2) -
|
||||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
|
||||
|
||||
var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
|
||||
return bearing >= 180 ? bearing-360 : bearing;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the point that is a distance and heading away from
|
||||
the given origin point.
|
||||
@param {L.LatLng} latlng: origin point
|
||||
@param {float} heading: heading in degrees, clockwise from 0 degrees north.
|
||||
@param {float} distance: distance in meters
|
||||
@returns {L.latLng} the destination point.
|
||||
Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html
|
||||
for a great reference and examples.
|
||||
*/
|
||||
destination: function(latlng, heading, distance) {
|
||||
heading = (heading + 360) % 360;
|
||||
var rad = Math.PI / 180,
|
||||
radInv = 180 / Math.PI,
|
||||
R = 6378137, // approximation of Earth's radius
|
||||
lon1 = latlng.lng * rad,
|
||||
lat1 = latlng.lat * rad,
|
||||
rheading = heading * rad,
|
||||
sinLat1 = Math.sin(lat1),
|
||||
cosLat1 = Math.cos(lat1),
|
||||
cosDistR = Math.cos(distance / R),
|
||||
sinDistR = Math.sin(distance / R),
|
||||
lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 *
|
||||
sinDistR * Math.cos(rheading)),
|
||||
lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR *
|
||||
cosLat1, cosDistR - sinLat1 * Math.sin(lat2));
|
||||
lon2 = lon2 * radInv;
|
||||
lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2;
|
||||
return L.latLng([lat2 * radInv, lon2]);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns the the angle of the given segment and the Equator in degrees,
|
||||
clockwise from 0 degrees north.
|
||||
@param {L.Map} map: Leaflet map to be used for this method
|
||||
@param {L.LatLng} latlngA: geographical point A of the segment
|
||||
@param {L.LatLng} latlngB: geographical point B of the segment
|
||||
@returns {Float} the angle in degrees.
|
||||
*/
|
||||
angle: function(map, latlngA, latlngB) {
|
||||
var pointA = map.latLngToContainerPoint(latlngA),
|
||||
pointB = map.latLngToContainerPoint(latlngB),
|
||||
angleDeg = Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180 / Math.PI + 90;
|
||||
angleDeg += angleDeg < 0 ? 360 : 0;
|
||||
return angleDeg;
|
||||
},
|
||||
|
||||
/**
|
||||
Returns a point snaps on the segment and heading away from the given origin point a distance.
|
||||
@param {L.Map} map: Leaflet map to be used for this method
|
||||
@param {L.LatLng} latlngA: geographical point A of the segment
|
||||
@param {L.LatLng} latlngB: geographical point B of the segment
|
||||
@param {float} distance: distance in meters
|
||||
@returns {L.latLng} the destination point.
|
||||
*/
|
||||
destinationOnSegment: function(map, latlngA, latlngB, distance) {
|
||||
var angleDeg = L.GeometryUtil.angle(map, latlngA, latlngB),
|
||||
latlng = L.GeometryUtil.destination(latlngA, angleDeg, distance);
|
||||
return L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
|
||||
},
|
||||
});
|
||||
|
||||
return L.GeometryUtil;
|
||||
|
||||
}));
|
||||
@@ -0,0 +1,481 @@
|
||||
L.PhotonBase = L.Class.extend({
|
||||
|
||||
forEach: function (els, callback) {
|
||||
Array.prototype.forEach.call(els, callback);
|
||||
},
|
||||
|
||||
ajax: function (callback, thisobj) {
|
||||
if (typeof this.xhr === 'object') {
|
||||
this.xhr.abort();
|
||||
}
|
||||
this.xhr = new XMLHttpRequest();
|
||||
var self = this;
|
||||
this.xhr.open('GET', this.options.url + this.buildQueryString(this.getParams()), true);
|
||||
|
||||
this.xhr.onload = function(e) {
|
||||
self.fire('ajax:return');
|
||||
if (this.status === 200) {
|
||||
if (callback) {
|
||||
var raw = this.response;
|
||||
raw = JSON.parse(raw);
|
||||
callback.call(thisobj || this, raw);
|
||||
}
|
||||
}
|
||||
delete this.xhr;
|
||||
};
|
||||
|
||||
this.fire('ajax:send');
|
||||
this.xhr.send();
|
||||
},
|
||||
|
||||
buildQueryString: function (params) {
|
||||
var queryString = [];
|
||||
for (var key in params) {
|
||||
if (params[key]) {
|
||||
queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
|
||||
}
|
||||
}
|
||||
return queryString.join('&');
|
||||
},
|
||||
|
||||
featureToPopupContent: function (feature) {
|
||||
var container = L.DomUtil.create('div', 'leaflet-photon-popup'),
|
||||
title = L.DomUtil.create('h3', '', container);
|
||||
title.innerHTML = feature.properties.label;
|
||||
return container;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
L.PhotonBaseSearch = L.PhotonBase.extend({
|
||||
|
||||
includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),
|
||||
|
||||
options: {
|
||||
url: 'https://photon.komoot.io/api/?',
|
||||
placeholder: 'Start typing...',
|
||||
minChar: 3,
|
||||
limit: 5,
|
||||
submitDelay: 300,
|
||||
includePosition: true,
|
||||
bbox: null,
|
||||
noResultLabel: 'No result',
|
||||
feedbackEmail: 'photon@komoot.de', // Set to null to remove feedback box
|
||||
feedbackLabel: 'Feedback'
|
||||
},
|
||||
|
||||
CACHE: '',
|
||||
RESULTS: [],
|
||||
KEYS: {
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
TAB: 9,
|
||||
RETURN: 13,
|
||||
ESC: 27,
|
||||
APPLE: 91,
|
||||
SHIFT: 16,
|
||||
ALT: 17,
|
||||
CTRL: 18
|
||||
},
|
||||
|
||||
initialize: function (input, options) {
|
||||
this.input = input;
|
||||
L.setOptions(this, options);
|
||||
var CURRENT = null;
|
||||
|
||||
try {
|
||||
Object.defineProperty(this, 'CURRENT', {
|
||||
get: function () {
|
||||
return CURRENT;
|
||||
},
|
||||
set: function (index) {
|
||||
if (typeof index === 'object') {
|
||||
index = this.resultToIndex(index);
|
||||
}
|
||||
CURRENT = index;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Hello IE8
|
||||
}
|
||||
this.input.type = L.Browser.ie ? 'text' : 'search';
|
||||
this.input.placeholder = this.options.placeholder;
|
||||
this.input.autocomplete = 'off';
|
||||
this.input.autocorrect = 'off';
|
||||
L.DomEvent.disableClickPropagation(this.input);
|
||||
|
||||
L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this);
|
||||
L.DomEvent.on(this.input, 'input', this.onInput, this);
|
||||
L.DomEvent.on(this.input, 'blur', this.onBlur, this);
|
||||
L.DomEvent.on(this.input, 'focus', this.onFocus, this);
|
||||
this.createResultsContainer();
|
||||
},
|
||||
|
||||
createResultsContainer: function () {
|
||||
this.resultsContainer = this.options.resultsContainer || L.DomUtil.create('ul', 'photon-autocomplete', document.querySelector('body'));
|
||||
},
|
||||
|
||||
resizeContainer: function()
|
||||
{
|
||||
var l = this.getLeft(this.input);
|
||||
var t = this.getTop(this.input) + this.input.offsetHeight;
|
||||
this.resultsContainer.style.left = l + 'px';
|
||||
this.resultsContainer.style.top = t + 'px';
|
||||
var width = this.options.width ? this.options.width : this.input.offsetWidth - 2;
|
||||
this.resultsContainer.style.width = width + 'px';
|
||||
},
|
||||
|
||||
onKeyDown: function (e) {
|
||||
switch (e.keyCode) {
|
||||
case this.KEYS.TAB:
|
||||
if(this.CURRENT !== null)
|
||||
{
|
||||
this.setChoice();
|
||||
}
|
||||
L.DomEvent.stop(e);
|
||||
break;
|
||||
case this.KEYS.RETURN:
|
||||
L.DomEvent.stop(e);
|
||||
this.setChoice();
|
||||
break;
|
||||
case this.KEYS.ESC:
|
||||
L.DomEvent.stop(e);
|
||||
this.hide();
|
||||
this.input.blur();
|
||||
break;
|
||||
case this.KEYS.DOWN:
|
||||
if(this.RESULTS.length > 0) {
|
||||
if(this.CURRENT !== null && this.CURRENT < this.RESULTS.length - 1) { // what if one resutl?
|
||||
this.CURRENT++;
|
||||
this.highlight();
|
||||
}
|
||||
else if(this.CURRENT === null) {
|
||||
this.CURRENT = 0;
|
||||
this.highlight();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case this.KEYS.UP:
|
||||
if(this.CURRENT !== null) {
|
||||
L.DomEvent.stop(e);
|
||||
}
|
||||
if(this.RESULTS.length > 0) {
|
||||
if(this.CURRENT > 0) {
|
||||
this.CURRENT--;
|
||||
this.highlight();
|
||||
}
|
||||
else if(this.CURRENT === 0) {
|
||||
this.CURRENT = null;
|
||||
this.highlight();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onInput: function (e) {
|
||||
if (typeof this.submitDelay === 'number') {
|
||||
window.clearTimeout(this.submitDelay);
|
||||
delete this.submitDelay;
|
||||
}
|
||||
this.submitDelay = window.setTimeout(L.Util.bind(this.search, this), this.options.submitDelay);
|
||||
},
|
||||
|
||||
onBlur: function (e) {
|
||||
this.fire('blur');
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
self.hide();
|
||||
}, 100);
|
||||
},
|
||||
|
||||
onFocus: function (e) {
|
||||
this.fire('focus');
|
||||
this.input.select();
|
||||
this.search(); // In case we have a value from a previous search.
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this.RESULTS = [];
|
||||
this.CURRENT = null;
|
||||
this.CACHE = '';
|
||||
this.resultsContainer.innerHTML = '';
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.fire('hide');
|
||||
this.clear();
|
||||
this.resultsContainer.style.display = 'none';
|
||||
},
|
||||
|
||||
setChoice: function (choice) {
|
||||
choice = choice || this.RESULTS[this.CURRENT];
|
||||
if (choice) {
|
||||
this.hide();
|
||||
this.fire('selected', {choice: choice.feature});
|
||||
this.onSelected(choice.feature);
|
||||
this.input.value = '';
|
||||
}
|
||||
},
|
||||
|
||||
search: function() {
|
||||
var val = this.input.value;
|
||||
var minChar = typeof this.options.minChar === 'function' ? this.options.minChar(val) : val.length >= this.options.minChar;
|
||||
if (!val || !minChar) return this.clear();
|
||||
if(val + '' === this.CACHE + '') return;
|
||||
else this.CACHE = val;
|
||||
this._doSearch();
|
||||
},
|
||||
|
||||
_doSearch: function () {
|
||||
this.ajax(this.handleResults, this);
|
||||
},
|
||||
|
||||
_onSelected: function (feature) {
|
||||
},
|
||||
|
||||
onSelected: function (choice) {
|
||||
return (this.options.onSelected || this._onSelected).call(this, choice);
|
||||
},
|
||||
|
||||
_formatResult: function (feature, el) {
|
||||
var title = L.DomUtil.create('strong', '', el),
|
||||
detailsContainer = L.DomUtil.create('small', '', el),
|
||||
details = [],
|
||||
type = this.formatType(feature);
|
||||
if (feature.properties.name) {
|
||||
title.innerHTML = feature.properties.name;
|
||||
} else if (feature.properties.housenumber) {
|
||||
title.innerHTML = feature.properties.housenumber;
|
||||
if (feature.properties.street) {
|
||||
title.innerHTML += ' ' + feature.properties.street;
|
||||
}
|
||||
}
|
||||
if (type) details.push(type);
|
||||
if (feature.properties.city && feature.properties.city !== feature.properties.name) {
|
||||
details.push(feature.properties.city);
|
||||
}
|
||||
if (feature.properties.country) details.push(feature.properties.country);
|
||||
detailsContainer.innerHTML = details.join(', ');
|
||||
},
|
||||
|
||||
formatResult: function (feature, el) {
|
||||
return (this.options.formatResult || this._formatResult).call(this, feature, el);
|
||||
},
|
||||
|
||||
formatType: function (feature) {
|
||||
return (this.options.formatType || this._formatType).call(this, feature);
|
||||
},
|
||||
|
||||
_formatType: function (feature) {
|
||||
return feature.properties.osm_value === 'yes'
|
||||
? feature.properties.osm_key
|
||||
: feature.properties.osm_value;
|
||||
},
|
||||
|
||||
createResult: function (feature) {
|
||||
var el = L.DomUtil.create('li', '', this.resultsContainer);
|
||||
this.formatResult(feature, el);
|
||||
var result = {
|
||||
feature: feature,
|
||||
el: el
|
||||
};
|
||||
// Touch handling needed
|
||||
L.DomEvent.on(el, 'mouseover', function (e) {
|
||||
this.CURRENT = result;
|
||||
this.highlight();
|
||||
}, this);
|
||||
L.DomEvent.on(el, 'mousedown', function (e) {
|
||||
this.setChoice();
|
||||
}, this);
|
||||
return result;
|
||||
},
|
||||
|
||||
resultToIndex: function (result) {
|
||||
var out = null;
|
||||
this.forEach(this.RESULTS, function (item, index) {
|
||||
if (item === result) {
|
||||
out = index;
|
||||
return;
|
||||
}
|
||||
});
|
||||
return out;
|
||||
},
|
||||
|
||||
handleResults: function(geojson) {
|
||||
var self = this;
|
||||
this.clear();
|
||||
this.resultsContainer.style.display = 'block';
|
||||
this.resizeContainer();
|
||||
this.forEach(geojson.features, function (feature) {
|
||||
self.RESULTS.push(self.createResult(feature));
|
||||
});
|
||||
if (geojson.features.length === 0) {
|
||||
var noresult = L.DomUtil.create('li', 'photon-no-result', this.resultsContainer);
|
||||
noresult.innerHTML = this.options.noResultLabel;
|
||||
}
|
||||
if (this.options.feedbackEmail) {
|
||||
var feedback = L.DomUtil.create('a', 'photon-feedback', this.resultsContainer);
|
||||
feedback.href = 'mailto:' + this.options.feedbackEmail;
|
||||
feedback.innerHTML = this.options.feedbackLabel;
|
||||
}
|
||||
this.CURRENT = 0;
|
||||
this.highlight();
|
||||
if (this.options.resultsHandler) {
|
||||
this.options.resultsHandler(geojson);
|
||||
}
|
||||
},
|
||||
|
||||
highlight: function () {
|
||||
var self = this;
|
||||
this.forEach(this.RESULTS, function (item, index) {
|
||||
if (index === self.CURRENT) {
|
||||
L.DomUtil.addClass(item.el, 'on');
|
||||
}
|
||||
else {
|
||||
L.DomUtil.removeClass(item.el, 'on');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getLeft: function (el) {
|
||||
var tmp = el.offsetLeft;
|
||||
el = el.offsetParent;
|
||||
while(el) {
|
||||
tmp += el.offsetLeft;
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return tmp;
|
||||
},
|
||||
|
||||
getTop: function (el) {
|
||||
var tmp = el.offsetTop;
|
||||
el = el.offsetParent;
|
||||
while(el) {
|
||||
tmp += el.offsetTop;
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return tmp;
|
||||
},
|
||||
|
||||
getParams: function () {
|
||||
return {
|
||||
q: this.CACHE,
|
||||
lang: this.options.lang,
|
||||
limit: this.options.limit,
|
||||
osm_tag: this.options.osm_tag
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
L.PhotonSearch = L.PhotonBaseSearch.extend({
|
||||
|
||||
initialize: function (map, input, options) {
|
||||
this.map = map;
|
||||
L.PhotonBaseSearch.prototype.initialize.call(this, input, options);
|
||||
},
|
||||
|
||||
_onSelected: function (feature) {
|
||||
this.map.setView([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], 16);
|
||||
},
|
||||
|
||||
getParams: function () {
|
||||
var params = L.PhotonBaseSearch.prototype.getParams.call(this);
|
||||
if (this.options.includePosition) {
|
||||
params.lat = this.map.getCenter().lat;
|
||||
params.lon = this.map.getCenter().lng;
|
||||
}
|
||||
if (this.options.bbox && this.options.bbox.length === 4) {
|
||||
params.bbox = this.options.bbox.join(',');
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
L.Control.Photon = L.Control.extend({
|
||||
|
||||
includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),
|
||||
|
||||
onAdd: function (map, options) {
|
||||
this.map = map;
|
||||
this.container = L.DomUtil.create('div', 'leaflet-photon');
|
||||
|
||||
this.options = L.Util.extend(this.options, options);
|
||||
|
||||
this.input = L.DomUtil.create('input', 'photon-input', this.container);
|
||||
this.search = new L.PhotonSearch(map, this.input, this.options);
|
||||
this.search.on('blur', this.forwardEvent, this);
|
||||
this.search.on('focus', this.forwardEvent, this);
|
||||
this.search.on('hide', this.forwardEvent, this);
|
||||
this.search.on('selected', this.forwardEvent, this);
|
||||
this.search.on('ajax:send', this.forwardEvent, this);
|
||||
this.search.on('ajax:return', this.forwardEvent, this);
|
||||
return this.container;
|
||||
},
|
||||
|
||||
// TODO onRemove
|
||||
|
||||
forwardEvent: function (e) {
|
||||
this.fire(e.type, e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
L.control.photon = function(options) {
|
||||
return new L.Control.Photon(options);
|
||||
}
|
||||
|
||||
L.Map.addInitHook(function () {
|
||||
if (this.options.photonControl) {
|
||||
this.photonControl = new L.Control.Photon(this.options.photonControlOptions || {});
|
||||
this.addControl(this.photonControl);
|
||||
}
|
||||
});
|
||||
|
||||
L.PhotonReverse = L.PhotonBase.extend({
|
||||
|
||||
includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),
|
||||
|
||||
options: {
|
||||
url: 'https://photon.komoot.de/reverse/?',
|
||||
limit: 1,
|
||||
handleResults: null
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
L.setOptions(this, options);
|
||||
},
|
||||
|
||||
doReverse: function (latlng) {
|
||||
latlng = L.latLng(latlng);
|
||||
this.fire('reverse', {latlng: latlng});
|
||||
this.latlng = latlng;
|
||||
this.ajax(this.handleResults, this);
|
||||
},
|
||||
|
||||
_handleResults: function (data) {
|
||||
/*eslint-disable no-console */
|
||||
console.log(data);
|
||||
/*eslint-enable no-alert */
|
||||
},
|
||||
|
||||
handleResults: function (data) {
|
||||
return (this.options.handleResults || this._handleResults).call(this, data);
|
||||
},
|
||||
|
||||
getParams: function () {
|
||||
return {
|
||||
lang: this.options.lang,
|
||||
limit: this.options.limit,
|
||||
lat: this.latlng.lat,
|
||||
lon: this.latlng.lng,
|
||||
osm_tag: this.options.osm_tag
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
/*! loglevel - v1.7.1 - https://github.com/pimterry/loglevel - (c) 2020 Tim Perry - licensed MIT */
|
||||
!function(a,b){"use strict";"function"==typeof define&&define.amd?define(b):"object"==typeof module&&module.exports?module.exports=b():a.log=b()}(this,function(){"use strict";function a(a,b){var c=a[b];if("function"==typeof c.bind)return c.bind(a);try{return Function.prototype.bind.call(c,a)}catch(b){return function(){return Function.prototype.apply.apply(c,[a,arguments])}}}function b(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function c(c){return"debug"===c&&(c="log"),typeof console!==i&&("trace"===c&&j?b:void 0!==console[c]?a(console,c):void 0!==console.log?a(console,"log"):h)}function d(a,b){for(var c=0;c<k.length;c++){var d=k[c];this[d]=c<a?h:this.methodFactory(d,a,b)}this.log=this.debug}function e(a,b,c){return function(){typeof console!==i&&(d.call(this,b,c),this[a].apply(this,arguments))}}function f(a,b,d){return c(a)||e.apply(this,arguments)}function g(a,b,c){function e(a){var b=(k[a]||"silent").toUpperCase();if(typeof window!==i&&l){try{return void(window.localStorage[l]=b)}catch(a){}try{window.document.cookie=encodeURIComponent(l)+"="+b+";"}catch(a){}}}function g(){var a;if(typeof window!==i&&l){try{a=window.localStorage[l]}catch(a){}if(typeof a===i)try{var b=window.document.cookie,c=b.indexOf(encodeURIComponent(l)+"=");-1!==c&&(a=/^([^;]+)/.exec(b.slice(c))[1])}catch(a){}return void 0===j.levels[a]&&(a=void 0),a}}var h,j=this,l="loglevel";"string"==typeof a?l+=":"+a:"symbol"==typeof a&&(l=void 0),j.name=a,j.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},j.methodFactory=c||f,j.getLevel=function(){return h},j.setLevel=function(b,c){if("string"==typeof b&&void 0!==j.levels[b.toUpperCase()]&&(b=j.levels[b.toUpperCase()]),!("number"==typeof b&&b>=0&&b<=j.levels.SILENT))throw"log.setLevel() called with invalid level: "+b;if(h=b,!1!==c&&e(b),d.call(j,b,a),typeof console===i&&b<j.levels.SILENT)return"No console available for logging"},j.setDefaultLevel=function(a){g()||j.setLevel(a,!1)},j.enableAll=function(a){j.setLevel(j.levels.TRACE,a)},j.disableAll=function(a){j.setLevel(j.levels.SILENT,a)};var m=g();null==m&&(m=null==b?"WARN":b),j.setLevel(m,!1)}var h=function(){},i="undefined",j=typeof window!==i&&typeof window.navigator!==i&&/Trident\/|MSIE /.test(window.navigator.userAgent),k=["trace","debug","info","warn","error"],l=new g,m={};l.getLogger=function(a){if("symbol"!=typeof a&&"string"!=typeof a||""===a)throw new TypeError("You must supply a name when creating a logger.");var b=m[a];return b||(b=m[a]=new g(a,l.getLevel(),l.methodFactory)),b};var n=typeof window!==i?window.log:void 0;return l.noConflict=function(){return typeof window!==i&&window.log===l&&(window.log=n),l},l.getLoggers=function(){return m},l.default=l,l});
|
||||